diff --git a/build.gradle.kts b/build.gradle.kts index 65221ed..a26b7af 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } group = "com.mapk" -version = "0.10" +version = "0.15" java { sourceCompatibility = JavaVersion.VERSION_1_8 @@ -30,7 +30,7 @@ repositories { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation(kotlin("reflect")) - implementation("com.github.ProjectMapK:Shared:0.5") + implementation("com.github.ProjectMapK:Shared:0.6") // 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/KConstructor.kt b/src/main/kotlin/com/mapk/annotations/KConverter.kt similarity index 83% rename from src/main/kotlin/com/mapk/annotations/KConstructor.kt rename to src/main/kotlin/com/mapk/annotations/KConverter.kt index 6ea3720..35034f7 100644 --- a/src/main/kotlin/com/mapk/annotations/KConstructor.kt +++ b/src/main/kotlin/com/mapk/annotations/KConverter.kt @@ -3,4 +3,4 @@ package com.mapk.annotations @Target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) @MustBeDocumented -annotation class KConstructor +annotation class KConverter diff --git a/src/main/kotlin/com/mapk/kmapper/KMapper.kt b/src/main/kotlin/com/mapk/kmapper/KMapper.kt index b6d7b6c..bf03103 100644 --- a/src/main/kotlin/com/mapk/kmapper/KMapper.kt +++ b/src/main/kotlin/com/mapk/kmapper/KMapper.kt @@ -1,23 +1,19 @@ package com.mapk.kmapper -import com.mapk.annotations.KConstructor import com.mapk.annotations.KGetterAlias 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 +import com.mapk.core.getAliasOrName +import com.mapk.core.toKConstructor import java.lang.reflect.Method import kotlin.reflect.KClass import kotlin.reflect.KFunction import kotlin.reflect.KParameter import kotlin.reflect.KVisibility -import kotlin.reflect.full.companionObjectInstance -import kotlin.reflect.full.findAnnotation -import kotlin.reflect.full.functions import kotlin.reflect.full.isSuperclassOf import kotlin.reflect.full.memberProperties -import kotlin.reflect.full.primaryConstructor import kotlin.reflect.jvm.javaGetter class KMapper private constructor( @@ -29,15 +25,12 @@ class KMapper private constructor( ) constructor(clazz: KClass, propertyNameConverter: (String) -> String = { it }) : this( - getTarget(clazz), propertyNameConverter + clazz.toKConstructor(), propertyNameConverter ) private val parameterMap: Map> = function.parameters .filter { it.kind != KParameter.Kind.INSTANCE } - .associate { - (it.findAnnotation()?.value ?: propertyNameConverter(it.name!!)) to - ParameterForMap.newInstance(it) - } + .associate { (propertyNameConverter(it.getAliasOrName()!!)) to ParameterForMap.newInstance(it) } private fun bindArguments(argumentBucket: ArgumentBucket, src: Any) { src::class.memberProperties.forEach outer@{ property -> @@ -117,29 +110,6 @@ class KMapper private constructor( } } -@Suppress("UNCHECKED_CAST") -internal fun getTarget(clazz: KClass): KFunctionForCall { - val factoryConstructor: List> = - clazz.companionObjectInstance?.let { companionObject -> - companionObject::class.functions - .filter { it.annotations.any { annotation -> annotation is KConstructor } } - .map { KFunctionForCall( - it, - companionObject - ) as KFunctionForCall } - } ?: emptyList() - - val constructors: List> = factoryConstructor + clazz.constructors - .filter { it.annotations.any { annotation -> annotation is KConstructor } } - .map { KFunctionForCall(it) } - - if (constructors.size == 1) return constructors.single() - - if (constructors.isEmpty()) return KFunctionForCall(clazz.primaryConstructor!!) - - throw IllegalArgumentException("Find multiple target.") -} - private fun mapObject(param: ParameterForMap, value: T): Any? { val valueClazz: KClass<*> = value::class diff --git a/src/test/kotlin/com/mapk/kmapper/GetTargetTest.kt b/src/test/kotlin/com/mapk/kmapper/GetTargetTest.kt deleted file mode 100644 index 60d2fb1..0000000 --- a/src/test/kotlin/com/mapk/kmapper/GetTargetTest.kt +++ /dev/null @@ -1,69 +0,0 @@ -@file:Suppress("unused") - -package com.mapk.kmapper - -import com.mapk.annotations.KConstructor -import com.mapk.core.KFunctionForCall -import kotlin.reflect.KFunction -import kotlin.reflect.full.memberProperties -import kotlin.reflect.full.primaryConstructor -import kotlin.reflect.jvm.isAccessible -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 -import org.junit.jupiter.api.assertThrows - -private class SecondaryConstructorDst(val argument: Int) { - @KConstructor constructor(argument: Number) : this(argument.toInt()) -} -class CompanionFactoryDst(val argument: IntArray) { - companion object { - @KConstructor - fun factory(csv: String): CompanionFactoryDst { - return csv.split(",").map { it.toInt() }.toIntArray().let { CompanionFactoryDst(it) } - } - } -} -private class ConstructorDst(val argument: String) -class MultipleConstructorDst @KConstructor constructor(val argument: Int) { - @KConstructor constructor(argument: String) : this(argument.toInt()) -} - -@Suppress("UNCHECKED_CAST") -@DisplayName("クラスからのコンストラクタ抽出関連テスト") -class GetTargetTest { - private fun KFunctionForCall.getTargetFunction(): KFunction { - return this::class.memberProperties.first { it.name == "function" }.getter.let { - it.isAccessible = true - it.call(this) as KFunction - } - } - - @Test - @DisplayName("セカンダリコンストラクタからの取得テスト") - fun testGetFromSecondaryConstructor() { - val function = getTarget(SecondaryConstructorDst::class).getTargetFunction() - assertTrue(function.annotations.any { it is KConstructor }) - } - - @Test - @DisplayName("ファクトリーメソッドからの取得テスト") - fun testGetFromFactoryMethod() { - val function = getTarget(SecondaryConstructorDst::class).getTargetFunction() - assertTrue(function.annotations.any { it is KConstructor }) - } - - @Test - @DisplayName("無指定でプライマリコンストラクタからの取得テスト") - fun testGetFromPrimaryConstructor() { - val function = getTarget(ConstructorDst::class).getTargetFunction() - assertEquals(ConstructorDst::class.primaryConstructor, function) - } - - @Test - @DisplayName("対象を複数指定した場合のテスト") - fun testMultipleDeclareConstructor() { - assertThrows { getTarget(MultipleConstructorDst::class) } - } -}