Jackson xml反序列化 - 序列化为一个列表,其中包含任意元素

Posted

技术标签:

【中文标题】Jackson xml反序列化 - 序列化为一个列表,其中包含任意元素【英文标题】:Jackson xml deserialization - serialize to a list with arbitrary elements in between 【发布时间】:2020-11-14 19:26:51 【问题描述】:

我正在使用 Jackson 来反序列化 XML。当中间没有其他元素时,它在序列化到列表中时工作正常,但是如果我在中间的某个地方插入一些其他字段,它似乎只会将字段下方的内容放入我的列表中。请参见下面仅包含 Product B 标记之后的 ProductA 对象。

我使用xmlMapper readTree方法设置断点获取JsonNode对象,而ProductB标签上面的属性在节点树中是没有的。

有没有办法使用 jackson(或其他库)来获取 Warehouse 元素中的所有 ProductA 元素,而与 Warehouse 子元素的顺序无关?

public class Warehouse 
@JacksonXmlElementWrapper(useWrapping = false)
@JacksonXmlProperty(localName = "ProductA")
private List<ProductA> productAList;

@JacksonXmlProperty(localName = "ProductB")
private String productB;
//getters and setters


public class ProductA 
@JacksonXmlProperty(localName = "PropA")
private String propA;

//getters and setters

<Warehouse>
 <ProductA>
  <propA>abc</propA>
 </ProductA>
 <ProductA>
  <propA>abc</propA>
 </ProductA>
 <ProductB>def</ProductB>
 <ProductA>
  <propA>abc</propA>
 </ProductA>
</Warehouse>

【问题讨论】:

【参考方案1】:

更改您的 Warehouse 类以使用仅用于从 XML 设置 productAList 值的方法,并从 productAList 属性中删除注释。

@JsonSetter(value =  "ProductA")
public void setProductAListFromXml(ProductA productA) 
    if (this.productAList == null) 
        this.productAList = new ArrayList<ProductA>();
     
    this.productAList.add(productA);

这是完整的 Warehouse 类:

@JacksonXmlRootElement(localName = "Warehouse")
public class Warehouse 
    private List<ProductA> productAList;

    @JacksonXmlProperty(localName = "ProductB")
    private String productB;

    public List<ProductA> getProductAList() 
        return productAList;
    

    public void setProductAList(List<ProductA> productAList) 
        this.productAList = productAList;
    

    @JsonSetter(value =  "ProductA")
    public void setProductAListFromXml(ProductA productA) 
        if (this.productAList == null) 
            this.productAList = new ArrayList<ProductA>();
         
        this.productAList.add(productA);
    
    
    public String getProductB() 
        return productB;
    
    
    public List<ProductA> getProductA() 
        return productAList;
    

像这样使用类:

String str = "<Warehouse>\r\n" + 
                " <ProductA>\r\n" + 
                "  <propA>abc</propA>\r\n" + 
                " </ProductA>\r\n" + 
                " <ProductA>\r\n" + 
                "  <propA>abc</propA>\r\n" + 
                " </ProductA>\r\n" + 
                " <ProductB>def</ProductB>\r\n" + 
                " <ProductA>\r\n" + 
                "  <propA>abc</propA>\r\n" + 
                " </ProductA>\r\n" + 
                "</Warehouse>";
        
XmlMapper mapper = new XmlMapper();
Warehouse warehouse = mapper.readValue(str, Warehouse.class);
System.out.println(warehouse.getProductB());
System.out.println(warehouse.getProductA());

产生这个输出:

def
[ProductA [propA=abc], ProductA [propA=abc], ProductA [propA=abc]]

【讨论】:

这适用于其中一个领域,但奇怪的是不适用于另一个领域。假设我有 productC,它与 productA 除了名称之外的所有内容都相同,作为仓库类的一个字段。它正在反序列化所有 productA 元素,但仅反序列化 2 个 productC 中的 1 个。无论如何,我能够使用 w3c/javax 文档解析获得所需的内容。

以上是关于Jackson xml反序列化 - 序列化为一个列表,其中包含任意元素的主要内容,如果未能解决你的问题,请参考以下文章

漏洞通告Jackson框架反序列化漏洞通告

Jackson 反序列化同名的 xml 字段

Jackson xml反序列化不连续的内联数组

Jackson学习

将子XML元素反序列化为XML字符串

Jackson 将日期字符串反序列化为 Long