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

Spring & Jackson环境下JSON列表转自定义格式XML的实现问题

你当前使用的@JacksonXmlElementWrapper(useWrapping = false)只能移除address列表的外层包裹标签,无法避免每个地址元素生成<address>父标签,也无法自动为streetName、city字段拼接序号后缀,因此无法实现预期的输出格式。

推荐两种可行实现方案:

方案一:使用@JsonAnyGetter实现(更简便)

通过@JsonAnyGetter注解动态生成带序号的平级字段,无需自定义序列化器:

  1. 定义Address实体类
public class Address {
    private String streetName;
    private String city;
    // 构造方法、getter、setter自行实现
}
  1. 定义根节点实体类
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Root {
    private String name;
    private List<Address> address;

    public String getName() {
        return name;
    }

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

    // 序列化时忽略原始address字段,避免生成多余的<address>标签
    @JsonIgnore
    public List<Address> getAddress() {
        return address;
    }

    public void setAddress(List<Address> address) {
        this.address = address;
    }

    // 动态返回所有带序号的地址字段,序列化时会直接作为根节点的子标签输出
    @JsonAnyGetter
    public Map<String, String> getDynamicAddressFields() {
        Map<String, String> fields = new HashMap<>();
        for (int i = 0; i < address.size(); i++) {
            int index = i + 1;
            Address addr = address.get(i);
            fields.put("streetName" + index, addr.getStreetName());
            fields.put("city" + index, addr.getCity());
        }
        return fields;
    }
}

方案二:自定义序列化器实现

如果需要更灵活的序列化逻辑,可以为根节点自定义序列化器:

  1. 定义序列化器类
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import java.util.List;

public class RootXmlSerializer extends StdSerializer<Root> {
    public RootXmlSerializer() {
        super(Root.class);
    }

    @Override
    public void serialize(Root root, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        // 写入name字段
        gen.writeStringField("name", root.getName());
        // 遍历地址列表生成带序号的字段
        List<Address> addresses = root.getAddress();
        for (int i = 0; i < addresses.size(); i++) {
            int index = i + 1;
            Address addr = addresses.get(i);
            gen.writeStringField("streetName" + index, addr.getStreetName());
            gen.writeStringField("city" + index, addr.getCity());
        }
        gen.writeEndObject();
    }
}
  1. 给Root类绑定序列化器
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.util.List;

@JsonSerialize(using = RootXmlSerializer.class)
public class Root {
    private String name;
    private List<Address> address;
    // 构造方法、getter、setter自行实现
}

测试代码

两种方案都可以用以下代码验证输出:

import com.fasterxml.jackson.dataformat.xml.XmlMapper;

public class XmlConvertTest {
    public static void main(String[] args) throws Exception {
        // 模拟解析JSON得到的对象
        Address addr1 = new Address("value1", "value2");
        Address addr2 = new Address("value3", "value4");
        Root root = new Root();
        root.setName("Edward");
        root.setAddress(List.of(addr1, addr2));

        XmlMapper xmlMapper = new XmlMapper();
        // 格式化输出XML
        String xmlResult = xmlMapper.writerWithDefaultPrettyPrinter().writeValueAsString(root);
        System.out.println(xmlResult);
    }
}

输出结果和要求的目标格式完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 14:39:00