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

Commit 19a9649

Browse files
authored
Merge pull request #14 from k163377/feature
Support for mapping to nested classes.
2 parents 9c7f7c6 + b4132a6 commit 19a9649

File tree

4 files changed

+67
-40
lines changed

4 files changed

+67
-40
lines changed

build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66
}
77

88
group = "com.mapk"
9-
version = "0.9"
9+
version = "0.10"
1010

1111
java {
1212
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -30,7 +30,7 @@ repositories {
3030
dependencies {
3131
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
3232
implementation(kotlin("reflect"))
33-
api("com.github.ProjectMapK:Shared:0.11")
33+
api("com.github.ProjectMapK:Shared:0.12")
3434
// 使うのはRowMapperのみなため他はexclude、またバージョンそのものは使う相手に合わせるためcompileOnly
3535
compileOnly(group = "org.springframework", name = "spring-jdbc", version = "5.2.4.RELEASE") {
3636
exclude(module = "spring-beans")
Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,30 @@
11
package com.mapk.krowmapper
22

33
import com.mapk.core.KFunctionForCall
4-
import com.mapk.core.isUseDefaultArgument
54
import com.mapk.core.toKConstructor
65
import java.sql.ResultSet
76
import kotlin.reflect.KClass
87
import kotlin.reflect.KFunction
9-
import kotlin.reflect.KParameter
108
import org.springframework.jdbc.core.RowMapper
119

1210
class KRowMapper<T : Any> private constructor(
13-
private val function: KFunctionForCall<T>,
14-
parameterNameConverter: (String) -> String
11+
private val function: KFunctionForCall<T>
1512
) : RowMapper<T> {
16-
constructor(function: KFunction<T>, propertyNameConverter: (String) -> String = { it }) : this(
17-
KFunctionForCall(function), propertyNameConverter
13+
constructor(function: KFunction<T>, parameterNameConverter: (String) -> String = { it }) : this(
14+
KFunctionForCall(function, parameterNameConverter)
1815
)
1916

20-
constructor(clazz: KClass<T>, propertyNameConverter: (String) -> String = { it }) : this(
21-
clazz.toKConstructor(), propertyNameConverter
17+
constructor(clazz: KClass<T>, parameterNameConverter: (String) -> String = { it }) : this(
18+
clazz.toKConstructor(parameterNameConverter)
2219
)
2320

24-
private val parameters: List<ParameterForMap> = function.parameters
25-
.filter { it.kind != KParameter.Kind.INSTANCE && !it.isUseDefaultArgument() }
26-
.map { ParameterForMap.newInstance(it, parameterNameConverter) }
21+
private val parameters: List<ParameterForMap> = function.requiredParameters.map { ParameterForMap.newInstance(it) }
2722

2823
override fun mapRow(rs: ResultSet, rowNum: Int): T {
29-
val argumentBucket = function.getArgumentBucket()
24+
val adaptor = function.getArgumentAdaptor()
3025

31-
parameters.forEach { param ->
32-
argumentBucket.putIfAbsent(param.param, param.getObject(rs))
33-
}
26+
parameters.forEach { adaptor.putIfAbsent(it.name, it.getObject(rs)) }
3427

35-
return function.call(argumentBucket)
28+
return function.call(adaptor)
3629
}
3730
}

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

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@ package com.mapk.krowmapper
33
import com.mapk.annotations.KColumnDeserializer
44
import com.mapk.core.EnumMapper
55
import com.mapk.core.KFunctionWithInstance
6-
import com.mapk.core.getAliasOrName
6+
import com.mapk.core.ValueParameter
77
import com.mapk.deserialization.AbstractKColumnDeserializer
88
import com.mapk.deserialization.KColumnDeserializeBy
99
import java.lang.IllegalArgumentException
1010
import java.sql.ResultSet
1111
import kotlin.reflect.KClass
1212
import kotlin.reflect.KFunction
13-
import kotlin.reflect.KParameter
1413
import kotlin.reflect.full.companionObjectInstance
1514
import kotlin.reflect.full.findAnnotation
1615
import kotlin.reflect.full.functions
@@ -20,78 +19,70 @@ import kotlin.reflect.jvm.isAccessible
2019
import kotlin.reflect.jvm.jvmName
2120

2221
internal sealed class ParameterForMap {
23-
abstract val param: KParameter
2422
abstract val name: String
2523
abstract val clazz: Class<*>
2624
abstract fun getObject(rs: ResultSet): Any?
2725

2826
private class Plain(
29-
override val param: KParameter,
3027
override val name: String,
3128
override val clazz: Class<*>
3229
) : ParameterForMap() {
3330
override fun getObject(rs: ResultSet): Any? = rs.getObject(name, clazz)
3431
}
3532

3633
private class Enum(
37-
override val param: KParameter,
3834
override val name: String,
3935
override val clazz: Class<*>
4036
) : ParameterForMap() {
4137
override fun getObject(rs: ResultSet): Any? = EnumMapper.getEnum(clazz, rs.getString(name))
4238
}
4339

4440
private class Deserializer(
45-
override val param: KParameter,
4641
override val name: String,
4742
override val clazz: Class<*>,
4843
private val deserializer: KFunction<*>
4944
) : ParameterForMap() {
5045
constructor(
51-
param: KParameter,
5246
name: String,
5347
deserializer: AbstractKColumnDeserializer<*, *, *>
54-
) : this(param, name, deserializer.srcClass, deserializer::deserialize)
48+
) : this(name, deserializer.srcClass, deserializer::deserialize)
5549

5650
override fun getObject(rs: ResultSet): Any? = deserializer.call(rs.getObject(name, clazz))
5751
}
5852

5953
companion object {
60-
fun newInstance(param: KParameter, parameterNameConverter: (String) -> String): ParameterForMap {
61-
val name = parameterNameConverter(param.getAliasOrName()!!)
62-
54+
fun <T : Any> newInstance(param: ValueParameter<T>): ParameterForMap {
6355
param.getDeserializer()?.let {
64-
return Deserializer(param, name, it)
56+
return Deserializer(param.name, it)
6557
}
6658

67-
val parameterKClazz = param.type.classifier as KClass<*>
68-
69-
parameterKClazz.getDeserializer()?.let {
59+
param.requiredClazz.getDeserializer()?.let {
7060
val targetClass = (it.parameters.single().type.classifier as KClass<*>).javaObjectType
71-
return Deserializer(param, name, targetClass, it)
61+
return Deserializer(param.name, targetClass, it)
7262
}
7363

74-
return parameterKClazz.javaObjectType.let {
64+
return param.requiredClazz.javaObjectType.let {
7565
when (it.isEnum) {
76-
true -> Enum(param, name, it)
77-
false -> Plain(param, name, it)
66+
true -> Enum(param.name, it)
67+
false -> Plain(param.name, it)
7868
}
7969
}
8070
}
8171
}
8272
}
8373

84-
private fun KParameter.getDeserializer(): AbstractKColumnDeserializer<*, *, *>? {
74+
@Suppress("UNCHECKED_CAST")
75+
private fun <T : Any> ValueParameter<T>.getDeserializer(): AbstractKColumnDeserializer<*, *, T>? {
8576
val deserializers = this.annotations.mapNotNull { paramAnnotation ->
8677
paramAnnotation.annotationClass
8778
.findAnnotation<KColumnDeserializeBy>()
8879
?.let { it.deserializer.primaryConstructor!!.call(paramAnnotation) }
8980
}
9081

9182
if (1 < deserializers.size)
92-
throw IllegalArgumentException("Find multiple deserializer from ${(this.type.classifier as KClass<*>).jvmName}")
83+
throw IllegalArgumentException("Find multiple deserializer from ${(this.requiredClazz).jvmName}")
9384

94-
return deserializers.singleOrNull()
85+
return deserializers.singleOrNull() as AbstractKColumnDeserializer<*, *, T>?
9586
}
9687

9788
private fun <T : Any> KClass<T>.getDeserializer(): KFunction<T>? {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.mapk.krowmapper
2+
3+
import com.google.common.base.CaseFormat
4+
import com.mapk.annotations.KParameterFlatten
5+
import com.mapk.core.NameJoiner
6+
import io.mockk.every
7+
import io.mockk.mockk
8+
import io.mockk.verify
9+
import java.sql.ResultSet
10+
import java.time.LocalDateTime
11+
import org.junit.jupiter.api.Assertions.assertEquals
12+
import org.junit.jupiter.api.DisplayName
13+
import org.junit.jupiter.api.Test
14+
15+
@DisplayName("KParameterFlattenテスト")
16+
class KParameterFlattenTest {
17+
data class InnerDst(val fooFoo: Int, val barBar: String)
18+
data class Dst(
19+
@KParameterFlatten(nameJoiner = NameJoiner.Snake::class) val bazBaz: InnerDst,
20+
val quxQux: LocalDateTime
21+
)
22+
23+
private fun camelToSnake(camel: String): String = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, camel)
24+
25+
private val expected = Dst(InnerDst(1, "str"), LocalDateTime.MIN)
26+
27+
@Test
28+
@DisplayName("スネークケースsrc -> キャメルケースdst")
29+
fun test() {
30+
val resultSet = mockk<ResultSet>() {
31+
every { getObject("baz_baz_foo_foo", any<Class<*>>()) } returns 1
32+
every { getObject("baz_baz_bar_bar", any<Class<*>>()) } returns "str"
33+
every { getObject("qux_qux", any<Class<*>>()) } returns LocalDateTime.MIN
34+
}
35+
36+
val result = KRowMapper(::Dst, this::camelToSnake).mapRow(resultSet, 0)
37+
assertEquals(expected, result)
38+
39+
verify(exactly = 1) { resultSet.getObject("baz_baz_foo_foo", Integer::class.java) }
40+
verify(exactly = 1) { resultSet.getObject("baz_baz_bar_bar", String::class.java) }
41+
verify(exactly = 1) { resultSet.getObject("qux_qux", LocalDateTime::class.java) }
42+
}
43+
}

0 commit comments

Comments
 (0)