Skip to content
This repository was archived by the owner on Jan 20, 2023. It is now read-only.

Commit 632b6da

Browse files
authored
Merge pull request #20 from k163377/fix_architecture
改名 & アーキテクチャ修正
2 parents bfdd0ea + 1d9fcbc commit 632b6da

File tree

11 files changed

+77
-77
lines changed

11 files changed

+77
-77
lines changed

src/main/kotlin/com/mapk/kmapper/ParameterForMap.kt

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/main/kotlin/com/mapk/kmapper/KMapper.kt renamed to src/main/kotlin/com/mapk/kmapper/PlainKMapper.kt

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.mapk.kmapper
33
import com.mapk.annotations.KGetterAlias
44
import com.mapk.annotations.KGetterIgnore
55
import com.mapk.core.ArgumentBucket
6-
import com.mapk.core.EnumMapper
76
import com.mapk.core.KFunctionForCall
87
import com.mapk.core.getAliasOrName
98
import com.mapk.core.isUseDefaultArgument
@@ -13,11 +12,10 @@ import kotlin.reflect.KClass
1312
import kotlin.reflect.KFunction
1413
import kotlin.reflect.KParameter
1514
import kotlin.reflect.KVisibility
16-
import kotlin.reflect.full.isSuperclassOf
1715
import kotlin.reflect.full.memberProperties
1816
import kotlin.reflect.jvm.javaGetter
1917

20-
class KMapper<T : Any> private constructor(
18+
class PlainKMapper<T : Any> private constructor(
2119
private val function: KFunctionForCall<T>,
2220
parameterNameConverter: (String) -> String
2321
) {
@@ -29,9 +27,9 @@ class KMapper<T : Any> private constructor(
2927
clazz.toKConstructor(), parameterNameConverter
3028
)
3129

32-
private val parameterMap: Map<String, ParameterForMap<*>> = function.parameters
30+
private val parameterMap: Map<String, PlainParameterForMap<*>> = function.parameters
3331
.filter { it.kind != KParameter.Kind.INSTANCE && !it.isUseDefaultArgument() }
34-
.associate { (parameterNameConverter(it.getAliasOrName()!!)) to ParameterForMap.newInstance(it) }
32+
.associate { (parameterNameConverter(it.getAliasOrName()!!)) to PlainParameterForMap.newInstance(it) }
3533

3634
private fun bindArguments(argumentBucket: ArgumentBucket, src: Any) {
3735
src::class.memberProperties.forEach outer@{ property ->
@@ -51,7 +49,7 @@ class KMapper<T : Any> private constructor(
5149
parameterMap[alias ?: property.name]?.let {
5250
// javaGetterを呼び出す方が高速
5351
javaGetter.isAccessible = true
54-
argumentBucket.putIfAbsent(it.param, javaGetter.invoke(src)?.let { value -> mapObject(it, value) })
52+
argumentBucket.putIfAbsent(it.param, javaGetter.invoke(src)?.let { value -> it.mapObject(value) })
5553
// 終了判定
5654
if (argumentBucket.isInitialized) return
5755
}
@@ -62,7 +60,7 @@ class KMapper<T : Any> private constructor(
6260
src.forEach { (key, value) ->
6361
parameterMap[key]?.let { param ->
6462
// 取得した内容がnullでなければ適切にmapする
65-
argumentBucket.putIfAbsent(param.param, value?.let { mapObject(param, it) })
63+
argumentBucket.putIfAbsent(param.param, value?.let { param.mapObject(value) })
6664
// 終了判定
6765
if (argumentBucket.isInitialized) return
6866
}
@@ -71,7 +69,7 @@ class KMapper<T : Any> private constructor(
7169

7270
private fun bindArguments(argumentBucket: ArgumentBucket, srcPair: Pair<*, *>) {
7371
parameterMap[srcPair.first.toString()]?.let {
74-
argumentBucket.putIfAbsent(it.param, srcPair.second?.let { value -> mapObject(it, value) })
72+
argumentBucket.putIfAbsent(it.param, srcPair.second?.let { value -> it.mapObject(value) })
7573
}
7674
}
7775

@@ -110,22 +108,3 @@ class KMapper<T : Any> private constructor(
110108
return function.call(bucket)
111109
}
112110
}
113-
114-
private fun <T : Any, R : Any> mapObject(param: ParameterForMap<R>, value: T): Any? {
115-
val valueClazz: KClass<*> = value::class
116-
117-
// パラメータに対してvalueが代入可能(同じもしくは親クラス)であればそのまま用いる
118-
if (param.clazz.isSuperclassOf(valueClazz)) return value
119-
120-
val converter: KFunction<*>? = param.getConverter(valueClazz)
121-
122-
return when {
123-
// converterに一致する組み合わせが有れば設定されていればそれを使う
124-
converter != null -> converter.call(value)
125-
// 要求された値がenumかつ元が文字列ならenum mapperでマップ
126-
param.javaClazz.isEnum && value is String -> EnumMapper.getEnum(param.clazz.java, value)
127-
// 要求されているパラメータがStringならtoStringする
128-
param.clazz == String::class -> value.toString()
129-
else -> throw IllegalArgumentException("Can not convert $valueClazz to ${param.clazz}")
130-
}
131-
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.mapk.kmapper
2+
3+
import com.mapk.core.EnumMapper
4+
import kotlin.reflect.KClass
5+
import kotlin.reflect.KFunction
6+
import kotlin.reflect.KParameter
7+
import kotlin.reflect.full.isSubclassOf
8+
import kotlin.reflect.full.isSuperclassOf
9+
10+
internal class PlainParameterForMap<T : Any> private constructor(val param: KParameter, private val clazz: KClass<T>) {
11+
private val javaClazz: Class<T> by lazy {
12+
clazz.java
13+
}
14+
// リストの長さが小さいと期待されるためこの形で実装しているが、理想的にはmap的なものが使いたい
15+
private val converters: Set<Pair<KClass<*>, KFunction<T>>> by lazy {
16+
convertersFromConstructors(clazz) + convertersFromStaticMethods(clazz) + convertersFromCompanionObject(clazz)
17+
}
18+
19+
fun <U : Any> mapObject(value: U): Any? {
20+
val valueClazz: KClass<*> = value::class
21+
22+
// パラメータに対してvalueが代入可能(同じもしくは親クラス)であればそのまま用いる
23+
if (clazz.isSuperclassOf(valueClazz)) return value
24+
25+
val converter: KFunction<*>? = getConverter(valueClazz)
26+
27+
return when {
28+
// converterに一致する組み合わせが有れば設定されていればそれを使う
29+
converter != null -> converter.call(value)
30+
// 要求された値がenumかつ元が文字列ならenum mapperでマップ
31+
javaClazz.isEnum && value is String -> EnumMapper.getEnum(javaClazz, value)
32+
// 要求されているパラメータがStringならtoStringする
33+
clazz == String::class -> value.toString()
34+
else -> throw IllegalArgumentException("Can not convert $valueClazz to $clazz")
35+
}
36+
}
37+
38+
// 引数の型がconverterに対して入力可能ならconverterを返す
39+
private fun <R : Any> getConverter(input: KClass<out R>): KFunction<T>? =
40+
converters.find { (key, _) -> input.isSubclassOf(key) }?.second
41+
42+
companion object {
43+
fun newInstance(param: KParameter): PlainParameterForMap<*> {
44+
return PlainParameterForMap(param, param.type.classifier as KClass<*>)
45+
}
46+
}
47+
}

src/test/kotlin/com/mapk/kmapper/ConverterKMapperTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ private data class BoundStaticMethodConverterSrc(val argument: String)
3232
@DisplayName("コンバータ有りでのマッピングテスト")
3333
class ConverterKMapperTest {
3434
@Nested
35-
@DisplayName("KMapper")
35+
@DisplayName("PlainKMapper")
3636
inner class KMapperTest {
3737
@Test
3838
@DisplayName("コンストラクターでのコンバートテスト")
3939
fun constructorConverterTest() {
40-
val mapper = KMapper(ConstructorConverterDst::class)
40+
val mapper = PlainKMapper(ConstructorConverterDst::class)
4141
val result = mapper.map(mapOf("argument" to 1))
4242

4343
assertEquals(ConstructorConverter(1), result.argument)
@@ -46,7 +46,7 @@ class ConverterKMapperTest {
4646
@Test
4747
@DisplayName("コンパニオンオブジェクトに定義したコンバータでのコンバートテスト")
4848
fun companionConverterTest() {
49-
val mapper = KMapper(CompanionConverterDst::class)
49+
val mapper = PlainKMapper(CompanionConverterDst::class)
5050
val result = mapper.map(mapOf("argument" to "arg"))
5151

5252
assertEquals("arg", result.argument.arg)
@@ -55,7 +55,7 @@ class ConverterKMapperTest {
5555
@Test
5656
@DisplayName("スタティックメソッドに定義したコンバータでのコンバートテスト")
5757
fun staticMethodConverterTest() {
58-
val mapper = KMapper(StaticMethodConverterDst::class)
58+
val mapper = PlainKMapper(StaticMethodConverterDst::class)
5959
val result = mapper.map(mapOf("argument" to "1,2,3"))
6060

6161
assertTrue(intArrayOf(1, 2, 3) contentEquals result.argument.arg)

src/test/kotlin/com/mapk/kmapper/DefaultArgumentTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ class DefaultArgumentTest {
1414
private val src = Src(1, "src")
1515

1616
@Nested
17-
@DisplayName("KMapper")
17+
@DisplayName("PlainKMapper")
1818
inner class KMapperTest {
1919
@Test
2020
fun test() {
21-
val result = KMapper(::Dst).map(src)
21+
val result = PlainKMapper(::Dst).map(src)
2222
assertEquals(Dst(1, "default"), result)
2323
}
2424
}

src/test/kotlin/com/mapk/kmapper/EnumMappingTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ private class EnumMappingDst(val language: JvmLanguage?)
1717
@DisplayName("文字列 -> Enumのマッピングテスト")
1818
class EnumMappingTest {
1919
@Nested
20-
@DisplayName("KMapper")
20+
@DisplayName("PlainKMapper")
2121
inner class KMapperTest {
22-
private val mapper = KMapper(EnumMappingDst::class)
22+
private val mapper = PlainKMapper(EnumMappingDst::class)
2323

2424
@ParameterizedTest(name = "Non-Null要求")
2525
@EnumSource(value = JvmLanguage::class)

src/test/kotlin/com/mapk/kmapper/KGetterIgnoreTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ class KGetterIgnoreTest {
1414
data class Dst(val arg1: Int, val arg2: String, val arg3: Int, val arg4: String)
1515

1616
@Nested
17-
@DisplayName("KMapper")
17+
@DisplayName("PlainKMapper")
1818
inner class KMapperTest {
1919
@Test
2020
@DisplayName("フィールドを無視するテスト")
2121
fun test() {
2222
val src1 = Src1(1, "2-1", 31)
2323
val src2 = Src2("2-2", 32, "4")
2424

25-
val mapper = KMapper(::Dst)
25+
val mapper = PlainKMapper(::Dst)
2626

2727
val dst1 = mapper.map(src1, src2)
2828
val dst2 = mapper.map(src2, src1)

src/test/kotlin/com/mapk/kmapper/ParameterNameConverterTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ private data class BoundSrc(val camel_case: String)
1212
@DisplayName("パラメータ名変換のテスト")
1313
class ParameterNameConverterTest {
1414
@Nested
15-
@DisplayName("KMapper")
15+
@DisplayName("PlainKMapper")
1616
inner class KMapperTest {
1717
@Test
1818
@DisplayName("スネークケースsrc -> キャメルケースdst")
1919
fun test() {
2020
val expected = "snakeCase"
2121
val src = mapOf("camel_case" to expected)
2222

23-
val mapper = KMapper(CamelCaseDst::class) {
23+
val mapper = PlainKMapper(CamelCaseDst::class) {
2424
CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, it)
2525
}
2626
val result = mapper.map(src)

src/test/kotlin/com/mapk/kmapper/PropertyAliasTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ private data class AliasedSrc(
2121
@DisplayName("エイリアスを貼った場合のテスト")
2222
class PropertyAliasTest {
2323
@Nested
24-
@DisplayName("KMapper")
24+
@DisplayName("PlainKMapper")
2525
inner class KMapperTest {
2626
@Test
2727
@DisplayName("パラメータにエイリアスを貼った場合")
@@ -32,7 +32,7 @@ class PropertyAliasTest {
3232
"arg3" to 3
3333
)
3434

35-
val result = KMapper(::AliasedDst).map(src)
35+
val result = PlainKMapper(::AliasedDst).map(src)
3636

3737
assertEquals(1.0, result.arg1)
3838
assertEquals(3, result.arg2)
@@ -42,7 +42,7 @@ class PropertyAliasTest {
4242
@DisplayName("ゲッターにエイリアスを貼った場合")
4343
fun getAliasTest() {
4444
val src = AliasedSrc(1.0, 2)
45-
val result = KMapper(::AliasedDst).map(src)
45+
val result = PlainKMapper(::AliasedDst).map(src)
4646

4747
assertEquals(1.0, result.arg1)
4848
assertEquals(2, result.arg2)

src/test/kotlin/com/mapk/kmapper/SimpleKMapperTest.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,14 @@ class SimpleKMapperTest {
7474
}
7575

7676
@Nested
77-
@DisplayName("KMapper")
77+
@DisplayName("PlainKMapper")
7878
inner class KMapperTest {
79-
private val mappers: Set<KMapper<out SimpleDst>> = setOf(
80-
KMapper(SimpleDst::class),
81-
KMapper(::SimpleDst),
82-
KMapper((SimpleDst)::factory),
83-
KMapper(::instanceFunction),
84-
KMapper(SimpleDstExt::class)
79+
private val mappers: Set<PlainKMapper<out SimpleDst>> = setOf(
80+
PlainKMapper(SimpleDst::class),
81+
PlainKMapper(::SimpleDst),
82+
PlainKMapper((SimpleDst)::factory),
83+
PlainKMapper(::instanceFunction),
84+
PlainKMapper(SimpleDstExt::class)
8585
)
8686

8787
@Nested

0 commit comments

Comments
 (0)