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

Commit cb0bdcd

Browse files
authored
Merge pull request #2 from k163377/feature
Feature
2 parents fa20717 + 0a35ce4 commit cb0bdcd

File tree

7 files changed

+92
-18
lines changed

7 files changed

+92
-18
lines changed

build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,16 @@ dependencies {
3333
testImplementation(group = "org.junit.jupiter", name = "junit-jupiter", version = "5.6.0") {
3434
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
3535
}
36+
// 現状プロパティ名の変換はテストでしか使っていないのでtestImplementation
37+
// https://mvnrepository.com/artifact/com.google.guava/guava
38+
testImplementation(group = "com.google.guava", name = "guava", version = "28.2-jre")
3639
}
3740

3841
tasks.compileKotlin {
3942
dependsOn("ktlintFormat")
4043
kotlinOptions {
4144
jvmTarget = "1.8"
45+
allWarningsAsErrors = true
4246
}
4347
}
4448

src/main/kotlin/com/wrongwrong/mapk/core/CompanionKFunction.kt renamed to src/main/kotlin/com/wrongwrong/mapk/core/KFunctionWithInstance.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@ package com.wrongwrong.mapk.core
33
import kotlin.reflect.KFunction
44
import kotlin.reflect.KParameter
55
import kotlin.reflect.full.instanceParameter
6+
import kotlin.reflect.jvm.isAccessible
67

