From a6b07132f7f027f95d5b52c5825c540645902eb1 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 19:29:51 +0900 Subject: [PATCH 01/14] =?UTF-8?q?=E3=83=90=E3=83=BC=E3=82=B8=E3=83=A7?= =?UTF-8?q?=E3=83=B3=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 0c252ad..0293b03 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } group = "com.mapk" -version = "0.1" +version = "0.6" java { sourceCompatibility = JavaVersion.VERSION_1_8 From 3259de09453432669960f15d5a320cd93e33007b Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 19:39:20 +0900 Subject: [PATCH 02/14] =?UTF-8?q?=E3=82=A2=E3=83=8E=E3=83=86=E3=83=BC?= =?UTF-8?q?=E3=82=B7=E3=83=A7=E3=83=B3=E3=83=A9=E3=82=A4=E3=83=96=E3=83=A9?= =?UTF-8?q?=E3=83=AA=E5=B0=8E=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 0293b03..3c12044 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -29,6 +29,8 @@ repositories { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation(kotlin("reflect")) + // https://mvnrepository.com/artifact/org.jetbrains/annotations + implementation(group = "org.jetbrains", name = "annotations", version = "19.0.0") // https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter testImplementation(group = "org.junit.jupiter", name = "junit-jupiter", version = "5.6.0") { From 3d7df70b287b6bfcd43fd4bdac156803f1d3c91d Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 19:41:51 +0900 Subject: [PATCH 03/14] =?UTF-8?q?Java=E3=82=B3=E3=83=BC=E3=83=89=E3=81=AB?= =?UTF-8?q?=E3=82=A2=E3=83=8E=E3=83=86=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/mapk/core/BucketGenerator.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/mapk/core/BucketGenerator.java b/src/main/java/com/mapk/core/BucketGenerator.java index b74eda7..0e909d5 100644 --- a/src/main/java/com/mapk/core/BucketGenerator.java +++ b/src/main/java/com/mapk/core/BucketGenerator.java @@ -2,19 +2,24 @@ import kotlin.Pair; import kotlin.reflect.KParameter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; class BucketGenerator { private final int initializationStatus; + @NotNull private final List initializeMask; private final int completionValue; + @NotNull private final KParameter[] keyArray; + @NotNull private final Object[] valueArray; - BucketGenerator(int capacity, Pair instancePair) { + BucketGenerator(int capacity, @Nullable Pair instancePair) { keyArray = new KParameter[capacity]; valueArray = new Object[capacity]; @@ -38,6 +43,7 @@ class BucketGenerator { this.completionValue = completionValue; } + @NotNull ArgumentBucket generate() { return new ArgumentBucket( keyArray.clone(), From be7b0e868cb9e52d4a1d90f6c4fad6d8f4979d7a Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 19:42:59 +0900 Subject: [PATCH 04/14] =?UTF-8?q?=E3=82=A2=E3=83=8E=E3=83=86=E3=83=BC?= =?UTF-8?q?=E3=82=B7=E3=83=A7=E3=83=B3=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/mapk/core/EnumMapper.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/mapk/core/EnumMapper.java b/src/main/java/com/mapk/core/EnumMapper.java index d5074ad..e206016 100644 --- a/src/main/java/com/mapk/core/EnumMapper.java +++ b/src/main/java/com/mapk/core/EnumMapper.java @@ -1,5 +1,8 @@ package com.mapk.core; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + public class EnumMapper { /** * Kotlinの型推論バグでクラスからvalueOfが使えないため、ここだけJavaで書いている(型引数もT extends Enumでは書けなかった) @@ -8,8 +11,9 @@ public class EnumMapper { * @param enumClass * @return Enum.valueOf */ + @Nullable @SuppressWarnings({"unchecked", "rawtypes"}) - public static T getEnum(Class clazz, String value) { + public static T getEnum(@NotNull Class clazz, @Nullable String value) { if (value == null || value.isEmpty()) { return null; } From b619c5dae261d3a54c5c643674908bfe419c12a4 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 21:44:30 +0900 Subject: [PATCH 05/14] =?UTF-8?q?=E6=8B=A1=E5=BC=B5=E9=96=A2=E6=95=B0?= =?UTF-8?q?=E3=82=92=E5=AE=9A=E7=BE=A9=E3=81=99=E3=82=8B=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/com/mapk/core/Functions.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/main/kotlin/com/mapk/core/Functions.kt diff --git a/src/main/kotlin/com/mapk/core/Functions.kt b/src/main/kotlin/com/mapk/core/Functions.kt new file mode 100644 index 0000000..8713f5b --- /dev/null +++ b/src/main/kotlin/com/mapk/core/Functions.kt @@ -0,0 +1,5 @@ +package com.mapk.core + +/** + * 拡張関数類を定義するファイル + */ From 935b5c34d740086c700acbd5a21538f039709fc7 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 21:46:36 +0900 Subject: [PATCH 06/14] =?UTF-8?q?=E3=83=91=E3=83=A9=E3=83=A1=E3=83=BC?= =?UTF-8?q?=E3=82=BF=E3=81=8B=E3=82=89=E3=82=A8=E3=82=A4=E3=83=AA=E3=82=A2?= =?UTF-8?q?=E3=82=B9=E3=82=82=E3=81=97=E3=81=8F=E3=81=AF=E3=83=97=E3=83=AD?= =?UTF-8?q?=E3=83=91=E3=83=86=E3=82=A3=E5=90=8D=E3=82=92=E5=8F=96=E5=BE=97?= =?UTF-8?q?=E3=81=99=E3=82=8B=E9=96=A2=E6=95=B0=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/com/mapk/core/Functions.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/mapk/core/Functions.kt b/src/main/kotlin/com/mapk/core/Functions.kt index 8713f5b..ef29771 100644 --- a/src/main/kotlin/com/mapk/core/Functions.kt +++ b/src/main/kotlin/com/mapk/core/Functions.kt @@ -1,5 +1,10 @@ package com.mapk.core +import com.mapk.annotations.KParameterAlias +import kotlin.reflect.KParameter +import kotlin.reflect.full.findAnnotation + /** - * 拡張関数類を定義するファイル + * パラメータからエイリアスもしくはプロパティ名を取得する関数 */ +fun KParameter.getAliasOrName(): String? = findAnnotation()?.value ?: name From b87d030ec8c93851b339234bf34ab1f1c2c043aa Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 21:55:21 +0900 Subject: [PATCH 07/14] =?UTF-8?q?krowmapper=E3=81=A7=E4=BD=BF=E3=81=88?= =?UTF-8?q?=E3=81=AA=E3=81=84=E3=81=AE=E3=81=A7=E3=80=81shared=E3=81=8B?= =?UTF-8?q?=E3=82=89=E3=81=AF=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/com/mapk/annotations/KConverter.kt | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 src/main/kotlin/com/mapk/annotations/KConverter.kt diff --git a/src/main/kotlin/com/mapk/annotations/KConverter.kt b/src/main/kotlin/com/mapk/annotations/KConverter.kt deleted file mode 100644 index 35034f7..0000000 --- a/src/main/kotlin/com/mapk/annotations/KConverter.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.mapk.annotations - -@Target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION) -@Retention(AnnotationRetention.RUNTIME) -@MustBeDocumented -annotation class KConverter From dc80169144a8ce2e82cda000fc5adb99bff33f40 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 22:01:17 +0900 Subject: [PATCH 08/14] =?UTF-8?q?=E3=81=A9=E3=81=86=E3=81=9B=E3=81=AA?= =?UTF-8?q?=E3=81=AE=E3=81=A7=E4=B8=80=E5=BF=9C=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/com/mapk/core/ArgumentBucket.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/mapk/core/ArgumentBucket.kt b/src/main/kotlin/com/mapk/core/ArgumentBucket.kt index d148cff..464e846 100644 --- a/src/main/kotlin/com/mapk/core/ArgumentBucket.kt +++ b/src/main/kotlin/com/mapk/core/ArgumentBucket.kt @@ -42,7 +42,7 @@ class ArgumentBucket internal constructor( override val keys: MutableSet get() = keyArray.filterNotNull().toMutableSet() override val values: MutableCollection - get() = throw UnsupportedOperationException() + get() = valueArray.filterIndexed { i, _ -> initializationStatus and initializeMask[i] != 0 }.toMutableList() fun putIfAbsent(key: KParameter, value: Any?) { val index = key.index From 2d10dd554e0442d3c66359fb06581bdb002055f8 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 22:04:03 +0900 Subject: [PATCH 09/14] =?UTF-8?q?=E4=B8=80=E5=BF=9C=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/com/mapk/core/ArgumentBucket.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/mapk/core/ArgumentBucket.kt b/src/main/kotlin/com/mapk/core/ArgumentBucket.kt index 464e846..266812d 100644 --- a/src/main/kotlin/com/mapk/core/ArgumentBucket.kt +++ b/src/main/kotlin/com/mapk/core/ArgumentBucket.kt @@ -1,5 +1,6 @@ package com.mapk.core +import java.util.Objects import kotlin.reflect.KParameter class ArgumentBucket internal constructor( @@ -26,9 +27,7 @@ class ArgumentBucket internal constructor( return keyArray[key.index] != null } - override fun containsValue(value: Any?): Boolean { - throw UnsupportedOperationException() - } + override fun containsValue(value: Any?): Boolean = valueArray.any { Objects.equals(value, it) } override fun get(key: KParameter): Any? = valueArray[key.index] fun getByIndex(key: Int): Any? = From 9320f379d7fbd5f0fc4d342e5dd01b6b9835b106 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 22:35:47 +0900 Subject: [PATCH 10/14] =?UTF-8?q?KConstructor=E3=82=A2=E3=83=8E=E3=83=86?= =?UTF-8?q?=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92=E7=A7=BB=E6=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/com/mapk/annotations/KConstructor.kt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/kotlin/com/mapk/annotations/KConstructor.kt diff --git a/src/main/kotlin/com/mapk/annotations/KConstructor.kt b/src/main/kotlin/com/mapk/annotations/KConstructor.kt new file mode 100644 index 0000000..6ea3720 --- /dev/null +++ b/src/main/kotlin/com/mapk/annotations/KConstructor.kt @@ -0,0 +1,6 @@ +package com.mapk.annotations + +@Target(AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION) +@Retention(AnnotationRetention.RUNTIME) +@MustBeDocumented +annotation class KConstructor From 87d860cf377fdcf09ccac56e06c10960331252f4 Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 22:37:51 +0900 Subject: [PATCH 11/14] =?UTF-8?q?toKConstructor=E3=81=A8=E3=81=97=E3=81=A6?= =?UTF-8?q?KConstructor=E3=81=8B=E3=82=89=E3=81=AE=E5=8F=96=E5=BE=97?= =?UTF-8?q?=E3=82=92=E7=A7=BB=E6=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/mapk/core/KFunctionForCall.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/main/kotlin/com/mapk/core/KFunctionForCall.kt b/src/main/kotlin/com/mapk/core/KFunctionForCall.kt index 33b8a3f..3cc727b 100644 --- a/src/main/kotlin/com/mapk/core/KFunctionForCall.kt +++ b/src/main/kotlin/com/mapk/core/KFunctionForCall.kt @@ -1,7 +1,12 @@ package com.mapk.core +import com.mapk.annotations.KConstructor +import kotlin.reflect.KClass import kotlin.reflect.KFunction import kotlin.reflect.KParameter +import kotlin.reflect.full.companionObjectInstance +import kotlin.reflect.full.functions +import kotlin.reflect.full.primaryConstructor import kotlin.reflect.jvm.isAccessible class KFunctionForCall(private val function: KFunction, instance: Any? = null) { @@ -28,3 +33,26 @@ class KFunctionForCall(private val function: KFunction, instance: Any? = n if (argumentBucket.isInitialized) function.call(*argumentBucket.valueArray) else function.callBy(argumentBucket) } + +@Suppress("UNCHECKED_CAST") +fun KClass.toKConstructor(): KFunctionForCall { + val factoryConstructor: List> = + this.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 + this.constructors + .filter { it.annotations.any { annotation -> annotation is KConstructor } } + .map { KFunctionForCall(it) } + + if (constructors.size == 1) return constructors.single() + + if (constructors.isEmpty()) return KFunctionForCall(this.primaryConstructor!!) + + throw IllegalArgumentException("Find multiple target.") +} From 53bcf0e4cb2c48d3cb58f3bfd596074c317f4cfd Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 22:45:40 +0900 Subject: [PATCH 12/14] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E7=94=A8?= =?UTF-8?q?=E3=81=AB=E5=85=AC=E9=96=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/com/mapk/core/KFunctionForCall.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/mapk/core/KFunctionForCall.kt b/src/main/kotlin/com/mapk/core/KFunctionForCall.kt index 3cc727b..7cbbb64 100644 --- a/src/main/kotlin/com/mapk/core/KFunctionForCall.kt +++ b/src/main/kotlin/com/mapk/core/KFunctionForCall.kt @@ -9,7 +9,7 @@ import kotlin.reflect.full.functions import kotlin.reflect.full.primaryConstructor import kotlin.reflect.jvm.isAccessible -class KFunctionForCall(private val function: KFunction, instance: Any? = null) { +class KFunctionForCall(internal val function: KFunction, instance: Any? = null) { val parameters: List = function.parameters private val generator: BucketGenerator From 35f02aff483d1139ee45da65669f005f06d186af Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 22:50:15 +0900 Subject: [PATCH 13/14] =?UTF-8?q?=E5=BE=AE=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/com/mapk/core/KFunctionForCall.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/kotlin/com/mapk/core/KFunctionForCall.kt b/src/main/kotlin/com/mapk/core/KFunctionForCall.kt index 7cbbb64..51fa697 100644 --- a/src/main/kotlin/com/mapk/core/KFunctionForCall.kt +++ b/src/main/kotlin/com/mapk/core/KFunctionForCall.kt @@ -40,10 +40,7 @@ fun KClass.toKConstructor(): KFunctionForCall { this.companionObjectInstance?.let { companionObject -> companionObject::class.functions .filter { it.annotations.any { annotation -> annotation is KConstructor } } - .map { KFunctionForCall( - it, - companionObject - ) as KFunctionForCall } + .map { KFunctionForCall(it, companionObject) as KFunctionForCall } } ?: emptyList() val constructors: List> = factoryConstructor + this.constructors From d24d36997c5100eaa44369a837c03e1d2ad5deac Mon Sep 17 00:00:00 2001 From: wrongwrong Date: Sat, 14 Mar 2020 22:50:26 +0900 Subject: [PATCH 14/14] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=92?= =?UTF-8?q?=E7=A7=BB=E6=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mapk/core/ToKConstructorTest.kt | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/test/kotlin/com/mapk/core/ToKConstructorTest.kt diff --git a/src/test/kotlin/com/mapk/core/ToKConstructorTest.kt b/src/test/kotlin/com/mapk/core/ToKConstructorTest.kt new file mode 100644 index 0000000..375633d --- /dev/null +++ b/src/test/kotlin/com/mapk/core/ToKConstructorTest.kt @@ -0,0 +1,68 @@ +package com.mapk.core + +import com.mapk.annotations.KConstructor +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 +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows + +@Suppress("UNCHECKED_CAST", "unused") +@DisplayName("クラスからのコンストラクタ抽出関連テスト") +class ToKConstructorTest { + 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()) + } + + 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 = SecondaryConstructorDst::class.toKConstructor().function + Assertions.assertTrue(function.annotations.any { it is KConstructor }) + } + + @Test + @DisplayName("ファクトリーメソッドからの取得テスト") + fun testGetFromFactoryMethod() { + val function = CompanionFactoryDst::class.toKConstructor().function + Assertions.assertTrue(function.annotations.any { it is KConstructor }) + } + + @Test + @DisplayName("無指定でプライマリコンストラクタからの取得テスト") + fun testGetFromPrimaryConstructor() { + val function = ConstructorDst::class.toKConstructor().function + Assertions.assertEquals(ConstructorDst::class.primaryConstructor, function) + } + + @Test + @DisplayName("対象を複数指定した場合のテスト") + fun testMultipleDeclareConstructor() { + assertThrows { MultipleConstructorDst::class.toKConstructor() } + } +}