Skip to content

Commit 489b749

Browse files
committed
Merge remote-tracking branch 'FasterXML/2.19'
2 parents 237a2eb + f8921c1 commit 489b749

File tree

4 files changed

+157
-2
lines changed

4 files changed

+157
-2
lines changed

release-notes/CREDITS-2.x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Contributors:
1818
# 2.19.0 (not yet released)
1919

2020
WrongWrong (@k163377)
21+
* #878: Fix for #876
2122
* #868: Added test case for FAIL_ON_NULL_FOR_PRIMITIVES
2223
* #866: Upgrade to JUnit5
2324
* #861: Update Kotlin to 1.9.24

release-notes/VERSION-2.x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Co-maintainers:
1818

1919
2.19.0 (not yet released)
2020

21+
#878: Fixed a problem where settings like `@JsonSetter(nulls = AS_EMPTY)` were not being applied when the input was `undefined`.
2122
#869: By using Enum.entries in the acquisition of KotlinFeature.defaults, the initialization load was reduced, albeit slightly.
2223
#861: Kotlin has been upgraded to 1.9.24.
2324
#858: Minor performance improvement of findDefaultCreator in edge cases.

src/main/kotlin/tools/jackson/module/kotlin/KotlinValueInstantiator.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ internal class KotlinValueInstantiator(
7878
paramType.isMarkedNullable -> null
7979
// Primitive types always try to get from a buffer, considering several settings
8080
jsonProp.type.isPrimitive -> buffer.getParameter(ctxt, jsonProp)
81-
// to get suitable "missing" value provided by deserializer
82-
else -> valueDeserializer?.getAbsentValue(ctxt)
81+
// to get suitable "missing" value provided by nullValueProvider
82+
else -> jsonProp.nullValueProvider?.getAbsentValue(ctxt)
8383
}
8484
}
8585

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package tools.jackson.module.kotlin.test.github
2+
3+
import com.fasterxml.jackson.annotation.JsonSetter
4+
import com.fasterxml.jackson.annotation.Nulls
5+
import tools.jackson.module.kotlin.jacksonObjectMapper
6+
import tools.jackson.module.kotlin.readValue
7+
import org.junit.jupiter.api.Nested
8+
import org.junit.jupiter.api.Test
9+
import tools.jackson.module.kotlin.jacksonMapperBuilder
10+
import kotlin.test.assertEquals
11+
12+
class GitHub876 {
13+
data class WithAnnotationWithoutDefault(
14+
@JsonSetter(nulls = Nulls.AS_EMPTY)
15+
val list: List<String>,
16+
@JsonSetter(nulls = Nulls.AS_EMPTY)
17+
val map: Map<String, String>,
18+
@JsonSetter(nulls = Nulls.AS_EMPTY)
19+
val string: String
20+
)
21+
22+
@Nested
23+
inner class WithAnnotationWithoutDefaultTest {
24+
val mapper = jacksonObjectMapper()
25+
26+
@Test
27+
fun nullInput() {
28+
val input = """{"list": null, "map": null, "string": null}"""
29+
val expected = WithAnnotationWithoutDefault(emptyList(), emptyMap(), "")
30+
31+
val actual = mapper.readValue<WithAnnotationWithoutDefault>(input)
32+
33+
assertEquals(expected, actual)
34+
}
35+
36+
@Test
37+
fun undefinedInput() {
38+
val input = """{}"""
39+
val expected = WithAnnotationWithoutDefault(emptyList(), emptyMap(), "")
40+
41+
val actual = mapper.readValue<WithAnnotationWithoutDefault>(input)
42+
43+
assertEquals(expected, actual)
44+
}
45+
}
46+
47+
data class WithAnnotationWithDefault(
48+
@JsonSetter(nulls = Nulls.AS_EMPTY)
49+
val list: List<String> = listOf("default"),
50+
@JsonSetter(nulls = Nulls.AS_EMPTY)
51+
val map: Map<String, String> = mapOf("default" to "default"),
52+
@JsonSetter(nulls = Nulls.AS_EMPTY)
53+
val string: String = "default"
54+
)
55+
56+
@Nested
57+
inner class WithAnnotationWithDefaultTest {
58+
val mapper = jacksonObjectMapper()
59+
60+
@Test
61+
fun nullInput() {
62+
// If null is explicitly specified, the default value is not used
63+
val input = """{"list": null, "map": null, "string": null}"""
64+
val expected = WithAnnotationWithDefault(emptyList(), emptyMap(), "")
65+
66+
val actual = mapper.readValue<WithAnnotationWithDefault>(input)
67+
68+
assertEquals(expected, actual)
69+
}
70+
71+
@Test
72+
fun undefinedInput() {
73+
// If the input is undefined, the default value is used
74+
val input = """{}"""
75+
val expected = WithAnnotationWithDefault()
76+
77+
val actual = mapper.readValue<WithAnnotationWithDefault>(input)
78+
79+
assertEquals(expected, actual)
80+
}
81+
}
82+
83+
// If it is set by configOverride, it is treated in the same way as if it were set by annotation
84+
data class WithoutAnnotationWithoutDefault(
85+
val list: List<String>,
86+
val map: Map<String, String>,
87+
val string: String
88+
)
89+
90+
@Nested
91+
inner class WithoutAnnotationWithoutDefaultTest {
92+
val mapper = jacksonMapperBuilder()
93+
.withConfigOverride(List::class.java) { it.nullHandling = JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY) }
94+
.withConfigOverride(Map::class.java) { it.nullHandling = JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY) }
95+
.withConfigOverride(String::class.java) { it.nullHandling = JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY) }
96+
.build()
97+
98+
@Test
99+
fun nullInput() {
100+
val input = """{"list": null, "map": null, "string": null}"""
101+
val expected = WithoutAnnotationWithoutDefault(emptyList(), emptyMap(), "")
102+
103+
val actual = mapper.readValue<WithoutAnnotationWithoutDefault>(input)
104+
105+
assertEquals(expected, actual)
106+
}
107+
108+
@Test
109+
fun undefinedInput() {
110+
val input = """{}"""
111+
val expected = WithoutAnnotationWithoutDefault(emptyList(), emptyMap(), "")
112+
113+
val actual = mapper.readValue<WithoutAnnotationWithoutDefault>(input)
114+
115+
assertEquals(expected, actual)
116+
}
117+
}
118+
119+
data class WithoutAnnotationWithDefault(
120+
val list: List<String> = listOf("default"),
121+
val map: Map<String, String> = mapOf("default" to "default"),
122+
val string: String = "default"
123+
)
124+
125+
@Nested
126+
inner class WithoutAnnotationWithDefaultTest {
127+
val mapper = jacksonMapperBuilder()
128+
.withConfigOverride(List::class.java) { it.nullHandling = JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY) }
129+
.withConfigOverride(Map::class.java) { it.nullHandling = JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY) }
130+
.withConfigOverride(String::class.java) { it.nullHandling = JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY) }
131+
.build()
132+
133+
@Test
134+
fun nullInput() {
135+
val input = """{"list": null, "map": null, "string": null}"""
136+
val expected = WithoutAnnotationWithDefault(emptyList(), emptyMap(), "")
137+
138+
val actual = mapper.readValue<WithoutAnnotationWithDefault>(input)
139+
140+
assertEquals(expected, actual)
141+
}
142+
143+
@Test
144+
fun undefinedInput() {
145+
val input = """{}"""
146+
val expected = WithoutAnnotationWithDefault()
147+
148+
val actual = mapper.readValue<WithoutAnnotationWithDefault>(input)
149+
150+
assertEquals(expected, actual)
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)