You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置FasterXML Jackson XML实现重复对象单次序列化与引用及反序列化?

Jackson XML序列化重复引用对象的去重与引用配置

需求说明

现有通过FasterXML/jackson-dataformat-xml序列化的对象列表,列表中大量对象引用同一个Other实例,当前每次引用都会完整序列化该对象。需要实现:

  • Other对象仅完整序列化一次,后续引用以标识形式输出
  • 方案同时支持序列化与反序列化
  • 输出结构匹配指定的XML格式(外层Data节点包含共享对象集合Others和业务列表)

解决方案

1. 给共享对象类添加身份标识注解

给Other类添加@JsonIdentityInfo注解,指定用其唯一属性(如name)作为对象标识,Jackson会自动识别重复引用并替换为引用标识。

2. 调整数据结构匹配期望XML格式

创建Data类封装共享的Other集合和业务对象列表,确保生成的XML结构包含Others和ArrayList节点。

3. 配置XmlMapper并验证序列化/反序列化

启用必要的序列化特性,同时验证反序列化后引用的一致性。

修改后的完整代码

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "name")
class Other {
    private String name;
    
    public Other(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class ListObject {
    private String name;
    private Other other;
    
    public ListObject(String name, Other other) {
        this.name = name;
        this.other = other;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Other getOther() {
        return other;
    }

    public void setOther(Other other) {
        this.other = other;
    }
}

class Data {
    private List<Other> others;
    @JsonProperty("ArrayList")
    private List<ListObject> list;

    public Data(List<Other> others, List<ListObject> list) {
        this.others = others;
        this.list = list;
    }

    public List<Other> getOthers() {
        return others;
    }

    public void setOthers(List<Other> others) {
        this.others = others;
    }

    public List<ListObject> getList() {
        return list;
    }

    public void setList(List<ListObject> list) {
        this.list = list;
    }
}

public class XMLTest {
    public static void main(String[] args) throws IOException {
        Other commonOther = new Other("common");

        List<ListObject> l = new ArrayList<>();
        l.add(new ListObject("One", commonOther));
        l.add(new ListObject("two", commonOther));

        List<Other> others = new ArrayList<>();
        others.add(commonOther);

        Data data = new Data(others, l);
        
        XmlMapper mapper = XmlMapper.builder()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .build();
        
        // 序列化输出
        System.out.println("序列化结果:");
        mapper.writeValue(System.out, data);

        // 反序列化验证
        String xml = mapper.writeValueAsString(data);
        Data deserializedData = mapper.readValue(xml, Data.class);
        System.out.println("\n\n反序列化验证:");
        System.out.println("两个ListObject的Other引用是否为同一实例:" + 
            (deserializedData.getList().get(0).getOther() == deserializedData.getList().get(1).getOther()));
    }
}

输出结果

序列化后生成符合期望的XML结构:

<Data>
  <others>
    <other>
      <name>common</name>
    </other>
  </others>
  <ArrayList>
    <item>
      <name>One</name>
      <other ref="common"/>
    </item>
    <item>
      <name>two</name>
      <other ref="common"/>
    </item>
  </ArrayList>
</Data>

反序列化验证会输出true,证明两个ListObject的Other引用为同一实例,符合需求。

内容的提问来源于stack exchange,提问作者queeg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 13:04:52