Skip to content

Commit 6abe555

Browse files
authored
Implement empty string coercion for arrays as well (#3564)
1 parent 6e6da86 commit 6abe555

File tree

3 files changed

+118
-6
lines changed

3 files changed

+118
-6
lines changed

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

+28-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
import com.fasterxml.jackson.databind.*;
1212
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
13+
import com.fasterxml.jackson.databind.cfg.CoercionAction;
14+
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
1315
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
1416
import com.fasterxml.jackson.databind.deser.NullValueProvider;
1517
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
@@ -350,10 +352,33 @@ protected Object[] handleNonArray(JsonParser p, DeserializationContext ctxt)
350352
return _emptyValue;
351353
}
352354
value = _nullProvider.getNullValue(ctxt);
353-
} else if (_elementTypeDeserializer == null) {
354-
value = _elementDeserializer.deserialize(p, ctxt);
355355
} else {
356-
value = _elementDeserializer.deserializeWithType(p, ctxt, _elementTypeDeserializer);
356+
if (p.hasToken(JsonToken.VALUE_STRING)) {
357+
String textValue = p.getText();
358+
// https://github.com/FasterXML/jackson-dataformat-xml/issues/513
359+
if (textValue.isEmpty()) {
360+
final CoercionAction act = ctxt.findCoercionAction(logicalType(), handledType(),
361+
CoercionInputShape.EmptyString);
362+
if (act != CoercionAction.Fail) {
363+
return (Object[]) _deserializeFromEmptyString(p, ctxt, act, handledType(),
364+
"empty String (\"\")");
365+
}
366+
} else if (_isBlank(textValue)) {
367+
final CoercionAction act = ctxt.findCoercionFromBlankString(logicalType(), handledType(),
368+
CoercionAction.Fail);
369+
if (act != CoercionAction.Fail) {
370+
return (Object[]) _deserializeFromEmptyString(p, ctxt, act, handledType(),
371+
"blank String (all whitespace)");
372+
}
373+
}
374+
// if coercion failed, we can still add it to a list
375+
}
376+
377+
if (_elementTypeDeserializer == null) {
378+
value = _elementDeserializer.deserialize(p, ctxt);
379+
} else {
380+
value = _elementDeserializer.deserializeWithType(p, ctxt, _elementTypeDeserializer);
381+
}
357382
}
358383
// Ok: bit tricky, since we may want T[], not just Object[]
359384
Object[] result;

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

