簡體   English   中英

Jackson XML 抽象類型的反序列化導致具有 null 值的字段

[英]Jackson XML deserialization of abstract type results in fields with null values

當嘗試將 XML 反序列化為擴展抽象基 class 的 object 時,我看到引用列表包含預期數量的元素,但這些對象上的所有字段都是 null。

僅當我為抽象 class 創建一個 XML 讀取器時才會發生這種情況。如果我直接反序列化為具體實現,則所有字段都具有預期值。

我在下面添加了最低限度的工作示例

預期為 output(作為 json 以提高可讀性)

{
 "References": [ { "id": "1", "Type": "Secondary Image" } ]
}

實際 output(作為 json 以提高可讀性)

{
  "References": [ { "id": null, "Type": null } ]
}

測試數據

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Foo TypeID="ConcreteA">
    <Reference ID="1" Type="Secondary Image">
        <Values/>
    </Reference>
</Foo>

摘要基地 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;
    }
}

具體實施

public class ConcreteClassA extends AbstractBase {}

測試用例

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 ""; }
    }
}

事實證明,我已經設法解決了多個問題。

  1. 我使用的 Jackson 版本 (2.11) 在使用相同標簽的多個元素方面存在一些問題,而不是在包裝器中。 這是我所知道的,也是我的設置器執行“addAll”而不只是設置列表的原因

此問題已通過升級到 2.12 得到解決,這意味着不再需要執行此操作來處理展開的元素。

  1. Jackson 未能正確反序列化項目,因為設置器接受了一個列表,該列表顯然由於一些 java 通用的胡言亂語而中斷(我一直無法弄清楚為什么,只是它發生了)。

我通過讓 setter 接受單個元素,然后將其添加到列表中來解決這個問題

@JsonSetter(value = "Reference")
public AbstractBase setReferences(Reference reference) {
    this.references.add(references);
    return this;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM