Skip to content

Commit dbd1fe5

Browse files
committed
Fix #318
1 parent 3eadc65 commit dbd1fe5

File tree

10 files changed

+99
-52
lines changed

10 files changed

+99
-52
lines changed

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<parent>
55
<groupId>com.fasterxml.jackson</groupId>
66
<artifactId>jackson-base</artifactId>
7-
<version>2.11.1-SNAPSHOT</version>
7+
<version>2.12.0-SNAPSHOT</version>
88
</parent>
99
<groupId>com.fasterxml.jackson.dataformat</groupId>
1010
<artifactId>jackson-dataformat-xml</artifactId>

release-notes/CREDITS-2.x

+4
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,7 @@ Luke Korth ([email protected])
6060

6161
* Reported #366: XML containing xsi:nil is improperly parsed
6262
(2.10.2)
63+
64+
Jochen Schalanda (joschi@github)
65+
* Repoerted #318: XMLMapper fails to deserialize null (POJO reference) from blank tag
66+
(2.12.0)

release-notes/VERSION-2.x

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ Project: jackson-dataformat-xml
44
= Releases
55
------------------------------------------------------------------------
66

7+
2.12.0 (not yet released)
8+
9+
#318: XMLMapper fails to deserialize null (POJO reference) from blank tag
10+
(reported by Jochen S)
11+
712
2.11.1 (not yet released)
813

914
-

src/main/java/com/fasterxml/jackson/dataformat/xml/JacksonXmlModule.java

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.fasterxml.jackson.databind.module.SimpleModule;
55
import com.fasterxml.jackson.dataformat.xml.deser.FromXmlParser;
66
import com.fasterxml.jackson.dataformat.xml.deser.XmlBeanDeserializerModifier;
7+
import com.fasterxml.jackson.dataformat.xml.deser.XmlBeanInstantiator;
78
import com.fasterxml.jackson.dataformat.xml.deser.XmlStringDeserializer;
89
import com.fasterxml.jackson.dataformat.xml.ser.XmlBeanSerializerModifier;
910

@@ -65,6 +66,9 @@ public void setupModule(SetupContext context)
6566
// as well as AnnotationIntrospector
6667
context.insertAnnotationIntrospector(_constructIntrospector());
6768