7-
internal class CompanionKFunction<T>(
8+
internal class KFunctionWithInstance<T>(
89
private val function: KFunction<T>,
910
private val instance: Any
1011
) : KFunction<T> by function {
12+
init {
13+
// このインスタンスを生成している時点でfunctionにアクセスしたい状況なので、アクセシビリティはここでセットする
14+
function.isAccessible = true
15+
}
16+
1117
private val instanceParam by lazy { mapOf(function.instanceParameter!! to instance) }
1218

1319
override val parameters: List<KParameter> by lazy {

src/main/kotlin/com/wrongwrong/mapk/core/KMapper.kt

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import com.wrongwrong.mapk.annotations.KPropertyAlias
55
import com.wrongwrong.mapk.annotations.KPropertyIgnore
66
import kotlin.reflect.KClass
77
import kotlin.reflect.KFunction
8-
import kotlin.reflect.KParameter
98
import kotlin.reflect.KProperty1
109
import kotlin.reflect.KVisibility
1110
import kotlin.reflect.full.companionObjectInstance
@@ -20,16 +19,12 @@ class KMapper<T : Any>(private val function: KFunction<T>, propertyNameConverter
2019
getTarget(clazz), propertyNameConverter
2120
)
2221

23-
private val parameters: Set<ParameterForMap<*>>
22+
private val parameters: Set<ParameterForMap<*>> = function.parameters
23+
.map { ParameterForMap.newInstance(it, propertyNameConverter) }
24+
.toSet()
2425

2526
init {
26-
val params: List<KParameter> = function.parameters
27-
28-
if (params.isEmpty()) throw IllegalArgumentException("This function is not require arguments.")
29-
30-
parameters = params
31-
.map { ParameterForMap.newInstance(it, propertyNameConverter) }
32-
.toSet()
27+
if (parameters.isEmpty()) throw IllegalArgumentException("This function is not require arguments.")
3328

3429
// private関数に対してもマッピングできなければ何かと不都合があるため、accessibleは書き換える
3530
function.isAccessible = true
@@ -44,6 +39,12 @@ class KMapper<T : Any>(private val function: KFunction<T>, propertyNameConverter
4439
}.let { function.callBy(it) }
4540
}
4641

42+
fun map(srcPair: Pair<String, Any?>): T = parameters
43+
.single { it.name == srcPair.first }
44+
.let {
45+
function.callBy(mapOf(it.param to srcPair.second?.let { value -> mapObject(it, value) }))
46+
}
47+
4748
fun map(src: Any): T {
4849
val srcMap: Map<String, KProperty1.Getter<*, *>> =
4950
src::class.memberProperties.filterTargets().associate { property ->
@@ -117,11 +118,7 @@ internal fun <T : Any> getTarget(clazz: KClass<T>): KFunction<T> {
117118
clazz.companionObjectInstance?.let { companionObject ->
118119
companionObject::class.functions
119120
.filter { it.annotations.any { annotation -> annotation is KConstructor } }
120-
.map {
121-
// isAccessibleの書き換えはKotlinの都合で先に行う必要が有る
122-
it.isAccessible = true
123-
CompanionKFunction(it, companionObject) as KFunction<T>
124-
}
121+
.map { KFunctionWithInstance(it, companionObject) as KFunction<T> }
125122
} ?: emptyList()
126123

127124
val constructors: List<KFunction<T>> = factoryConstructor + clazz.constructors

src/main/kotlin/com/wrongwrong/mapk/core/ParameterForMap.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ private fun <T : Any> creatorsFromCompanionObject(clazz: KClass<T>): Set<Pair<KC
6666
companionObject::class.functions
6767
.filter { it.annotations.any { annotation -> annotation is KConverter } }
6868
.map { function ->
69-
// isAccessibleの書き換えはKotlinの都合で先に行う必要が有る
70-
function.isAccessible = true
71-
val func: KFunction<T> = CompanionKFunction(function, companionObject) as KFunction<T>
69+
val func: KFunction<T> = KFunctionWithInstance(function, companionObject) as KFunction<T>
7270

7371
(func.parameters.single().type.classifier as KClass<*>) to func
7472
}.toSet()
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@file:Suppress("unused")
2+
3+
package mapk.core
4+
5+
import com.wrongwrong.mapk.core.KMapper
6+
import org.junit.jupiter.api.Assertions.assertEquals
7+
import org.junit.jupiter.api.DisplayName
8+
import org.junit.jupiter.params.ParameterizedTest
9+
import org.junit.jupiter.params.provider.EnumSource
10+
11+
enum class JvmLanguage {
12+
Java, Scala, Groovy, Kotlin
13+
}
14+
15+
private class EnumMappingDst(val language: JvmLanguage?)
16+
17+
@DisplayName("文字列 -> Enumのマッピングテスト")
18+
class EnumMappingTest {
19+
private val mapper = KMapper(EnumMappingDst::class)
20+
21+
@ParameterizedTest(name = "Non-Null要求")
22+
@EnumSource(value = JvmLanguage::class)
23+
fun test(language: JvmLanguage) {
24+
val result = mapper.map("language" to language.name)
25+
26+
assertEquals(language, result.language)
27+
}
28+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package mapk.core
2+
3+
import com.google.common.base.CaseFormat
4+
import com.wrongwrong.mapk.core.KMapper
5+
import org.junit.jupiter.api.Assertions.assertEquals
6+
import org.junit.jupiter.api.DisplayName
7+
import org.junit.jupiter.api.Test
8+
9+
private class CamelCaseDst(val camelCase: String)
10+
11+
@DisplayName("プロパティ名変換のテスト")
12+
class PropertyNameConverterTest {
13+
@Test
14+
@DisplayName("スネークケースsrc -> キャメルケースdst")
15+
fun test() {
16+
val expected = "snakeCase"
17+
val src = mapOf("camel_case" to expected)
18+
19+
val mapper = KMapper(CamelCaseDst::class) { CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, it) }
20+
val result = mapper.map(src)
21+
22+
assertEquals(expected, result.camelCase)
23+
}
24+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package mapk.core
2+
3+
import com.wrongwrong.mapk.core.KMapper
4+
import org.junit.jupiter.api.Assertions.assertEquals
5+
import org.junit.jupiter.api.DisplayName
6+
import org.junit.jupiter.api.Test
7+
8+
private data class StringMappingDst(val value: String)
9+
10+
@DisplayName("文字列に対してtoStringしたものを渡すテスト")
11+
class StringMappingTest {
12+
@Test
13+
fun test() {
14+
val result: StringMappingDst = KMapper(StringMappingDst::class).map("value" to 1)
15+
assertEquals("1", result.value)
16+
}
17+
}

0 commit comments

Comments
 (0)