Skip to content

Commit e5fbf10

Browse files
committed
Merge branch '2.15'
2 parents b8c53ed + 16c4e3a commit e5fbf10

File tree

4 files changed

+188
-5
lines changed

4 files changed

+188
-5
lines changed

release-notes/CREDITS-2.x

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,5 +221,11 @@ Joo Hyuk Kim (JooHyukKim@github)
221221
PJ Fanning (pjfanning@github)
222222

223223
* Contributed fix for #533: (Android) java.lang.NoClassDefFoundError: Failed resolution
224-
of: Ljavax/xml/stream/XMLInputFactory
224+
of: Ljavax/xml/stream/XMLInputFactory
225+
(2.15.0)
226+
227+
Marco Belladelli (mbladel@github)
228+
229+
* Contributed fix for #584: Deserialization of `null` String values in Arrays / `Collection`s
230+
not working as expected
225231
(2.15.0)

release-notes/VERSION-2.x

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Project: jackson-dataformat-xml
44
=== Releases ===
55
------------------------------------------------------------------------
66

7-
2.15.0 (not yet released)
7+
2.15.0-rc1 (18-Mar-2023)
88

99
#533: (Android) java.lang.NoClassDefFoundError: Failed resolution
1010
of: Ljavax/xml/stream/XMLInputFactory
@@ -19,6 +19,9 @@ Project: jackson-dataformat-xml
1919
for XML pretty-printing
2020
(requested by @koalalam)
2121
(contributed by Joo Hyuk K)
22+
#584: Deserialization of `null` String values in Arrays / `Collection`s
23+
not working as expected
24+
(fix contributed by Marco B)
2225

2326
2.14.2 (28-Jan-2023)
2427