69+
// 2.11 adds ValueInstantiator, too
70+
context.addValueInstantiators(new XmlBeanInstantiator.Provider());
71+
6872
// and finally inform XmlFactory about overrides, if need be:
6973
if (_cfgNameForTextElement != FromXmlParser.DEFAULT_UNNAMED_TEXT_PROPERTY) {
7074
XmlMapper m = (XmlMapper) context.getOwner();

src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlBeanDeserializerModifier.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,11 @@ public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
9696
ValueInstantiator inst = deser.getValueInstantiator();
9797
// 03-Aug-2017, tatu: [dataformat-xml#254] suggests we also should
9898
// allow passing `int`/`Integer`/`long`/`Long` cases, BUT
99-
// unfortunately we can not simple use default handling. Would need
99+
// unfortunately we can not simply use default handling. Would need
100100
// coercion.
101-
if (!inst.canCreateFromString()) {
101+
// 30-Apr-2020, tatu: Complication from [dataformat-xml#318] as we now
102+
// have a delegate too...
103+
if ((inst instanceof XmlBeanInstantiator) || !inst.canCreateFromString()) {
102104
SettableBeanProperty textProp = _findSoleTextProp(config, deser.properties());
103105
if (textProp != null) {
104106
return new XmlTextDeserializer(deser, textProp);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.fasterxml.jackson.dataformat.xml.deser;
2+
3+
import java.io.IOException;
4+
5+
import com.fasterxml.jackson.databind.*;
6+
import com.fasterxml.jackson.databind.deser.ValueInstantiator;
7+
import com.fasterxml.jackson.databind.deser.ValueInstantiators;
8+
import com.fasterxml.jackson.databind.deser.std.StdValueInstantiator;
9+
10+
/**
11+
* {@link ValueInstantiator} implementation needed mostly to support
12+
* creating "empty" instance (or {@code null}) of POJOs from String
13+
* value consisting of all whitespace -- something that happens with
14+
* indentation.
15+
*
16+
* @since 2.12
17+
*/
18+
public class XmlBeanInstantiator
19+
extends ValueInstantiator.Delegating
20+
implements java.io.Serializable
21+
{
22+
private static final long serialVersionUID = 1L;
23+
24+
protected final JavaType _type;
25+
26+
protected final boolean _canCreateDefault;
27+
28+
public XmlBeanInstantiator(JavaType type, ValueInstantiator base) {
29+
super(base);
30+
_type = type;
31+
_canCreateDefault = base.canCreateUsingDefault();
32+
}
33+
34+
@Override
35+
public boolean canInstantiate() { return true; }
36+
37+
@Override
38+
public boolean canCreateFromString() {
39+
return true;
40+
}
41+
42+
@Override
43+
public Object createFromString(DeserializationContext ctxt, String value)
44+
throws IOException
45+
{
46+
if (_canCreateDefault) {
47+
if (value.isEmpty() || value.trim().isEmpty()) {
48+
return delegate().createUsingDefault(ctxt);
49+
}
50+
// Should we try to give more meaningful error otherwise?
51+
}
52+
return delegate().createFromString(ctxt, value);
53+
}
54+
55+
public static class Provider extends ValueInstantiators.Base
56+
implements java.io.Serializable
57+
{
58+
private static final long serialVersionUID = 1L;
59+
60+
@Override
61+
public ValueInstantiator findValueInstantiator(DeserializationConfig config,
62+
BeanDescription beanDesc, ValueInstantiator defaultInstantiator)
63+
{
64+
// let's avoid custom ones?
65+
if (defaultInstantiator instanceof StdValueInstantiator) {
66+
return new XmlBeanInstantiator(beanDesc.getType(), defaultInstantiator);
67+
}
68+
return defaultInstantiator;
69+
}
70+
}
71+
}

src/test/java/com/fasterxml/jackson/dataformat/xml/failing/EmptyBeanDeser318Test.java renamed to src/test/java/com/fasterxml/jackson/dataformat/xml/deser/EmptyBeanDeser318Test.java

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
package com.fasterxml.jackson.dataformat.xml.failing;
1+
package com.fasterxml.jackson.dataformat.xml.deser;
22

3-
import com.fasterxml.jackson.databind.DeserializationFeature;
43
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
54
import com.fasterxml.jackson.dataformat.xml.XmlTestBase;
65
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
@@ -43,7 +42,8 @@ public void testEmptyString() throws Exception {
4342

4443
Wrapper value = MAPPER.readValue(s, Wrapper.class);
4544
assertEquals("id", value.id);
46-
assertNull(value.nested);
45+
assertNotNull(value.nested);
46+
assertNull(value.nested.nested2);
4747
}
4848

4949
public void testBlankString() throws Exception {
@@ -57,7 +57,8 @@ public void testBlankString() throws Exception {
5757
// Cannot construct instance of `JacksonXMLTest$Nested` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value (' ')
5858
Wrapper value = MAPPER.readValue(s, Wrapper.class);
5959
assertEquals("id", value.id);
60-
assertNull(value.nested);
60+
assertNotNull(value.nested);
61+
assertNull(value.nested.nested2);
6162
}
6263

6364
public void testBlankString2() throws Exception {
@@ -66,14 +67,11 @@ public void testBlankString2() throws Exception {
6667
+ " <nested> </nested>"
6768
+ "</wrapper>";
6869

69-
// This fails with the following exception:
70-
// com.fasterxml.jackson.databind.exc.MismatchedInputException:
71-
// Cannot construct instance of `JacksonXMLTest$Nested` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value (' ')
7270
Wrapper value = MAPPER.readerFor(Wrapper.class)
73-
.with(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)
7471
.readValue(s);
7572
assertEquals("id", value.id);
76-
assertNull(value.nested);
73+
assertNotNull(value.nested);
74+
assertNull(value.nested.nested2);
7775
}
7876

7977
public void testMissing() throws Exception {

src/test/java/com/fasterxml/jackson/dataformat/xml/failing/EmptyListDeser124Test.java

-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import java.util.List;
55

66
import com.fasterxml.jackson.annotation.JsonProperty;
7-
import com.fasterxml.jackson.annotation.JsonSetter;
8-
import com.fasterxml.jackson.annotation.Nulls;
97
import com.fasterxml.jackson.dataformat.xml.*;
108

119
// for [dataformat-xml#124]

src/test/java/com/fasterxml/jackson/dataformat/xml/lists/Issue101UnwrappedListAttributesTest.java

+2-37
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,7 @@
1010
// Failing unit test(s) wrt [Issue#64]
1111
public class Issue101UnwrappedListAttributesTest extends XmlTestBase
1212
{
13-
static class Optional {
14-
@JacksonXmlText
15-
public String number = "NOT SET";
16-
17-
@JacksonXmlProperty(isAttribute=true)
18-
public String type = "NOT SET";
19-
20-
public Optional() { }
21-
22-
// uncommenting this ALSO works:
23-
// public Optional(String n) { number = n; }
24-
}
25-
26-
static class Optionals {
27-
@JacksonXmlElementWrapper(useWrapping = false)
28-
public List<Optional> optional;
29-
}
30-
31-
// For [Issue#101]
13+
// For [dataformat-xml#101]
3214
@JacksonXmlRootElement(localName = "root")
3315
@JsonPropertyOrder({ "unwrapped", "name" })
3416
static class Root {
@@ -62,24 +44,7 @@ public UnwrappedElement (String id, String type) {
6244

6345
private final XmlMapper MAPPER = new XmlMapper();
6446

65-
// // [Issue#64]
66-
public void testOptionalsWithMissingType() throws Exception
67-
{
68-
// Optionals ob = MAPPER.readValue("<MultiOptional><optional type='work'>123-456-7890</optional></MultiOptional>",
69-
Optionals ob = MAPPER.readValue("<MultiOptional><optional>123-456-7890</optional></MultiOptional>",
70-
Optionals.class);
71-
assertNotNull(ob);
72-
assertNotNull(ob.optional);
73-
assertEquals(1, ob.optional.size());
74-
75-
// System.err.println("ob: " + ob); // works fine
76-
77-
Optional opt = ob.optional.get(0);
78-
assertEquals("123-456-7890", opt.number);
79-
assertEquals("NOT SET", opt.type);
80-
}
81-
82-
// [Issue#101]
47+
// [dataformat-xml#101]
8348
public void testWithTwoAttributes() throws Exception
8449
{
8550
final String EXP = "<root>"

src/test/java/com/fasterxml/jackson/dataformat/xml/lists/UnwrappedListsTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ static class DefaultList {
3838
public Value[] value;
3939
}
4040

41-
// [Issue#64]
41+
// [dataformat-xml#64]
4242
static class Optionals {
4343
@JacksonXmlElementWrapper(useWrapping = false)
4444
public List<Optional> optional;

0 commit comments

Comments
 (0)