+29-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
import com.fasterxml.jackson.databind.*;
1111
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
12+
import com.fasterxml.jackson.databind.cfg.CoercionAction;
13+
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
1214
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
1315
import com.fasterxml.jackson.databind.deser.NullValueProvider;
1416
import com.fasterxml.jackson.databind.deser.impl.NullsConstantProvider;
@@ -308,9 +310,33 @@ private final String[] handleNonArray(JsonParser p, DeserializationContext ctxt)
308310
((_unwrapSingle == null) &&
309311
ctxt.isEnabled(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY));
310312
if (canWrap) {
311-
String value = p.hasToken(JsonToken.VALUE_NULL)
312-
? (String) _nullProvider.getNullValue(ctxt)
313-
: _parseString(p, ctxt);
313+
String value;
314+
if (p.hasToken(JsonToken.VALUE_NULL)) {
315+
value = (String) _nullProvider.getNullValue(ctxt);
316+
} else {
317+
if (p.hasToken(JsonToken.VALUE_STRING)) {
318+
String textValue = p.getText();
319+
// https://github.com/FasterXML/jackson-dataformat-xml/issues/513
320+
if (textValue.isEmpty()) {
321+
final CoercionAction act = ctxt.findCoercionAction(logicalType(), handledType(),
322+
CoercionInputShape.EmptyString);
323+
if (act != CoercionAction.Fail) {
324+
return (String[]) _deserializeFromEmptyString(p, ctxt, act, handledType(),
325+
"empty String (\"\")");
326+
}
327+
} else if (_isBlank(textValue)) {
328+
final CoercionAction act = ctxt.findCoercionFromBlankString(logicalType(), handledType(),
329+
CoercionAction.Fail);
330+
if (act != CoercionAction.Fail) {
331+
return (String[]) _deserializeFromEmptyString(p, ctxt, act, handledType(),
332+
"blank String (all whitespace)");
333+
}
334+
}
335+
// if coercion failed, we can still add it to an array
336+
}
337+
338+
value = _parseString(p, ctxt);
339+
}
314340
return new String[] { value };
315341
}
316342
if (p.hasToken(JsonToken.VALUE_STRING)) {

src/test/java/com/fasterxml/jackson/databind/convert/EmptyStringAsSingleValueTest.java

+61
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.fasterxml.jackson.databind.ObjectMapper;
1313
import com.fasterxml.jackson.databind.cfg.CoercionAction;
1414
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
15+
import org.junit.Assert;
1516

1617
// [databind#3418]: Coercion from empty String to Collection<String>, with
1718
// `DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY`
@@ -113,4 +114,64 @@ public void testCoercedBlankToListWrapper() throws Exception {
113114
assertEquals(Collections.emptyList(),
114115
COERCION_MAPPER.readValue("\" \"", new TypeReference<List<StringWrapper>>() {}));
115116
}
117+
118+
public void testEmptyToArray() throws Exception {
119+
// NO coercion + empty string input + StringCollectionDeserializer
120+
Assert.assertArrayEquals(new String[]{""},
121+
NORMAL_MAPPER.readValue("\"\"", new TypeReference<String[]>() {}));
122+
}
123+
124+
public void testEmptyToArrayWrapper() throws Exception {
125+
// NO coercion + empty string input + normal CollectionDeserializer
126+
Assert.assertArrayEquals(new StringWrapper[]{new StringWrapper("")},
127+
NORMAL_MAPPER.readValue("\"\"", new TypeReference<StringWrapper[]>() {}));
128+
}
129+
130+
public void testCoercedEmptyToArray() throws Exception {
131+
// YES coercion + empty string input + StringCollectionDeserializer
132+
Assert.assertArrayEquals(new String[0], COERCION_MAPPER.readValue("\"\"",
133+
new TypeReference<String[]>() {}));
134+
}
135+
136+
public void testCoercedEmptyToArrayWrapper() throws Exception {
137+
// YES coercion + empty string input + normal CollectionDeserializer
138+
Assert.assertArrayEquals(new StringWrapper[0],
139+
COERCION_MAPPER.readValue("\"\"", new TypeReference<StringWrapper[]>() {}));
140+
}
141+
142+
public void testCoercedListToArray() throws Exception {
143+
// YES coercion + empty LIST input + StringCollectionDeserializer
144+
Assert.assertArrayEquals(new String[0],
145+
COERCION_MAPPER.readValue("[]", new TypeReference<String[]>() {}));
146+
}
147+
148+
public void testCoercedListToArrayWrapper() throws Exception {
149+
// YES coercion + empty LIST input + normal CollectionDeserializer
150+
Assert.assertArrayEquals(new StringWrapper[0],
151+
COERCION_MAPPER.readValue("[]", new TypeReference<StringWrapper[]>() {}));
152+
}
153+
154+
public void testBlankToArray() throws Exception {
155+
// NO coercion + empty string input + StringCollectionDeserializer
156+
Assert.assertArrayEquals(new String[]{" "},
157+
NORMAL_MAPPER.readValue("\" \"", new TypeReference<String[]>() {}));
158+
}
159+
160+
public void testBlankToArrayWrapper() throws Exception {
161+
// NO coercion + empty string input + normal CollectionDeserializer
162+
Assert.assertArrayEquals(new StringWrapper[]{new StringWrapper(" ")},
163+
NORMAL_MAPPER.readValue("\" \"", new TypeReference<StringWrapper[]>() {}));
164+
}
165+
166+
public void testCoercedBlankToArray() throws Exception {
167+
// YES coercion + empty string input + StringCollectionDeserializer
168+
Assert.assertArrayEquals(new String[0],
169+
COERCION_MAPPER.readValue("\" \"", new TypeReference<String[]>() {}));
170+
}
171+
172+
public void testCoercedBlankToArrayWrapper() throws Exception {
173+
// YES coercion + empty string input + normal CollectionDeserializer
174+
Assert.assertArrayEquals(new StringWrapper[0],
175+
COERCION_MAPPER.readValue("\" \"", new TypeReference<StringWrapper[]>() {}));
176+
}
116177
}

0 commit comments

Comments
 (0)