src/main/java/tools/jackson/dataformat/xml/deser/FromXmlParser.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -834,12 +834,16 @@ public String nextTextValue() throws JacksonException
834834
switch (token) {
835835
case XmlTokenStream.XML_END_ELEMENT:
836836
if (_mayBeLeaf) {
837-
// NOTE: this is different from nextToken() -- produce "", NOT null
838837
_mayBeLeaf = false;
839-
_currToken = JsonToken.VALUE_STRING;
838+
// 18-Mar-2023, tatu: [dataformat-xml#584 / #585] in 2.14 and before
839+
// returned VALUE_STRING on assumption we never expose `null`s if
840+
// asked text value -- but that seems incorrect. Hoping this won't
841+
// break anything in 2.15+
842+
843+
_currToken = JsonToken.VALUE_NULL;
840844
// 13-May-2020, tatu: [dataformat-xml#397]: advance `index`
841845
_streamReadContext.valueStarted();
842-
return (_currText = "");
846+
return (_currText = null);
843847
}
844848
_currToken = _streamReadContext.inArray() ? JsonToken.END_ARRAY : JsonToken.END_OBJECT;
845849
_streamReadContext = _streamReadContext.getParent();
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package tools.jackson.dataformat.xml.lists;
2+
3+
import java.util.HashMap;
4+
import java.util.List;
5+
import java.util.Map;
6+
7+
import org.junit.Test;
8+
9+
import tools.jackson.core.type.TypeReference;
10+
import tools.jackson.dataformat.xml.XmlMapper;
11+
12+
import static tools.jackson.dataformat.xml.deser.FromXmlParser.Feature.PROCESS_XSI_NIL;
13+
import static tools.jackson.dataformat.xml.ser.ToXmlGenerator.Feature.WRITE_NULLS_AS_XSI_NIL;
14+
import static java.util.Arrays.asList;
15+
import static org.junit.Assert.assertEquals;
16+
import static org.junit.Assert.assertNotNull;
17+
import static org.junit.Assert.assertNull;
18+
19+
// [dataformat-xml#584]
20+
public class StringListRoundtripTest {
21+
private final static XmlMapper MAPPER = new XmlMapper();
22+
23+
@Test
24+
public void testStringArray() throws Exception
25+
{
26+
// default mode, should get back empty string
27+
MAPPER.disable(WRITE_NULLS_AS_XSI_NIL);
28+
MAPPER.enable(PROCESS_XSI_NIL);
29+
stringArrayRoundtrip(false);
30+
31+
// xsi null enabled, should get back null
32+
MAPPER.enable(WRITE_NULLS_AS_XSI_NIL);
33+
MAPPER.enable(PROCESS_XSI_NIL);
34+
stringArrayRoundtrip(true);
35+
36+
// xsi null write enabled but processing disabled, should get back empty string
37+
MAPPER.enable(WRITE_NULLS_AS_XSI_NIL);
38+
MAPPER.disable(PROCESS_XSI_NIL);
39+
stringArrayRoundtrip(false);
40+
}
41+
42+
private void stringArrayRoundtrip(boolean shouldBeNull) throws Exception
43+
{
44+
String[] array = new String[] {"", "test", null, "test2"};
45+
46+
// serialize to string
47+
String xml = MAPPER.writeValueAsString(array);
48+
assertNotNull(xml);
49+
50+
// then bring it back
51+
String[] result = MAPPER.readValue(xml, String[].class);
52+
assertEquals(4, result.length);
53+
assertEquals("", result[0]);
54+
assertEquals("test", result[1]);
55+
if (shouldBeNull)
56+
{
57+
assertNull(result[2]);
58+
} else
59+
{
60+
assertEquals("", result[2]);
61+
}
62+
assertEquals("test2", result[3]);
63+
}
64+
65+
@Test
66+
public void testStringList() throws Exception
67+
{
68+
// default mode, should get back empty string
69+
MAPPER.disable(WRITE_NULLS_AS_XSI_NIL);
70+
MAPPER.enable(PROCESS_XSI_NIL);
71+
stringListRoundtrip(false);
72+
73+
// xsi null enabled, should get back null
74+
MAPPER.enable(WRITE_NULLS_AS_XSI_NIL);
75+
MAPPER.enable(PROCESS_XSI_NIL);
76+
stringListRoundtrip(true);
77+
78+
// xsi null write enabled but processing disabled, should get back empty string
79+
MAPPER.enable(WRITE_NULLS_AS_XSI_NIL);
80+
MAPPER.disable(PROCESS_XSI_NIL);
81+
stringListRoundtrip(false);
82+
}
83+
84+
private void stringListRoundtrip(boolean shouldBeNull) throws Exception
85+
{
86+
List<String> list = asList("", "test", null, "test2");
87+
88+
// serialize to string
89+
String xml = MAPPER.writeValueAsString(list);
90+
assertNotNull(xml);
91+
92+
// then bring it back
93+
List<String> result = MAPPER.readValue(xml, new TypeReference<List<String>>() {});
94+
assertEquals(4, result.size());
95+
assertEquals("", result.get(0));
96+
assertEquals("test", result.get(1));
97+
if (shouldBeNull)
98+
{
99+
assertNull(result.get(2));
100+
} else
101+
{
102+
assertEquals("", result.get(2));
103+
}
104+
assertEquals("test2", result.get(3));
105+
}
106+
107+
@Test
108+
public void testStringMap() throws Exception
109+
{
110+
// default mode, should get back empty string
111+
MAPPER.disable(WRITE_NULLS_AS_XSI_NIL);
112+
MAPPER.enable(PROCESS_XSI_NIL);
113+
stringMapRoundtrip(false);
114+
115+
// xsi null enabled, should get back null
116+
MAPPER.enable(WRITE_NULLS_AS_XSI_NIL);
117+
MAPPER.enable(PROCESS_XSI_NIL);
118+
stringMapRoundtrip(true);
119+
120+
// xsi null write enabled but processing disabled, should get back empty string
121+
MAPPER.enable(WRITE_NULLS_AS_XSI_NIL);
122+
MAPPER.disable(PROCESS_XSI_NIL);
123+
stringMapRoundtrip(false);
124+
}
125+
126+
private void stringMapRoundtrip(boolean shouldBeNull) throws Exception
127+
{
128+
Map<String, String> map = new HashMap<String, String>() {{
129+
put("a", "");
130+
put("b", "test");
131+
put("c", null);
132+
put("d", "test2");
133+
}};
134+
MapPojo mapPojo = new MapPojo();
135+
mapPojo.setMap( map );
136+
137+
// serialize to string
138+
String xml = MAPPER.writeValueAsString(mapPojo);
139+
assertNotNull(xml);
140+
141+
// then bring it back
142+
MapPojo result = MAPPER.readValue(xml, MapPojo.class);
143+
assertEquals(4, result.map.size());
144+
assertEquals("", result.map.get("a"));
145+
assertEquals("test", result.map.get("b"));
146+
if (shouldBeNull)
147+
{
148+
assertNull(result.map.get("c"));
149+
} else
150+
{
151+
assertEquals("", result.map.get("c"));
152+
}
153+
assertEquals("test2", result.map.get("d"));
154+
}
155+
156+
private static class MapPojo {
157+
private Map<String, String> map;
158+
159+
public MapPojo() {
160+
}
161+
162+
public Map<String, String> getMap() {
163+
return map;
164+
}
165+
166+
public void setMap(Map<String, String> map) {
167+
this.map = map;
168+
}
169+
}
170+
}

0 commit comments

Comments
 (0)