这是我的 XML:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<licenseSummary>
<dependencies>
<dependency>
<groupId>Hello World 1</groupId>
</dependency>
<dependency>
<groupId>Hello World 2</groupId>
</dependency>
</dependencies>
</licenseSummary>
这是我的模型:
@Getter
@Setter
@JacksonXmlRootElement(localName = "licenseSummary")
@EqualsAndHashCode
public class LicenseSummary {
@NonNull
@JacksonXmlProperty(localName = "dependency")
@JacksonXmlElementWrapper(localName = "dependencies")
List<Dependency> dependencies;
@JsonCreator
public LicenseSummary(@NonNull List<Dependency> dependencies) {
this.dependencies = dependencies;
}
}
@Getter
@Setter
@EqualsAndHashCode
public class Dependency {
@NonNull
@JacksonXmlProperty(localName = "groupId")
private String groupId;
@JsonCreator
public Dependency(@NonNull String groupId) {
this.groupId = groupId;
}
}
当我尝试将上述 XML 反序列化到模型 POJO 中时,出现以下错误:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.util.ArrayList<de.symate.maven.plugins.licenseaggregator.model.Dependency>` from Object value (token `JsonToken.FIELD_NAME`)
at [Source: (BufferedInputStream); line: 3, column: 3]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1767)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1541)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1488)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.handleNonArray(CollectionDeserializer.java:402)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:254)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:30)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1490)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:348)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185)
at com.fasterxml.jackson.dataformat.xml.deser.XmlDeserializationContext.readRootValue(XmlDeserializationContext.java:104)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4917)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3897)
at de.symate.maven.plugins.licenseaggregator.model.LicenseSummaryTest.xmlDeserializationWorks(LicenseSummaryTest.java:30)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
有人可以帮助我吗?
有趣的是,当我创建模型类的 POJO 并使用完全相同的映射器对其进行序列化时,上面发布的 XML 就是结果。但尝试反序列化它不起作用:(
据我了解https://github.com/FasterXML/jackson-dataformat-xml/issues/517,问题出在注释
@JacksonXmlElementWrapper
中,构造函数参数没有正确支持该注释(特别是如果您想要使用包装元素反序列化集合结构)
<items>
<item></item>
<item></item>
</items>
这就是我可以使用的解决方案。 Jackson 正常工作所需的默认构造函数可以设置为受保护,因此它不会被暴露,并且没有人可以滥用它来创建浅对象。
@Getter
@Setter
@JacksonXmlRootElement(localName = "licenseSummary")
@EqualsAndHashCode
public class LicenseSummary {
@NonNull
@JacksonXmlProperty(localName = "dependency")
@JacksonXmlElementWrapper(localName = "dependencies")
List<Dependency> dependencies;
public LicenseSummary(@NonNull List<Dependency> dependencies) {
this.dependencies = dependencies;
}
/**
* Protected no-args constructor for Jackson, because @JacksonXmlElementWrapper does not work properly on constructor arguments.
*/
@JsonCreator
protected LicenseSummary() {}
}
@Getter
@Setter
@EqualsAndHashCode
public class Dependency {
@NonNull
@JacksonXmlProperty(localName = "groupId")
private String groupId;
@JsonCreator
public Dependency(@JacksonXmlProperty(localName = "groupId") @NonNull String groupId) {
this.groupId = groupId;
}
}