Skip to content

Commit 6c37f48

Browse files
committed
Fixed #442 (missing START_OBJECT for leading "mixed text")
1 parent 43a0881 commit 6c37f48

File tree

3 files changed

+56
-25
lines changed

3 files changed

+56
-25
lines changed

release-notes/VERSION-2.x

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ Project: jackson-dataformat-xml
66

77
2.13.0 (not yet released)
88

9-
No changes since 2.12
9+
#442: Missing `START_OBJECT` token in complex element starting with text
10+
(reported by richardsonwk@github)
1011

1112
2.12.3 (not yet released)
1213

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

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ private Feature(boolean defaultState) {
153153
*/
154154
protected boolean _closed;
155155

156-
final protected IOContext _ioContext;
156+
protected final IOContext _ioContext;
157157

158158
/*
159159
/**********************************************************
@@ -179,6 +179,16 @@ private Feature(boolean defaultState) {
179179

180180
protected String _currText;
181181

182+
/**
183+
* Additional flag that is strictly needed when exposing "mixed" leading
184+
* String value as "anonymous" property/string pair. If so, code returns
185+
* START_OBJECT first, sets {@code _nextToken} to be {@code FIELD_NAME}
186+
* and sets this flag to indicate use of "anonymous" marker.
187+
*
188+
* @since 2.13
189+
*/
190+
protected boolean _nextIsLeadingMixed;
191+
182192
/*
183193
/**********************************************************
184194
/* Parsing state, parsed values
@@ -668,7 +678,15 @@ public JsonToken nextToken() throws IOException
668678
_parsingContext = _parsingContext.getParent();
669679
break;
670680
case FIELD_NAME:
671-
_parsingContext.setCurrentName(_xmlTokens.getLocalName());
681+
// 29-Mar-2021, tatu: [dataformat-xml#442]: special case of leading
682+
// mixed text added
683+
if (_nextIsLeadingMixed) {
684+
_nextIsLeadingMixed = false;
685+
_parsingContext.setCurrentName(_cfgNameForTextElement);
686+
_nextToken = JsonToken.VALUE_STRING;
687+
} else {
688+
_parsingContext.setCurrentName(_xmlTokens.getLocalName());
689+
}
672690
break;
673691
default: // VALUE_STRING, VALUE_NULL
674692
// 13-May-2020, tatu: [dataformat-xml#397]: advance `index` anyway; not
@@ -756,7 +774,7 @@ public JsonToken nextToken() throws IOException
756774
_currText = _xmlTokens.getText();
757775
if (_mayBeLeaf) {
758776
_mayBeLeaf = false;
759-
// One more refinement (pronunced like "hack") is that if
777+
// One more refinement (pronounced like "hack") is that if
760778
// we had an empty String (or all white space), and we are
761779
// deserializing an array, we better hide the empty text.
762780
// Also: must skip following END_ELEMENT
@@ -792,7 +810,14 @@ public JsonToken nextToken() throws IOException
792810
// but... [dataformat-xml#191]: looks like we can't short-cut, must
793811
// loop over again
794812
if (_parsingContext.inObject()) {
795-
if ((_currToken != JsonToken.FIELD_NAME) && XmlTokenStream._allWs(_currText)) {
813+
if (_currToken == JsonToken.FIELD_NAME) {
814+
// 29-Mar-2021, tatu: [dataformat-xml#442]: need special handling for
815+
// leading mixed content; requires 3-token sequence for which _nextToken
816+
// along is not enough.
817+
_nextIsLeadingMixed = true;
818+
_nextToken = JsonToken.FIELD_NAME;
819+
return (_currToken = JsonToken.START_OBJECT);
820+
} else if (XmlTokenStream._allWs(_currText)) {
796821
token = _nextToken();
797822
continue;
798823
}
@@ -802,6 +827,11 @@ public JsonToken nextToken() throws IOException
802827
token = _nextToken();
803828
continue;
804829
}
830+
// 29-Mar-2021, tatu: This seems like an error condition...
831+
// How should we indicate it? As of 2.13, report as unexpected state
832+
throw _constructError(
833+
"Unexpected non-whitespace text ('"+_currText+"' in Array context: should not occur (or should be handled)"
834+
);
805835
}
806836

807837
// If not a leaf (or otherwise ignorable), need to transform into property...

src/test/java/com/fasterxml/jackson/dataformat/xml/failing/XmlParser442Test.java renamed to src/test/java/com/fasterxml/jackson/dataformat/xml/stream/XmlParser442Test.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.fasterxml.jackson.dataformat.xml.failing;
1+
package com.fasterxml.jackson.dataformat.xml.stream;
22

33
import com.fasterxml.jackson.core.JsonToken;
44

@@ -11,26 +11,26 @@ public class XmlParser442Test extends XmlTestBase
1111
private final XmlMapper MAPPER = newMapper();
1212

1313
// For [dataformat-xml#442]
14-
public void testMixedContentAfter() throws Exception
14+
public void testMixedContentBeforeElement442() throws Exception
1515
{
16-
try (FromXmlParser xp = (FromXmlParser) MAPPER.createParser(
17-
"<root>\n" // START_OBJECT
18-
+" <branch>\n" // *Missing* START_OBJECT
19-
+" text\n"
20-
+" <leaf>stuff</leaf>\n"
21-
+" </branch>\n" // END_OBJECT
22-
+"</root>\n" // END_OBJECT
23-
24-
/*
25-
"<SomeXml>\n" // START_OBJECT
26-
+" <ParentElement>\n" // *Missing* START_OBJECT
27-
+" text\n"
28-
+" <ChildElement someAttribute=\"value\"/>\n" // START_OBJECT/END_OBJECT
29-
+" further text\n"
30-
+" </ParentElement>\n" // END_OBJECT
31-
+"</SomeXml>\n" // END_OBJECT
32-
*/
33-
)) {
16+
final String XML =
17+
"<root>\n" // START_OBJECT
18+
+" <branch>\n" // *Missing* START_OBJECT
19+
+" text\n"
20+
+" <leaf>stuff</leaf>\n"
21+
+" </branch>\n" // END_OBJECT
22+
+"</root>\n" // END_OBJECT
23+
;
24+
25+
// Should get equivalent of:
26+
//
27+
// { "branch" : {
28+
// "" : " text ",
29+
// "leaf" : "stuff"
30+
// }
31+
// }
32+
33+
try (FromXmlParser xp = (FromXmlParser) MAPPER.createParser(XML)) {
3434
assertToken(JsonToken.START_OBJECT, xp.nextToken());
3535
assertToken(JsonToken.FIELD_NAME, xp.nextToken());
3636
assertEquals("branch", xp.currentName());

0 commit comments

Comments
 (0)