使用jackson将xml和对象、List相互转换

文章目录


Jackson Xml

Jackson 是一个广泛使用的 JSON 处理库,但在处理 XML 数据时,Jackson 也提供了相应的支持。虽然 Jackson 的主要用途是处理 JSON 数据,但通过在pom.xml中引入jackson-dataformat-xml 模块,可以很方便地将 Java 对象序列化为 XML 文档或将 XML 文档反序列化为 Java 对象。

常用注解

  • @JacksonXmlRootElement:定义Xml根元素,默认使用类的SimpleName
  • @JacksonXmlProperty:指定属性名称,以及属性是否被写成一个XML元素或属性
  • @JacksonXmlElementWrapper:允许指定用于包装List和Map属性的XML元素。类似JAXB的@XmlElementWrapper
  • @JacksonXmlCData:允许指定一个属性的值被序列化在一个CData标签中

常用的配置属性

  • SerializationFeature.INDENT_OUTPUT:是否格式化输出,默认false
  • SerializationFeature.WRITE_DATES_AS_TIMESTAMPS:日期写为时间戳,默认true
  • MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES:反序列化忽略大小写,默认false
  • DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES:反序列化时,未知字段是否直接失败,默认true

相关依赖

xml 复制代码
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

jackson工具类

java 复制代码
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;

import java.io.IOException;

/**
 * @author qf
 * @since 2024/09/11 19:04
 */
public class JacksonXmlUtil {
    private static class SingletonHolder {
        private static XmlMapper xmlMapper = new XmlMapper();
        static {
            // 在构造器中进行配置
            //反序列化的时候如果多了其他属性,不抛出异常
            xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        }
    }

    public static XmlMapper getXmlSingleton() {
        XmlMapper mapper = SingletonHolder.xmlMapper;
        return mapper;
    }

    /**
     * 对象转xml
     *
     * @param obj
     * @return
     * @throws JsonProcessingException
     */
    public static String toXml(Object obj) throws JsonProcessingException {
        ObjectMapper mapper = getXmlSingleton();
        return mapper.writeValueAsString(obj);
    }


    /**
     * xml转为对象
     *
     * @param xml
     * @param clazz
     * @param <T>
     * @return
     * @throws IOException
     */
    public static <T> T toXmlObject(String xml, Class<T> clazz) throws IOException {
        XmlMapper mapper = getXmlSingleton();
        return mapper.readValue(xml, clazz);
    }
}

xml和对象相互转换

xml数据

xml 复制代码
<root>
    <id>1001</id>
    <name>test</name>
    <node>
        <test1>test1</test1>
        <test2>test2</test2>
    </node>
</root>

实体类

java 复制代码
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;

import java.util.List;

/**
 * @author qf
 * @since 2024/09/11 19:06
 */
@Data
@JacksonXmlRootElement(localName = "root")
public class XmlDataBo {

    @JacksonXmlProperty(localName = "id")
    private Long id;

    @JacksonXmlProperty(localName = "name")
    private String name;

    @JacksonXmlProperty(localName = "node")
    private XmlDataTestBo testBo;
}
java 复制代码
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;

/**
 * @author qf
 * @since 2024/09/10 19:42
 */
@Data
@JacksonXmlRootElement(localName = "node")
public class XmlDataTestBo {
    @JacksonXmlProperty(localName = "test1")
    private String Test1;
    @JacksonXmlProperty(localName = "test2")
    private String Test2;
}

xml转为对象

java 复制代码
    public static void main(String[] args) throws IOException {
        String xmlStr = "<root><id>1001</id><name>test</name><node><test1>test1</test1><test2>test2</test2></node></root>";
//        XmlDataBo xmlBo = JacksonXmlUtil.toXmlObject(xmlStr, XmlDataBo.class);
        XmlMapper xmlMapper = new XmlMapper();
        xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        XmlDataBo xmlBo = xmlMapper.readValue(xmlStr, XmlDataBo.class);
    }

输出

txt 复制代码
XmlDataBo(id=1001, name=test, testBo=XmlDataTestBo(Test1=test1, Test2=test2))

对象转为xml

