diff --git a/build.gradle.kts b/build.gradle.kts index 01f1bdf..1efed45 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,7 +30,7 @@ repositories { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation(kotlin("reflect")) - implementation("com.github.ProjectMapK:Shared:0.2") + implementation("com.github.ProjectMapK:Shared:0.3") // https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter testImplementation(group = "org.junit.jupiter", name = "junit-jupiter", version = "5.6.0") { diff --git a/src/main/kotlin/com/mapk/annotations/KGetterAlias.kt b/src/main/kotlin/com/mapk/annotations/KGetterAlias.kt index 8195905..8aed5f4 100644 --- a/src/main/kotlin/com/mapk/annotations/KGetterAlias.kt +++ b/src/main/kotlin/com/mapk/annotations/KGetterAlias.kt @@ -1,5 +1,5 @@ package com.mapk.annotations -@Target(AnnotationTarget.PROPERTY) +@Target(AnnotationTarget.PROPERTY_GETTER) @Retention(AnnotationRetention.RUNTIME) annotation class KGetterAlias(val value: String) diff --git a/src/main/kotlin/com/mapk/annotations/KPropertyIgnore.kt b/src/main/kotlin/com/mapk/annotations/KGetterIgnore.kt similarity index 54% rename from src/main/kotlin/com/mapk/annotations/KPropertyIgnore.kt rename to src/main/kotlin/com/mapk/annotations/KGetterIgnore.kt index 70db6ee..c9eac8b 100644 --- a/src/main/kotlin/com/mapk/annotations/KPropertyIgnore.kt +++ b/src/main/kotlin/com/mapk/annotations/KGetterIgnore.kt @@ -1,6 +1,6 @@ package com.mapk.annotations -@Target(AnnotationTarget.PROPERTY) +@Target(AnnotationTarget.PROPERTY_GETTER) @Retention(AnnotationRetention.RUNTIME) @MustBeDocumented -annotation class KPropertyIgnore +annotation class KGetterIgnore diff --git a/src/main/kotlin/com/mapk/kmapper/KMapper.kt b/src/main/kotlin/com/mapk/kmapper/KMapper.kt index 556742f..4e79408 100644 --- a/src/main/kotlin/com/mapk/kmapper/KMapper.kt +++ b/src/main/kotlin/com/mapk/kmapper/KMapper.kt @@ -2,8 +2,8 @@ package com.mapk.kmapper import com.mapk.annotations.KConstructor import com.mapk.annotations.KGetterAlias -import com.mapk.annotations.KPropertyAlias -import com.mapk.annotations.KPropertyIgnore +import com.mapk.annotations.KGetterIgnore +import com.mapk.annotations.KParameterAlias import com.mapk.core.ArgumentBucket import com.mapk.core.EnumMapper import com.mapk.core.KFunctionForCall @@ -35,7 +35,7 @@ class KMapper private constructor( private val parameterMap: Map> = function.parameters .filter { it.kind != KParameter.Kind.INSTANCE } .associate { - (it.findAnnotation()?.value ?: propertyNameConverter(it.name!!)) to + (it.findAnnotation()?.value ?: propertyNameConverter(it.name!!)) to ParameterForMap.newInstance(it) } @@ -51,21 +51,26 @@ class KMapper private constructor( } private fun bindArguments(argumentBucket: ArgumentBucket, src: Any) { - src::class.memberProperties.forEach { property -> - val javaGetter: Method? = property.javaGetter - if (javaGetter != null && property.visibility == KVisibility.PUBLIC && property.annotations.none { annotation -> annotation is KPropertyIgnore }) { - parameterMap[property.findAnnotation()?.value ?: property.name]?.let { - // javaGetterを呼び出す方が高速 - javaGetter.isAccessible = true - argumentBucket.setArgument(javaGetter.invoke(src)?.let { value -> - mapObject( - it, - value - ) - }, it.index) - // 終了判定 - if (argumentBucket.isInitialized) return - } + src::class.memberProperties.forEach outer@{ property -> + // propertyが公開されていない場合は処理を行わない + if (property.visibility != KVisibility.PUBLIC) return@outer + + // ゲッターが取れない場合は処理を行わない + val javaGetter: Method = property.javaGetter ?: return@outer + + var alias: String? = null + // NOTE: IgnoreとAliasが同時に指定されるようなパターンを考慮してaliasが取れてもbreakしていない + javaGetter.annotations.forEach { + if (it is KGetterIgnore) return@outer // ignoreされている場合は処理を行わない + if (it is KGetterAlias) alias = it.value + } + + parameterMap[alias ?: property.name]?.let { + // javaGetterを呼び出す方が高速 + javaGetter.isAccessible = true + argumentBucket.setArgument(javaGetter.invoke(src)?.let { value -> mapObject(it, value) }, it.index) + // 終了判定 + if (argumentBucket.isInitialized) return } } } diff --git a/src/test/kotlin/com/mapk/kmapper/KGetterIgnoreTest.kt b/src/test/kotlin/com/mapk/kmapper/KGetterIgnoreTest.kt new file mode 100644 index 0000000..f2985d1 --- /dev/null +++ b/src/test/kotlin/com/mapk/kmapper/KGetterIgnoreTest.kt @@ -0,0 +1,29 @@ +package com.mapk.kmapper + +import com.mapk.annotations.KGetterIgnore +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +class KGetterIgnoreTest { + data class Src1(val arg1: Int, val arg2: String, @get:KGetterIgnore val arg3: Short) + data class Src2(@get:KGetterIgnore val arg2: String, val arg3: Int, val arg4: String) + + data class Dst(val arg1: Int, val arg2: String, val arg3: Int, val arg4: String) + + @Test + @DisplayName("フィールドを無視するテスト") + fun test() { + val src1 = Src1(1, "2-1", 31) + val src2 = Src2("2-2", 32, "4") + + val mapper = KMapper(::Dst) + + val dst1 = mapper.map(src1, src2) + val dst2 = mapper.map(src2, src1) + + assertTrue(dst1 == dst2) + assertEquals(Dst(1, "2-1", 32, "4"), dst1) + } +} diff --git a/src/test/kotlin/com/mapk/kmapper/ParamAliasTest.kt b/src/test/kotlin/com/mapk/kmapper/PropertyAliasTest.kt similarity index 87% rename from src/test/kotlin/com/mapk/kmapper/ParamAliasTest.kt rename to src/test/kotlin/com/mapk/kmapper/PropertyAliasTest.kt index 97d5f19..16cc936 100644 --- a/src/test/kotlin/com/mapk/kmapper/ParamAliasTest.kt +++ b/src/test/kotlin/com/mapk/kmapper/PropertyAliasTest.kt @@ -1,24 +1,24 @@ package com.mapk.kmapper import com.mapk.annotations.KGetterAlias -import com.mapk.annotations.KPropertyAlias +import com.mapk.annotations.KParameterAlias import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test private data class AliasedDst( val arg1: Double, - @param:KPropertyAlias("arg3") val arg2: Int + @param:KParameterAlias("arg3") val arg2: Int ) private data class AliasedSrc( - @KGetterAlias("arg1") + @get:KGetterAlias("arg1") val arg2: Double, val arg3: Int ) @DisplayName("エイリアスを貼った場合のテスト") -class ParamAliasTest { +class PropertyAliasTest { @Test @DisplayName("パラメータにエイリアスを貼った場合") fun paramAliasTest() {