【问题标题】:Jackson XML deserialization of abstract type results in fields with null values抽象类型的 Jackson XML 反序列化导致具有空值的字段
【发布时间】:2021-02-18 08:04:43
【问题描述】:

当尝试将 XML 反序列化为扩展抽象基类的对象时,我看到引用列表包含预期数量的元素,但这些对象上的所有字段均为空。

仅当我为抽象类创建 XML 阅读器时才会发生这种情况。如果我直接反序列化到具体实现,所有字段都具有预期值。

我在下面添加了最小的工作示例

预期输出(为便于阅读的 json)

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

实际输出(为便于阅读的 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>

抽象基类

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

【问题讨论】:

    标签: java jackson jackson-dataformat-xml


    【解决方案1】:

    原来有多个问题,我已经设法解决了。

    1. 我使用的 Jackson 版本 (2.11) 在多个元素使用相同标签时存在一些问题,而不是在包装器中。这是我所知道的,也是我的设置器执行“addAll”而不是设置列表的原因

    升级到 2.12 解决了这个问题,这意味着不再需要这样做来处理展开的元素。

    1. Jackson 未能正确反序列化这些项目,因为 setter 接受了一个列表,该列表显然是由于一些 java 泛型 mumbo jumbo 而中断(我一直无法弄清楚原因,只是它发生了)。

    我通过让 setter 接受单个元素,然后将其添加到列表中解决了这个问题

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

    【讨论】:

      猜你喜欢
      • 2017-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-10
      • 2019-10-21
      • 1970-01-01
      相关资源
      最近更新 更多