java 复制代码
        XmlDataTestBo testBo = new XmlDataTestBo();
        testBo.setTest1("test1");
        testBo.setTest2("test2");
        XmlDataBo xmlDataBo = new XmlDataBo();
        xmlDataBo.setId(1001L);
        xmlDataBo.setName("test");
        xmlDataBo.setTestBo(testBo);
        String xml = JacksonXmlUtil.toXml(xmlDataBo);
        System.out.println(xml);
txt 复制代码
<root><id>1001</id><name>test</name><node><test2>test2</test2><test1>test1</test1></node></root>

xml和List相互转换

xml数据

java 复制代码
<root>
    <id>1001</id>
    <name>test</name>
    <node>
        <info>
            <name>zs</name>
            <age>18</age>
            <sex>男</sex>
         </info>
         <info>
            <name>ls</name>
            <age>19</age>
            <sex>女</sex>
         </info>
    </node>
</root>

实体类

根标签 < root >

java 复制代码
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;

/**
 * @author qbh
 * @since 2024/09/10 19:25
 */
@Data
@JacksonXmlRootElement(localName = "root")
public class XmlDataBo {

    @JacksonXmlProperty(localName = "id")
    private Long id;

    @JacksonXmlProperty(localName = "name")
    private String name;

    @JacksonXmlProperty(localName = "node")
    private XmlDataTestBo testBo;

}

node标签< node >

java 复制代码
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;

import java.util.List;

/**
 * @author qf
 * @since 2024/09/10 18:42
 */
@Data
@JacksonXmlRootElement(localName = "node")
public class XmlDataTestBo {
//    @JacksonXmlProperty(localName = "test1")
//    private String Test1;
//    @JacksonXmlProperty(localName = "test2")
//    private String Test2;

    /**
     * JacksonXmlElementWrapper注解用于指定列表或数组属性在XML中的包装元素,以提供更好的结构化层次和语义意义。
     *  当useWrapping = true:列表或数组会被包裹在一个额外的元素中。
     *  当useWrapping = false:列表或数组不会被包裹在额外的元素中。
     */
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "info")
    private List<XmlDataInfoBo> infoBos;
}

info标签 < info >

java 复制代码
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.lang.ref.PhantomReference;

/**
 * @author qf
 * @since 2024/09/10 19:27
 */
@NoArgsConstructor
@AllArgsConstructor
@Data
@JacksonXmlRootElement(localName = "info")
public class XmlDataInfoBo {

    @JacksonXmlProperty(localName = "name")
    private String name;

    @JacksonXmlProperty(localName = "age")
    private Integer age;

    @JacksonXmlProperty(localName = "sex")
    private String sex;
}

List转xml

java 复制代码
        XmlDataBo xmlDataBo = new XmlDataBo();
        xmlDataBo.setId(1001L);
        xmlDataBo.setName("test");
        List<XmlDataInfoBo> infoBos = new ArrayList<>();
        infoBos.add(new XmlDataInfoBo("zs", 18, "男"));
        infoBos.add(new XmlDataInfoBo("ls", 19, "女"));
        XmlDataTestBo testBo = new XmlDataTestBo();
        testBo.setInfoBos(infoBos);
        xmlDataBo.setTestBo(testBo);
        String xml = JacksonXmlUtil.toXml(xmlDataBo);
        System.out.println(xml);

输出

java 复制代码
<root><id>1001</id><name>test</name><node><info><name>zs</name><age>18</age><sex>男</sex></info><info><name>ls</name><age>19</age><sex>女</sex></info></node></root>

xml转List

方法1

java 复制代码
        String xmlStr = "<root><id>1001</id><name>test</name><node><info><name>zs</name><age>18</age><sex>男</sex></info><info><name>ls</name><age>19</age><sex>女</sex></info></node></root>";
        XmlDataBo xmlDataBo = JacksonXmlUtil.toXmlObject(xmlStr, XmlDataBo.class);
        System.out.println(xmlDataBo);

输出

txt 复制代码
XmlDataBo(id=1001, name=test, testBo=XmlDataTestBo(infoBos=[XmlDataInfoBo(name=zs, age=18, sex=男), XmlDataInfoBo(name=ls, age=19, sex=女)]))

方法2

