Skip to content

Commit 9e91750

Browse files
committed
Merge branch '2.x' into 3.x
2 parents 01a108b + ad3b119 commit 9e91750

File tree

9 files changed

+383
-10
lines changed

9 files changed

+383
-10
lines changed

release-notes/CREDITS-2.x

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,6 +1866,9 @@ wrongwrong (@k163377)
18661866
* Contributed fix for #5139: In `CollectionDeserializer`, `JsonSetter.contentNulls`
18671867
is sometimes ignored
18681868
(2.19.1)
1869+
* Contributed fix for #5202: #5202: `JsonSetter.contentNulls` ignored for `Object[]`,
1870+
`String[]` and `Collection<String>`
1871+
(2.19.2)
18691872
18701873
Bernd Ahlers (@bernd)
18711874
* Reported #4742: Deserialization with Builder, External type id, `@JsonCreator` failing

release-notes/VERSION-2.x

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ Project: jackson-databind
2828
2929
2.19.2 (not yet released)
3030
31+
#5202: `JsonSetter.contentNulls` ignored for `Object[]`, `String[]`
32+
and `Collection<String>`
33+
(fix by @wrongwrong)
3134
#5215: `@JsonAnyGetter` serialization order change from 2.18.4 to 2.19.0
3235
(reported by Eddú M)
3336
(fix by Joo-Hyuk K)

src/main/java/tools/jackson/databind/deser/jdk/ObjectArrayDeserializer.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,19 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt)
203203
if (_skipNullValues) {
204204
continue;
205205
}
206-
value = _nullProvider.getNullValue(ctxt);
206+
value = null;
207207
} else {
208208
value = _deserializeNoNullChecks(p, ctxt);
209209
}
210+
211+
if (value == null) {
212+
value = _nullProvider.getNullValue(ctxt);
213+
214+
if (value == null && _skipNullValues) {
215+
continue;
216+
}
217+
}
218+
210219
if (ix >= chunk.length) {
211220
chunk = buffer.appendCompletedChunk(chunk);
212221
ix = 0;
@@ -269,10 +278,19 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt,
269278
if (_skipNullValues) {
270279
continue;
271280
}
272-
value = _nullProvider.getNullValue(ctxt);
281+
value = null;
273282
} else {
274283
value = _deserializeNoNullChecks(p, ctxt);
275284
}
285+
286+
if (value == null) {
287+
value = _nullProvider.getNullValue(ctxt);
288+
289+
if (value == null && _skipNullValues) {
290+
continue;
291+
}
292+
}
293+
276294
if (ix >= chunk.length) {
277295
chunk = buffer.appendCompletedChunk(chunk);
278296
ix = 0;
@@ -342,7 +360,7 @@ protected Object handleNonArray(JsonParser p, DeserializationContext ctxt)
342360
if (_skipNullValues) {
343361
return _emptyValue;
344362
}
345-
value = _nullProvider.getNullValue(ctxt);
363+
value = null;
346364
} else {
347365
if (p.hasToken(JsonToken.VALUE_STRING)) {
348366
String textValue = p.getString();
@@ -367,6 +385,15 @@ protected Object handleNonArray(JsonParser p, DeserializationContext ctxt)
367385

368386
value = _deserializeNoNullChecks(p, ctxt);
369387
}
388+
389+
if (value == null) {
390+
value = _nullProvider.getNullValue(ctxt);
391+
392+
if (value == null && _skipNullValues) {
393+
return _emptyValue;
394+
}
395+
}
396+
370397
// Ok: bit tricky, since we may want T[], not just Object[]
371398
Object[] result;
372399

@@ -394,4 +421,3 @@ protected Object _deserializeNoNullChecks(JsonParser p, DeserializationContext c
394421
return _elementDeserializer.deserializeWithType(p, ctxt, _elementTypeDeserializer);
395422
}
396423
}
397-

