Skip to content

Commit 1464997

Browse files
authored
JsonSetter.contentNulls ignored for Object[], String[] and Collection<String> (#5202)
1 parent dd27a21 commit 1464997

File tree

9 files changed

+393
-10
lines changed

9 files changed

+393
-10
lines changed

release-notes/CREDITS-2.x

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,6 +1863,9 @@ wrongwrong (@k163377)
18631863
* Contributed fix for #5139: In `CollectionDeserializer`, `JsonSetter.contentNulls`
18641864
is sometimes ignored
18651865
(2.19.1)
1866+
* Contributed fix for #5202: #5202: `JsonSetter.contentNulls` ignored for `Object[]`,
1867+
`String[]` and `Collection<String>`
1868+
(2.19.2)
18661869

18671870
Bernd Ahlers (@bernd)
18681871
* 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
@@ -6,6 +6,9 @@ Project: jackson-databind
66

77
2.19.2 (not yet released)
88

9+
#5202: `JsonSetter.contentNulls` ignored for `Object[]`, `String[]`
10+
and `Collection<String>`
11+
(fix by @wrongwrong)
912
#5215: `@JsonAnyGetter` serialization order change from 2.18.4 to 2.19.0
1013
(reported by Eddú M)
1114
(fix by Joo-Hyuk K)

src/main/java/com/fasterxml/jackson/databind/deser/std/ObjectArrayDeserializer.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,19 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt)
211211
if (_skipNullValues) {
212212
continue;
213213
}
214-
value = _nullProvider.getNullValue(ctxt);
214+
value = null;
215215
} else {
216216
value = _deserializeNoNullChecks(p, ctxt);
217217
}
218+
219+
if (value == null) {
220+
value = _nullProvider.getNullValue(ctxt);
221+
222+
if (value == null && _skipNullValues) {
223+
continue;
224+
}
225+
}
226+
218227
if (ix >= chunk.length) {
219228
chunk = buffer.appendCompletedChunk(chunk);
220229
ix = 0;
@@ -275,10 +284,19 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt,
275284
if (_skipNullValues) {
276285
continue;
277286
}
278-
value = _nullProvider.getNullValue(ctxt);
287+
value = null;
279288
} else {
280289
value = _deserializeNoNullChecks(p, ctxt);
281290
}
291+
292+
if (value == null) {
293+
value = _nullProvider.getNullValue(ctxt);
294+
295+
if (value == null && _skipNullValues) {
296+
continue;
297+
}
298+
}
299+
282300
if (ix >= chunk.length) {
283301
chunk = buffer.appendCompletedChunk(chunk);
284302
ix = 0;
@@ -346,7 +364,7 @@ protected Object handleNonArray(JsonParser p, DeserializationContext ctxt)
346364
if (_skipNullValues) {
347365
return _emptyValue;
348366
}
349-
value = _nullProvider.getNullValue(ctxt);
367+
value = null;
350368
} else {
351369
if (p.hasToken(JsonToken.VALUE_STRING)) {
352370
String textValue = p.getText();
@@ -371,6 +389,15 @@ protected Object handleNonArray(JsonParser p, DeserializationContext ctxt)
371389

372390
value = _deserializeNoNullChecks(p, ctxt);
373391
}
392+
393+
if (value == null) {
394+
value = _nullProvider.getNullValue(ctxt);
395+
396+
if (value == null && _skipNullValues) {
397+
return _emptyValue;
398+
}
399+
}
400+
374401
// Ok: bit tricky, since we may want T[], not just Object[]
375402
Object[] result;
376403

@@ -399,4 +426,3 @@ protected Object _deserializeNoNullChecks(JsonParser p, DeserializationContext c
399426
return _elementDeserializer.deserializeWithType(p, ctxt, _elementTypeDeserializer);
400427
}
401428
}
402-

