Skip to content

Commit 1bfa168

Browse files
authored
Fix #608: support text-node-only cases (#826)
1 parent fe21fa4 commit 1bfa168

3 files changed

Lines changed: 56 additions & 28 deletions

File tree

release-notes/VERSION

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ Version: 3.x (for earlier see VERSION-2.x)
6262
deserialization to base class
6363
(reported by @tetradon)
6464
(fix by @cowtowncoder, w/ Claude code)
65+
#608: Jackson fails to instantiate class when only text node is present
66+
(reported by @codemonstur)
67+
(fix by @cowtowncoder, w/ Claude code)
6568
#615: Deserialization of Xml with `@JacksonXmlText` using `@JsonCreator` (into
6669
`java.util.Map`) fails
6770
(reported by Severin K)

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

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,11 @@ protected ValueDeserializer<?> _modifyBeanDeserializer(DeserializationConfig con
113113
// coercion.
114114
// 30-Apr-2020, tatu: Complication from [dataformat-xml#318] as we now
115115
// have a delegate too...
116+
// [dataformat-xml#608]: relaxed from earlier check that required all
117+
// non-text properties to be attributes; now handles beans with
118+
// @JacksonXmlText alongside other element properties too.
116119
if (!inst.canCreateFromString()) {
117-
SettableBeanProperty textProp = _findSoleTextProp(config, deser.properties());
120+
SettableBeanProperty textProp = _findTextProp(deser.properties());
118121
if (textProp != null) {
119122
return new XmlTextDeserializer(deser, textProp);
120123
}
@@ -142,31 +145,22 @@ protected ValueDeserializer<?> _modifyThroughDelegation(DeserializationConfig co
142145
return deser;
143146
}
144147

145-
private SettableBeanProperty _findSoleTextProp(DeserializationConfig config,
146-
Iterator<SettableBeanProperty> propIt)
148+
/**
149+
* Find the {@code @JacksonXmlText} property (renamed to {@code _cfgNameForTextValue}
150+
* by {@link #updateProperties}) if one exists.
151+
*<p>
152+
* NOTE: before [dataformat-xml#608] fix, this method also required all non-text
153+
* properties to be attributes; relaxed to allow element properties too.
154+
*/
155+
private SettableBeanProperty _findTextProp(Iterator<SettableBeanProperty> propIt)
147156
{
148-
final AnnotationIntrospector ai = config.getAnnotationIntrospector();
149-
SettableBeanProperty textProp = null;
150157
while (propIt.hasNext()) {
151158
SettableBeanProperty prop = propIt.next();
152-
AnnotatedMember m = prop.getMember();
153-
if (m != null) {
154-
// Ok, let's use a simple check: we should have renamed it earlier so:
155-
PropertyName n = prop.getFullName();
156-
if (_cfgNameForTextValue.equals(n.getSimpleName())) {
157-
// should we verify we only got one?
158-
textProp = prop;
159-
continue;
160-
}
161-
// as-attribute are ok as well
162-
Boolean b = AnnotationUtil.findIsAttributeAnnotation(config, ai, m);
163-
if (b != null && b.booleanValue()) {
164-
continue;
165-
}
159+
PropertyName n = prop.getFullName();
160+
if (_cfgNameForTextValue.equals(n.getSimpleName())) {
161+
return prop;
166162
}
167-
// Otherwise, it's something else; no go
168-
return null;
169163
}
170-
return textProp;
164+
return null;
171165
}
172166
}

src/test/java/tools/jackson/dataformat/xml/tofix/XmlTextOnlyDeser608Test.java renamed to src/test/java/tools/jackson/dataformat/xml/deser/XmlTextOnlyDeser608Test.java

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
package tools.jackson.dataformat.xml.tofix;
1+
package tools.jackson.dataformat.xml.deser;
22

33
import org.junit.jupiter.api.Test;
44

55
import tools.jackson.databind.ObjectMapper;
66
import tools.jackson.dataformat.xml.XmlTestUtil;
77
import tools.jackson.dataformat.xml.annotation.JacksonXmlProperty;
88
import tools.jackson.dataformat.xml.annotation.JacksonXmlText;
9-
import tools.jackson.dataformat.xml.testutil.failure.JacksonTestFailureExpected;
109

1110
import static org.junit.jupiter.api.Assertions.assertEquals;
1211
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -39,6 +38,18 @@ static class Plain608 {
3938
public String text;
4039
}
4140

41+
// Has @JacksonXmlText with mix of attributes and element properties
42+
static class Mixed608 {
43+
@JacksonXmlProperty(isAttribute = true)
44+
public String attr;
45+
46+
@JacksonXmlProperty(isAttribute = false)
47+
public String elem;
48+
49+
@JacksonXmlText
50+
public String text;
51+
}
52+
4253
private final ObjectMapper MAPPER = newMapper();
4354

4455
// Works: nested has both a child element and text content
@@ -62,10 +73,8 @@ public void testPlainTextOnly608() throws Exception {
6273
assertEquals("The text node.", result.plain.text);
6374
}
6475

65-
// Fails: nested type has @JacksonXmlText plus other element properties,
66-
// but XML only contains text (no child elements). Jackson incorrectly
67-
// tries String-argument constructor instead of object deserialization.
68-
@JacksonTestFailureExpected
76+
// [dataformat-xml#608]: nested type has @JacksonXmlText plus other element
77+
// properties, but XML only contains text (no child elements).
6978
@Test
7079
public void testNestedWithOnlyText608() throws Exception {
7180
String xml = "<Root608><nested>The text node.</nested></Root608>";
@@ -75,4 +84,26 @@ public void testNestedWithOnlyText608() throws Exception {
7584
assertNull(result.nested.reallyNotHere);
7685
assertEquals("The text node.", result.nested.text);
7786
}
87+
88+
// [dataformat-xml#608]: mixed attributes + elements + text, text-only XML
89+
@Test
90+
public void testMixedTextOnly608() throws Exception {
91+
String xml = "<Mixed608>The text node.</Mixed608>";
92+
Mixed608 result = MAPPER.readValue(xml, Mixed608.class);
93+
assertNotNull(result);
94+
assertNull(result.attr);
95+
assertNull(result.elem);
96+
assertEquals("The text node.", result.text);
97+
}
98+
99+
// [dataformat-xml#608]: mixed attributes + elements + text, with attribute present
100+
@Test
101+
public void testMixedWithAttrAndText608() throws Exception {
102+
String xml = "<Mixed608 attr=\"v\">The text node.</Mixed608>";
103+
Mixed608 result = MAPPER.readValue(xml, Mixed608.class);
104+
assertNotNull(result);
105+
assertEquals("v", result.attr);
106+
assertNull(result.elem);
107+
assertEquals("The text node.", result.text);
108+
}
78109
}

0 commit comments

Comments
 (0)