也可以直接从node标签中拿取列表(跳过node标签直接拿列表info)

修改root实体类

java 复制代码
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;

import java.util.List;

/**
 * @author qbh
 * @since 2024/09/10 17:25
 */
@Data
@JacksonXmlRootElement(localName = "root")
public class XmlDataBo {

    @JacksonXmlProperty(localName = "id")
    private Long id;

    @JacksonXmlProperty(localName = "name")
    private String name;

//    @JacksonXmlProperty(localName = "node")
//    private XmlDataTestBo testBo;

    @JacksonXmlElementWrapper(useWrapping = true )
    @JacksonXmlProperty(localName = "node")
    private List<XmlDataInfoBo> infoBos;

}

测试

java 复制代码
    public static void main(String[] args) throws IOException {
        String xmlStr = "<root><id>1001</id><name>test</name><node><info><name>zs</name><age>18</age><sex>男</sex></info><info><name>ls</name><age>19</age><sex>女</sex></info></node></root>";
        XmlDataBo xmlDataBo = JacksonXmlUtil.toXmlObject(xmlStr, XmlDataBo.class);
        System.out.println(xmlDataBo);
    }

输出

txt 复制代码
XmlDataBo(id=1001, name=test, infoBos=[XmlDataInfoBo(name=zs, age=18, sex=男), XmlDataInfoBo(name=ls, age=19, sex=女)])

@JacksonXmlElementWrapper 的 useWrapping 参数区别

@JacksonXmlElementWrapper 注解用于指定列表或数组属性在 XML 中的包装元素。useWrapping 参数控制是否使用额外的包装元素来包裹列表或数组。

  1. useWrapping = true (默认)
    当 useWrapping = true 时,表示列表或数组被包裹在一个额外的元素中。例如以上代码中:
xml 复制代码
<root>
    <node>
        <info>
            <name>zs</name>
            <age>18</age>
            <sex>男</sex>
         </info>
         <info>
            <name>ls</name>
            <age>19</age>
            <sex>女</sex>
         </info>
    </node>
</root>

在这个例子中,info标签被包裹在node标签中。

所以在取值时代码:

java 复制代码
    @JacksonXmlElementWrapper(useWrapping = true )
    @JacksonXmlProperty(localName = "node")
    private List<XmlDataInfoBo> infoBos;
  1. useWrapping = false
    当 useWrapping = false 时,表示列表或数组没有被包裹在额外的元素中。例如以上代码中:
xml 复制代码
<root>
     <info>
         <name>zs</name>
         <age>18</age>
         <sex>男</sex>
      </info>
      <info>
         <name>ls</name>
         <age>19</age>
         <sex>女</sex>
      </info>
</root>

所以在取值时代码:

java 复制代码
    @JacksonXmlElementWrapper(useWrapping = false)
    @JacksonXmlProperty(localName = "info")
    private List<XmlDataInfoBo> infoBos;

总结

当列表或数组会被包裹在一个额外的元素中或想直接从父标签拿子标签列表时,选择useWrapping = true。

列表或数组没有被包裹在额外的元素中时,选择useWrapping = false。


相关推荐
monkey_meng16 分钟前
【Rust类型驱动开发 Type Driven Development】
开发语言·后端·rust
落落落sss25 分钟前
MQ集群
java·服务器·开发语言·后端·elasticsearch·adb·ruby
我救我自己25 分钟前
UE5运行时创建slate窗口
java·服务器·ue5
2401_853275731 小时前
ArrayList 源码分析
java·开发语言
爪哇学长1 小时前
SQL 注入详解:原理、危害与防范措施
xml·java·数据库·sql·oracle
大鲤余1 小时前
Rust,删除cargo安装的可执行文件
开发语言·后端·rust
她说彩礼65万1 小时前
Asp.NET Core Mvc中一个视图怎么设置多个强数据类型
后端·asp.net·mvc
MoFe11 小时前
【.net core】【sqlsugar】字符串拼接+内容去重
java·开发语言·.netcore
陈随易1 小时前
农村程序员-关于小孩教育的思考
前端·后端·程序员
_江南一点雨1 小时前
SpringBoot 3.3.5 试用CRaC,启动速度提升3到10倍
java·spring boot·后端