src/main/java/com/fasterxml/jackson/databind/deser/std/StringArrayDeserializer.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,17 @@ public String[] deserialize(JsonParser p, DeserializationContext ctxt) throws IO
162162
if (_skipNullValues) {
163163
continue;
164164
}
165-
value = (String) _nullProvider.getNullValue(ctxt);
166165
} else {
167166
value = _parseString(p, ctxt, _nullProvider);
168167
}
168+
169+
if (value == null) {
170+
value = (String) _nullProvider.getNullValue(ctxt);
171+
172+
if (value == null && _skipNullValues) {
173+
continue;
174+
}
175+
}
169176
}
170177
if (ix >= chunk.length) {
171178
chunk = buffer.appendCompletedChunk(chunk);
@@ -219,13 +226,22 @@ private String[] _deserializeCustom(JsonParser p, DeserializationContext ctxt,
219226
if (_skipNullValues) {
220227
continue;
221228
}
222-
value = (String) _nullProvider.getNullValue(ctxt);
229+
value = null;
223230
} else {
224231
value = deser.deserialize(p, ctxt);
225232
}
226233
} else {
227234
value = deser.deserialize(p, ctxt);
228235
}
236+
237+
if (value == null) {
238+
value = (String) _nullProvider.getNullValue(ctxt);
239+
240+
if (value == null && _skipNullValues) {
241+
continue;
242+
}
243+
}
244+
229245
if (ix >= chunk.length) {
230246
chunk = buffer.appendCompletedChunk(chunk);
231247
ix = 0;
@@ -283,10 +299,17 @@ public String[] deserialize(JsonParser p, DeserializationContext ctxt,
283299
if (_skipNullValues) {
284300
return NO_STRINGS;
285301
}
286-
value = (String) _nullProvider.getNullValue(ctxt);
287302
} else {
288303
value = _parseString(p, ctxt, _nullProvider);
289304
}
305+
306+
if (value == null) {
307+
value = (String) _nullProvider.getNullValue(ctxt);
308+
309+
if (value == null && _skipNullValues) {
310+
continue;
311+
}
312+
}
290313
}
291314
if (ix >= chunk.length) {
292315
chunk = buffer.appendCompletedChunk(chunk);

src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,10 +213,18 @@ public Collection<String> deserialize(JsonParser p, DeserializationContext ctxt,
213213
if (_skipNullValues) {
214214
continue;
215215
}
216-
value = (String) _nullProvider.getNullValue(ctxt);
217216
} else {
218217
value = _parseString(p, ctxt, _nullProvider);
219218
}
219+
220+
if (value == null) {
221+
value = (String) _nullProvider.getNullValue(ctxt);
222+
223+
if (value == null && _skipNullValues) {
224+
continue;
225+
}
226+
}
227+
220228
result.add(value);
221229
}
222230
} catch (Exception e) {
@@ -246,13 +254,22 @@ private Collection<String> deserializeUsingCustom(JsonParser p, DeserializationC
246254
if (_skipNullValues) {
247255
continue;
248256
}
249-
value = (String) _nullProvider.getNullValue(ctxt);
257+
value = null;
250258
} else {
251259
value = deser.deserialize(p, ctxt);
252260
}
253261
} else {
254262
value = deser.deserialize(p, ctxt);
255263
}
264+
265+
if (value == null) {
266+
value = (String) _nullProvider.getNullValue(ctxt);
267+
268+
if (value == null && _skipNullValues) {
269+
continue;
270+
}
271+
}
272+
256273
result.add(value);
257274
}
258275
} catch (Exception e) {
@@ -297,7 +314,7 @@ private final Collection<String> handleNonArray(JsonParser p, DeserializationCon
297314
if (_skipNullValues) {
298315
return result;
299316
}
300-
value = (String) _nullProvider.getNullValue(ctxt);
317+
value = null;
301318
} else {
302319
if (p.hasToken(JsonToken.VALUE_STRING)) {
303320
String textValue = p.getText();
@@ -326,6 +343,15 @@ private final Collection<String> handleNonArray(JsonParser p, DeserializationCon
326343
throw JsonMappingException.wrapWithPath(e, result, result.size());
327344
}
328345
}
346+
347+
if (value == null) {
348+
value = (String) _nullProvider.getNullValue(ctxt);
349+
350+
if (value == null && _skipNullValues) {
351+
return result;
352+
}
353+
}
354+
329355
result.add(value);
330356
return result;
331357
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.fasterxml.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 com.fasterxml.jackson.databind.ObjectMapper;
9+
import com.fasterxml.jackson.databind.exc.InvalidNullException;
10+
import com.fasterxml.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+
.defaultSetterInfo(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+
.defaultSetterInfo(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: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.fasterxml.jackson.databind.deser.jdk;
2+
3+
import java.io.IOException;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
import com.fasterxml.jackson.annotation.JsonSetter;
8+
import com.fasterxml.jackson.annotation.Nulls;
9+
10+
import com.fasterxml.jackson.core.JsonParser;
11+
12+
import com.fasterxml.jackson.databind.DeserializationContext;
13+
import com.fasterxml.jackson.databind.ObjectMapper;
14+
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
15+
import com.fasterxml.jackson.databind.exc.InvalidNullException;
16+
import com.fasterxml.jackson.databind.json.JsonMapper;
17+
import com.fasterxml.jackson.databind.module.SimpleModule;
18+
19+
import static org.junit.jupiter.api.Assertions.assertEquals;
20+
import static org.junit.jupiter.api.Assertions.assertThrows;
21+
22+
// For [databind#5165]
23+
public class StringArrayDeserializer5165Test
24+
{
25+
static class Dst {
26+
public String[] array;
27+
}
28+
29+
// Custom deserializer that converts empty strings to null
30+
static class EmptyStringToNullDeserializer extends StdDeserializer<String> {
31+
private static final long serialVersionUID = 1L;
32+
33+
public EmptyStringToNullDeserializer() {
34+
super(String.class);
35+
}
36+
37+
@Override
38+
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
39+
String value = p.getValueAsString();
40+
if (value != null && value.isEmpty()) {
41+
return null;
42+
}
43+
return value;
44+
}
45+
}
46+
47+
private ObjectMapper createMapperWithCustomDeserializer() {
48+
SimpleModule module = new SimpleModule()
49+
.addDeserializer(String.class, new EmptyStringToNullDeserializer());
50+
51+
return JsonMapper.builder()
52+
.addModule(module)
53+
.defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.FAIL))
54+
.build();
55+
}
56+
57+
@Test
58+
public void nullsFailTest() {
59+
ObjectMapper mapper = createMapperWithCustomDeserializer();
60+
61+
assertThrows(
62+
InvalidNullException.class,
63+
() -> mapper.readValue("{\"array\":[\"\"]}", Dst.class)
64+
);
65+
}
66+
67+
@Test
68+
public void nullsSkipTest() throws Exception {
69+
SimpleModule module = new SimpleModule()
70+
.addDeserializer(String.class, new EmptyStringToNullDeserializer());
71+
72+
ObjectMapper mapper = JsonMapper.builder()
73+
.addModule(module)
74+
.defaultSetterInfo(JsonSetter.Value.forContentNulls(Nulls.SKIP))
75+
.build();
76+
77+
Dst dst = mapper.readValue("{\"array\":[\"\"]}", Dst.class);
78+
79+
assertEquals(0, dst.array.length, "Null values should be skipped");
80+
}
81+
}

0 commit comments

Comments
 (0)