jackson-dataformat-xml
jackson-dataformat-xml copied to clipboard
A @JsonUnwrapped with a @JacksonXmlElementWrapper(useWrapping=false) on a collection fails reading from XML, but not JSON
I have originally created this issue in jackson-databind ( https://github.com/FasterXML/jackson-databind/issues/2073 ) ... but realised only now that I should have created the issue here.
Versions Version Used: 2.9.5 Woodstox Core Used: 5.1.0 Note that I also used Lombok bellow, but only for using the Getter and Setter annotations. Replacing them with the usual boiler plate hand-written getterXXX() and setterXXX() yields the same result.
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.14</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
Summary: It seems that when you have a collection ( e.g. List ) annotated with JacksonXmlElementWrapper(useWrapping=false) in a bean which itself was annotated with JsonUnwrapped, unmarshalled / reading from XML fails with an exception.
Note that it is NOT an issue when reading from JSON, only from XML.
Example Take the following example ( imports removed for brevity ):
@XmlRootElement
@Getter @Setter
public class Request {
@XmlElement
@JsonUnwrapped
private Composite composite = new Composite();
}
@XmlType
@Getter @Setter
public class Composite {
@XmlElement
private String messageId;
@XmlElement
private Integer number;
@JacksonXmlElementWrapper(useWrapping=false)
@XmlElement
private List<Header> headers = new ArrayList<>();
}
@XmlType
@Getter @Setter
public class Header {
@XmlElement
private String headerId;
}
Unit Test
public class RequestTest {
@Test
public void testXmlMarshallingAndUnmarshalling() throws Exception {
final ObjectMapper mapper = new XmlMapper();
testMarshallingAndUnmarshalling(mapper);
}
@Test
public void testJsonMarshallingAndUnmarshalling() throws Exception {
final ObjectMapper mapper = new ObjectMapper();
testMarshallingAndUnmarshalling(mapper);
}
private void testMarshallingAndUnmarshalling(ObjectMapper mapper) throws Exception {
mapper.enable(SerializationFeature.INDENT_OUTPUT);
final Request request = new Request();
request.getComposite().setMessageId("ABC");
request.getComposite().setNumber(123);
final Header header1 = new Header();
header1.setHeaderId("headerID1");
final Header header2 = new Header();
header2.setHeaderId("headerID2");
request.getComposite().getHeaders().add(header1);
request.getComposite().getHeaders().add(header2);
String xmlString = mapper.writeValueAsString(request);
System.out.println(xmlString);
final Request anotherRequest = mapper.readValue(xmlString, Request.class);
Assert.assertEquals(request.getComposite().getMessageId(), anotherRequest.getComposite().getMessageId());
Assert.assertEquals(request.getComposite().getNumber(), anotherRequest.getComposite().getNumber());
Assert.assertEquals("ABC", anotherRequest.getComposite().getMessageId());
Assert.assertEquals(new Integer(123), anotherRequest.getComposite().getNumber());
Assert.assertEquals(2, anotherRequest.getComposite().getHeaders().size());
Assert.assertEquals("headerID1", anotherRequest.getComposite().getHeaders().get(0).getHeaderId());
Assert.assertEquals("headerID2", anotherRequest.getComposite().getHeaders().get(1).getHeaderId());
}
}
... which writes to and reads from XML and JSON.
- Writing to JSON works. Reading the JSON that was just written also works.
- Writing to XML works, Reading from XML that was just written fails.
It seems to think that the property from the unwrapped Composite should be a property on the Request.
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running RequestTest
{
"messageId" : "ABC",
"number" : 123,
"headers" : [ {
"headerId" : "headerID1"
}, {
"headerId" : "headerID2"
} ]
}
<Request>
<messageId>ABC</messageId>
<number>123</number>
<headers>
<headerId>headerID1</headerId>
</headers>
<headers>
<headerId>headerID2</headerId>
</headers>
</Request>
Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.475 sec <<< FAILURE!
testXmlMarshallingAndUnmarshalling(RequestTest) Time elapsed: 0.13 sec <<< ERROR!
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "messageId" (class Request), not marked as ignorable (one known property: "composite"])
at [Source: (StringReader); line: 2, column: 29] (through reference chain: Request["messageId"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:822)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1152)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1582)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1560)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:294)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)
at RequestTest.testMarshallingAndUnmarshalling(RequestTest.java:44)
at RequestTest.testXmlMarshallingAndUnmarshalling(RequestTest.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Results :
Tests in error:
testXmlMarshallingAndUnmarshalling(RequestTest): Unrecognized field "messageId" (class Request), not marked as ignorable (one known property: "composite"])(..)
Tests run: 2, Failures: 0, Errors: 1, Skipped: 0
+1