Skip to content

Commit f8921c1

Browse files
authored
Merge pull request #878 from k163377/876
Fix for #876
2 parents 9d4ad6a + 4c0a067 commit f8921c1

File tree

4 files changed

+156
-2
lines changed

4 files changed

+156
-2
lines changed

release-notes/CREDITS-2.x

+1
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

+1
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/com/fasterxml/jackson/module/kotlin/KotlinValueInstantiator.kt

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

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

0 commit comments

Comments
 (0)