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

Commit 5ab85ad

Browse files
authored
Merge pull request #8 from k163377/feature
Add usages to README and add test.
2 parents c35bcec + a64292f commit 5ab85ad

File tree

3 files changed

+212
-14
lines changed

3 files changed

+212
-14
lines changed

README.md

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,197 @@ val dst: Dst = jdbcTemplate.query(query) { rs, _ ->
2929
val dst: Dst = jdbcTemplate.query(query, KRowMapper(::Dst))
3030
```
3131

32+
## Usage
33+
### Convert Naming conventions
34+
`KRowMapper` searches columns by default in camel case.
35+
If the DB is named in snake case, mapping can be done by passing a conversion function(e.g. defined in `JackSon`, `Guava`) to `KRowMapper`.
36+
37+
```kotlin
38+
// if use Guava.
39+
KRowMapper(::Dst) { colName: String ->
40+
CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, colName)
41+
}
42+
```
43+
44+
### Deserialize column
45+
`KRowMapper` provides a deserialization function for the acquisition results of three patterns.
46+
47+
- Deserialize at initialization using the `factory method` or deserialize on initialize.
48+
- Define a deserializer for the `class`.
49+
- Define custom deserializer `annotation`.
50+
51+
#### Deserialize at initialization using the factory method or deserialize on initialize
52+
Deserialization within a `factory method` or initialization is the simplest method.
53+
Also, deserialization from multiple columns to one argument or from one column to multiple arguments cannot be realized other than this method.
54+
55+
```kotlin
56+
// example of deserialize on factory method
57+
data class Dst(
58+
foo: Foo,
59+
bar: Bar,
60+
baz: Baz?,
61+
...
62+
) {
63+
companion object {
64+
fun factory(
65+
foo: String,
66+
bar: String,
67+
baz: Int?,
68+
...
69+
): Dst {
70+
return Dst(
71+
Foo(foo),
72+
Bar.fromString(bar),
73+
baz?.let { Baz(it) },
74+
...
75+
)
76+
}
77+
}
78+
}
79+
80+
val dst: Dst = jdbcTemplate.query(query, KRowMapper((Dst)::factory))
81+
```
82+
83+
#### Define a deserializer for the class
84+
By assigning the `KColumnDeserializer` `annotation` to the `constructor` or `factory method`, deserialization by the `KFunction` can be performed.
85+
The `method` that assigns this `annotation` must have one argument.
86+
87+
When the deserializer is defined in this way, the destination will be as follows.
88+
89+
```kotlin
90+
data class Dst(
91+
val foo: ByConstructor,
92+
val bar: BySecondaryConstructor,
93+
val baz: ByCompanionObject,
94+
val qux: ByStaticMethod
95+
)
96+
```
97+
98+
##### constructor
99+
```kotlin
100+
data class ByConstructor @KColumnDeserializer constructor(val fooString: String)
101+
```
102+
103+
##### secondary constructor
104+
```kotlin
105+
data class BySecondaryConstructor(val barShort: Short) {
106+
@KColumnDeserializer
107+
constructor(bar: String) : this(bar.toShort())
108+
}
109+
```
110+
111+
##### factory method
112+
```kotlin
113+
data class ByCompanionObject(val bazInt: Int) {
114+
companion object {
115+
@KColumnDeserializer
116+
fun factory(baz: String) = ByCompanionObject(baz.toInt())
117+
}
118+
}
119+
```
120+
121+
##### (static method)
122+
`Java` `static method` is also supported.
123+
124+
```java
125+
public class ByStaticMethod {
126+
private final String quxString;
127+
128+
public ByStaticMethod(String quxString) {
129+
this.quxString = quxString;
130+
}
131+
132+
public String getQuxString() {
133+
return quxString;
134+
}
135+
136+
@KColumnDeserializer
137+
public static ByStaticMethod factory(Integer quxArg) {
138+
return new ByStaticMethod(quxArg.toString());
139+
}
140+
}
141+
```
142+
143+
#### Define custom deserializer annotation
144+
`KRowMapper` supports complex deserialization by defining custom deserializer `annotations`.
145+
As an example, a custom deserializer `annotation` that performs deserialization from a `String` to `LocalDateTime` is shown.
146+
147+
```kotlin
148+
// annotation
149+
@Target(AnnotationTarget.VALUE_PARAMETER)
150+
@Retention(AnnotationRetention.RUNTIME)
151+
@MustBeDocumented
152+
@KColumnDeserializeBy(LocalDateTimeDeserializerImpl::class)
153+
annotation class LocalDateTimeDeserializer(val pattern: String = "yyyy-MM-dd'T'HH:mm:ss")
154+
155+
// deserializer
156+
class LocalDateTimeDeserializerImpl(
157+
annotation: LocalDateTimeDeserializer
158+
) : AbstractKColumnDeserializer<LocalDateTimeDeserializer, String, LocalDateTime>(annotation) {
159+
private val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern(annotation.pattern)
160+
161+
override val srcClass: Class<String> = String::class.javaObjectType
162+
163+
override fun deserialize(source: String?): LocalDateTime? {
164+
return source?.let {
165+
LocalDateTime.parse(it, formatter)
166+
}
167+
}
168+
}
169+
```
170+
171+
```kotlin
172+
// usage
173+
data class Dst(@LocalDateTimeDeserializer val dateTime: LocalDateTime)
174+
```
175+
176+
##### annotation
177+
For the `annotation class`, specify the deserializer `class` with the `KColumnDeserializeBy` `annotation`.
178+
Also, the fields prepared for this `annotation class` can be used from the deserializer.
179+
180+
```kotlin
181+
@Target(AnnotationTarget.VALUE_PARAMETER)
182+
@Retention(AnnotationRetention.RUNTIME)
183+
@MustBeDocumented
184+
// LocalDateTimeDeserializerImpl is deserializer class
185+
@KColumnDeserializeBy(LocalDateTimeDeserializerImpl::class)
186+
annotation class LocalDateTimeDeserializer(val pattern: String = "yyyy-MM-dd'T'HH:mm:ss")
187+
```
188+
189+
##### deserializer
190+
Deserializer is created by inheriting `AbstractKColumnDeserializer`.
191+
The meaning of each type parameter is as follows.
192+
193+
- `A`: `Annotation class` (`LocalDateTimeDeserializer` in this example)
194+
- `S`: `Java class` of argument required at deserialization
195+
- `D`: `Class` returned after deserialization
196+
197+
```kotlin
198+
abstract class AbstractKColumnDeserializer<A : Annotation, S : Any, D : Any>(protected val annotation: A) {
199+
abstract val srcClass: Class<S>
200+
abstract fun deserialize(source: S?): D?
201+
}
202+
```
203+
204+
In the example, deserialization from a `String` to `LocalDateTime` is performed based on the `pattern` obtained from the
205+
`LocalDateTimeDeserializer`.
206+
207+
```kotlin
208+
class LocalDateTimeDeserializerImpl(
209+
annotation: LocalDateTimeDeserializer
210+
) : AbstractKColumnDeserializer<LocalDateTimeDeserializer, String, LocalDateTime>(annotation) {
211+
private val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern(annotation.pattern)
212+
213+
override val srcClass: Class<String> = String::class.javaObjectType
214+
215+
override fun deserialize(source: String?): LocalDateTime? {
216+
return source?.let {
217+
LocalDateTime.parse(it, formatter)
218+
}
219+
}
220+
}
221+
```
222+
32223
## Installation
33224
Published on JitPack.
34225
You can use this library on `maven`, `gradle` and any other build tools.

src/test/java/com/mapk/krowmapper/ByStaticMethod.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
import com.mapk.annotations.KColumnDeserializer;
44

55
public class ByStaticMethod {
6-
private final String bazString;
6+
private final String quxString;
77

8-
public ByStaticMethod(String bazString) {
9-
this.bazString = bazString;
8+
public ByStaticMethod(String quxString) {
9+
this.quxString = quxString;
1010
}
1111

12-
public String getBazString() {
13-
return bazString;
12+
public String getQuxString() {
13+
return quxString;
1414
}
1515

1616
@KColumnDeserializer
17-
public static ByStaticMethod factory(Integer bazArg) {
18-
return new ByStaticMethod(bazArg.toString());
17+
public static ByStaticMethod factory(Integer quxArg) {
18+
return new ByStaticMethod(quxArg.toString());
1919
}
2020
}

src/test/kotlin/com/mapk/krowmapper/DeserializeByMethodTest.kt

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,22 @@ import org.junit.jupiter.api.Test
1010

1111
class DeserializeByMethodTest {
1212
data class ByConstructor @KColumnDeserializer constructor(val fooString: String)
13-
data class ByCompanionObject(val barInt: Int) {
13+
data class BySecondaryConstructor(val barShort: Short) {
14+
@KColumnDeserializer
15+
constructor(bar: String) : this(bar.toShort())
16+
}
17+
data class ByCompanionObject(val bazInt: Int) {
1418
companion object {
1519
@KColumnDeserializer
16-
fun factory(bar: String) = ByCompanionObject(bar.toInt())
20+
fun factory(baz: String) = ByCompanionObject(baz.toInt())
1721
}
1822
}
1923

2024
data class Dst(
2125
val foo: ByConstructor,
22-
val bar: ByCompanionObject,
23-
val baz: ByStaticMethod
26+
val bar: BySecondaryConstructor,
27+
val baz: ByCompanionObject,
28+
val qux: ByStaticMethod
2429
)
2530

2631
@Test
@@ -29,12 +34,14 @@ class DeserializeByMethodTest {
2934
val resultSet = mockk<ResultSet>()
3035
every { resultSet.getObject("foo", any<Class<*>>()) } returns "foo"
3136
every { resultSet.getObject("bar", any<Class<*>>()) } returns "123"
32-
every { resultSet.getObject("baz", any<Class<*>>()) } returns 321
37+
every { resultSet.getObject("baz", any<Class<*>>()) } returns "321"
38+
every { resultSet.getObject("qux", any<Class<*>>()) } returns 777
3339

3440
val result = KRowMapper(::Dst).mapRow(resultSet, 0)
3541

3642
Assertions.assertEquals("foo", result.foo.fooString)
37-
Assertions.assertEquals(123, result.bar.barInt)
38-
Assertions.assertEquals("321", result.baz.bazString)
43+
Assertions.assertEquals(123, result.bar.barShort)
44+
Assertions.assertEquals(321, result.baz.bazInt)
45+
Assertions.assertEquals("777", result.qux.quxString)
3946
}
4047
}

0 commit comments

Comments
 (0)