[英]Jackson XML deserialization of abstract type results in fields with null values
When trying to deserialize XML to an object that extends an abstract base class, I'm seeing that the list of references contains the expected number of elements, but all the fields on those objects are null.当尝试将 XML 反序列化为扩展抽象基 class 的 object 时,我看到引用列表包含预期数量的元素,但这些对象上的所有字段都是 null。
This only happens if I create an XML reader for the abstract class. If I deserialize directly to the concrete implementation all the fields have the expected value.仅当我为抽象 class 创建一个 XML 读取器时才会发生这种情况。如果我直接反序列化为具体实现,则所有字段都具有预期值。
I've added the minimum working example below我在下面添加了最低限度的工作示例
Expected output (as json for readability)预期为 output(作为 json 以提高可读性)
{
"References": [ { "id": "1", "Type": "Secondary Image" } ]
}
Actual output (as json for readability)实际 output(作为 json 以提高可读性)
{
"References": [ { "id": null, "Type": null } ]
}
Test Data测试数据
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Foo TypeID="ConcreteA">
<Reference ID="1" Type="Secondary Image">
<Values/>
</Reference>
</Foo>
Abstract base class摘要基地 class
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "TypeID", visible = true)
@JsonSubTypes({
@JsonSubTypes.Type(value = ConcreteClassA.class, name = "ConcreteA")
})
public abstract class AbstractBase {
@JacksonXmlProperty(localName = "TypeID", isAttribute = true)
private String typeId;
@JsonIgnore
private List<Reference> references = new ArrayList<>();
@JacksonXmlElementWrapper(useWrapping = false)
@JacksonXmlProperty(localName = "Reference")
public List<Reference> getReferences() {
return references;
}
@JsonSetter
public AbstractBase setReferences(List<Reference> references) {
this.references.addAll(references);
return this;
}
}
Concrete Implementation具体实施
public class ConcreteClassA extends AbstractBase {}
Test Cases测试用例
public class DeserializationTest {
@Test
public void deserializedAbstractClass_fieldsShouldNotBeNull() throws JsonProcessingException {
var mapper = new XmlMapper()
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
.deactivateDefaultTyping()
.registerModule(new JacksonXmlModule());
var xmlData = readTestData();
var reader = mapper.readerFor(AbstractBase.class);
var deserializedObject = reader.readValue(xmlData);
assert(deserializedObject instanceof ConcreteClassA);
var concreteClassA = (ConcreteClassA) deserializedObject;
assert(concreteClassA.getReferences().get(0).getId() != null);
}
@Test
public void deserializedConcreteClass_fieldsShouldNotBeNull() throws JsonProcessingException {
var mapper = new XmlMapper()
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
.configure(MapperFeature.USE_BASE_TYPE_AS_DEFAULT_IMPL, true)
.registerModule(new JacksonXmlModule());
var xmlData = readTestData();
var reader = mapper.readerFor(ConcreteClassA.class);
var deserializedObject = reader.readValue(xmlData);
assert(deserializedObject instanceof ConcreteClassA);
var concreteClassA = (ConcreteClassA) deserializedObject;
assert(concreteClassA.getReferences().get(0).getId() != null);
}
private String readTestData() {
try {
var datafile = getClass().getClassLoader().getResource("TestData.xml");
return Files.lines(Paths.get(datafile.toURI())).collect(Collectors.joining());
} catch (Exception e) { return ""; }
}
}
Turns out there are multiple problems, that I've managed to solve.事实证明,我已经设法解决了多个问题。
This problem was solved by upgrading to 2.12, which means that it's no longer necessary to do this to handle unwrapped elements.此问题已通过升级到 2.12 得到解决,这意味着不再需要执行此操作来处理展开的元素。
I solved this by having the setter accept a single element, and then adding that to the list我通过让 setter 接受单个元素,然后将其添加到列表中来解决这个问题
@JsonSetter(value = "Reference")
public AbstractBase setReferences(Reference reference) {
this.references.add(references);
return this;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.