src/main/java/tools/jackson/databind/deser/jdk/StringArrayDeserializer.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,17 @@ public String[] deserialize(JsonParser p, DeserializationContext ctxt) throws Ja
152152
if (_skipNullValues) {
153153
continue;
154154
}
155-
value = (String) _nullProvider.getNullValue(ctxt);
156155
} else {
157156
value = _parseString(p, ctxt, _nullProvider);
158157
}
158+
159+
if (value == null) {
160+
value = (String) _nullProvider.getNullValue(ctxt);
161+
162+
if (value == null && _skipNullValues) {
163+
continue;
164+
}
165+
}
159166
}
160167
if (ix >= chunk.length) {
161168
chunk = buffer.appendCompletedChunk(chunk);
@@ -210,13 +217,22 @@ protected final String[] _deserializeCustom(JsonParser p, DeserializationContext
210217
if (_skipNullValues) {
211218
continue;
212219
}
213-
value = (String) _nullProvider.getNullValue(ctxt);
220+
value = null;
214221
} else {
215222
value = deser.deserialize(p, ctxt);
216223
}
217224
} else {
218225
value = deser.deserialize(p, ctxt);
219226
}
227+
228+
if (value == null) {
229+
value = (String) _nullProvider.getNullValue(ctxt);
230+
231+
if (value == null && _skipNullValues) {
232+
continue;
233+
}
234+
}
235+
220236
if (ix >= chunk.length) {
221237
chunk = buffer.appendCompletedChunk(chunk);
222238
ix = 0;
@@ -274,10 +290,17 @@ public String[] deserialize(JsonParser p, DeserializationContext ctxt,
274290
if (_skipNullValues) {
275291
return NO_STRINGS;
276292
}
277-
value = (String) _nullProvider.getNullValue(ctxt);
278293
} else {
279294
value = _parseString(p, ctxt, _nullProvider);
280295
}
296+
297+
if (value == null) {
298+
value = (String) _nullProvider.getNullValue(ctxt);
299+
300+
if (value == null && _skipNullValues) {
301+
continue;
302+
}
303+
}
281304
}
282305
if (ix >= chunk.length) {
283306
chunk = buffer.appendCompletedChunk(chunk);

src/main/java/tools/jackson/databind/deser/jdk/StringCollectionDeserializer.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,18 @@ public Collection<String> deserialize(JsonParser p, DeserializationContext ctxt,
208208
if (_skipNullValues) {
209209
continue;
210210
}
211-
value = (String) _nullProvider.getNullValue(ctxt);
212211
} else {
213212
value = _parseString(p, ctxt, _nullProvider);
214213
}
214+
215+
if (value == null) {
216+
value = (String) _nullProvider.getNullValue(ctxt);
217+
218+
if (value == null && _skipNullValues) {
219+
continue;
220+
}
221+
}
222+
215223
result.add(value);
216224
}
217225
} catch (Exception e) {
@@ -242,13 +250,22 @@ private Collection<String> deserializeUsingCustom(JsonParser p, DeserializationC
242250
if (_skipNullValues) {
243251
continue;
244252
}
245-
value = (String) _nullProvider.getNullValue(ctxt);
253+
value = null;
246254
} else {
247255
value = deser.deserialize(p, ctxt);
248256
}
249257
} else {
250258
value = deser.deserialize(p, ctxt);
251259
}
260+
261+
if (value == null) {
262+
value = (String) _nullProvider.getNullValue(ctxt);
263+
264+
if (value == null && _skipNullValues) {
265+
continue;
266+
}
267+
}
268+
252269
result.add(value);
253270
}
254271
} catch (Exception e) {
@@ -294,7 +311,7 @@ private final Collection<String> handleNonArray(JsonParser p, DeserializationCon
294311
if (_skipNullValues) {
295312
return result;
296313
}
297-
value = (String) _nullProvider.getNullValue(ctxt);
314+
value = null;
298315
} else {
299316
if (p.hasToken(JsonToken.VALUE_STRING)) {
300317
String textValue = p.getString();
@@ -318,6 +335,15 @@ private final Collection<String> handleNonArray(JsonParser p, DeserializationCon
318335
}
319336
value = (valueDes == null) ? _parseString(p, ctxt, _nullProvider) : valueDes.deserialize(p, ctxt);
320337
}
338+
339+
if (value == null) {
340+
value = (String) _nullProvider.getNullValue(ctxt);
341+
342+
if (value == null && _skipNullValues) {
343+
return result;
344+
}
345+
}
346+
321347
result.add(value);
322348
return result;
323349
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package tools.jackson.databind.deser.jdk;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import com.fasterxml.jackson.annotation.JsonSetter;
6+
import com.fasterxml.jackson.annotation.Nulls;
7+
8+
import tools.jackson.databind.ObjectMapper;
9+
import tools.jackson.databind.exc.InvalidNullException;
10+
import tools.jackson.databind.json.JsonMapper;
11+
12+
import static org.junit.jupiter.api.Assertions.assertEquals;
13+
import static org.junit.jupiter.api.Assertions.assertThrows;
14+
15+
// For [databind#5165]
16+
public class ObjectArrayDeserializer5165Test
17+
{
18+
static class Dst {
19+
public Integer[] array;
20+
}
21+
22+
@Test
23+
public void nullsFailTest() {
24+
ObjectMapper mapper = JsonMapper.builder()
25+
.changeDefaultNullHandling(n -> JsonSetter.Value.forContentNulls(Nulls.FAIL))
26+
.build();
27+
28+
// NOTE! Relies on default coercion of "" into `null` for `Integer`s...
29+
assertThrows(
30+
InvalidNullException.class,
31+
() -> mapper.readValue("{\"array\":[\"\"]}", Dst.class)
32+
);
33+
}
34+
35+
@Test
36+
public void nullsSkipTest() throws Exception {
37+
ObjectMapper mapper = JsonMapper.builder()
38+
.changeDefaultNullHandling(n -> JsonSetter.Value.forContentNulls(Nulls.SKIP))
39+
.build();
40+
41+
Dst dst = mapper.readValue("{\"array\":[\"\"]}", Dst.class);
42+
// NOTE! Relies on default coercion of "" into `null` for `Integer`s...
43+
assertEquals(0, dst.array.length, "Null values should be skipped");
44+
}
45+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package tools.jackson.databind.deser.jdk;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import com.fasterxml.jackson.annotation.JsonSetter;
6+
import com.fasterxml.jackson.annotation.Nulls;
7+
8+
import tools.jackson.core.JsonParser;
9+
10+
import tools.jackson.databind.DeserializationContext;
11+
import tools.jackson.databind.ObjectMapper;
12+
import tools.jackson.databind.deser.std.StdDeserializer;
13+
import tools.jackson.databind.exc.InvalidNullException;
14+
import tools.jackson.databind.json.JsonMapper;
15+
import tools.jackson.databind.module.SimpleModule;
16+
17+
import static org.junit.jupiter.api.Assertions.assertEquals;
18+
import static org.junit.jupiter.api.Assertions.assertThrows;
19+
20+
// For [databind#5165]
21+
public class StringArrayDeserializer5165Test
22+
{
23+
static class Dst {
24+
public String[] array;
25+
}
26+
27+
// Custom deserializer that converts empty strings to null
28+
static class EmptyStringToNullDeserializer extends StdDeserializer<String> {
29+
public EmptyStringToNullDeserializer() {
30+
super(String.class);
31+
}
32+
33+
@Override
34+
public String deserialize(JsonParser p, DeserializationContext ctxt) {
35+
String value = p.getValueAsString();
36+
if (value != null && value.isEmpty()) {
37+
return null;
38+
}
39+
return value;
40+
}
41+
}
42+
43+
private ObjectMapper createMapperWithCustomDeserializer() {
44+
SimpleModule module = new SimpleModule()
45+
.addDeserializer(String.class, new EmptyStringToNullDeserializer());
46+
47+
return JsonMapper.builder()
48+
.addModule(module)
49+
.changeDefaultNullHandling(n -> JsonSetter.Value.forContentNulls(Nulls.FAIL))
50+
.build();
51+
}
52+
53+
@Test
54+
public void nullsFailTest() {
55+
ObjectMapper mapper = createMapperWithCustomDeserializer();
56+
57+
assertThrows(
58+
InvalidNullException.class,
59+
() -> mapper.readValue("{\"array\":[\"\"]}", Dst.class)
60+
);
61+
}
62+
63+
@Test
64+
public void nullsSkipTest() throws Exception {
65+
SimpleModule module = new SimpleModule()
66+
.addDeserializer(String.class, new EmptyStringToNullDeserializer());
67+
68+
ObjectMapper mapper = JsonMapper.builder()
69+
.addModule(module)
70+
.changeDefaultNullHandling(n -> JsonSetter.Value.forContentNulls(Nulls.SKIP))
71+
.build();
72+
73+
Dst dst = mapper.readValue("{\"array\":[\"\"]}", Dst.class);
74+
75+
assertEquals(0, dst.array.length, "Null values should be skipped");
76+
}
77+
}

0 commit comments

Comments
 (0)