xml序列化框架使用对比(Jaxb,XStream,Jackson)
一、Jaxb
1.1 介绍
JAXB(Java Architecture for XML Binding简称JAXB),为java自带的框架,允许Java开发人员将Java类映射为XML表示方式。JAXB提供两种主要特性:将一个Java对象序列化为XML,以及反向操作。
常用注解:
@XmlRootElement
:定义Xml根元素,序列化的根类必须有该注解@XmlElement
:将JavaBean属性映射到对应的xml元素@XmlAttribute
:将JavaBean属性映射到XML属性@XmlElementWrapper
:根据集合来产生包装元素。它必须与collection属性一起使用
@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
@XmlElementWrapper
@XmlElement(name="hobby")
List<String> hobbies;
}
生成的xml如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<hobbies>
<hobby>Swimming</hobby>
<hobby>basketball</hobby>
</hobbies>
</employee>
@XmlAccessorType
:使用Java类中的哪些字段或属性来生成xml。它有四个选项,默认是PUBLIC_MEMBER- NONE:除非使用某些JAXB注释专门对其进行注释,否则所有字段或属性均不会被映射
- FIELD:字段映射
- PROPERTY:getter/setter对映射
- PUBLIC_MEMBER:public的getter/setter对以及public字段映射
@XmlAccessorOrder
:控制类中字段和属性的顺序。有ALPHABETICAL(字母顺)和UNDEFINED(类中字段顺序)两个选择。只对字段映射生效@XmlTransient
:不做序列化@XmlJavaTypeAdapter
:用于自定义Xml和Java属性的转换器
1.2 使用方式
主要使用的类有JAXBContext,Marshaller,Unmarshaller。JAXBContext用于创建Marshaller,Unmarshaller。Marshaller用于序列化,Unmarshaller用于反序列化。
- 序列化
UserDO user = createUser();
JAXBContext jaxbContext = JAXBContext.newInstance(UserDO.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter sw = new StringWriter();
marshaller.marshal(user, sw);
String xml = sw.toString();
System.out.println(xml);
- 返序列化
JAXBContext jaxbContext = JAXBContext.newInstance(UserDO.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
UserDO unSerialUser = (UserDO) unmarshaller.unmarshal(new StringReader(xml));
System.out.println(unSerialUser);
1.3 总结
- 要序列化的根类必须加上@XmlRootElement注解(不加也有方法实现,但是很麻烦)
- JAXB默认序列化getter和setter,且必须成对出现才会被序列化。建议指定使用Field序列化方式
- 默认null值不会被序列化,如果需要序列化需要增加@XmlElement(nillable = true)
- 空标签
<age></age>
的返序列化:如果age为Integer类型,则反序列化后的age=0
;如果age是Long类型,则age=null
;如果age为String类型,则age=""
- JAXBContext是线程安全的,但Marshaller和Unmarshaller是非线程安全的,可以考虑池化
二、XStream
2.1 介绍
官网:http://x-stream.github.io/index.html
XStream是一个简单的基于Java的类库,用来将Java对象序列化成XML或反序列化为对象。XStream可以通过编程或注解的方式,进行xml的转换。
一个XStream实例在其生命周期中设想了两个阶段:
- 设置:当XStream实例被实例化时,很多默认的配置已经被应用,也就是说,实例处于设置阶段。现在是应用进一步配置的时候了。这个阶段不是线程安全的
- 执行:一旦实例被正确配置,就可以在执行阶段使用,执行阶段是线程安全的,也就是说,有可能同时使用一个XStream实例来执行。因此,在执行阶段之后不应该重新配置一个实例
XStream的结构由六个主要部件组成:
- Converters:转换器用于对象和xml互转,自定义转换器可以实现Converter接口,然后通过xStream.registerConverter方法进行注册
- Mappers:映射器用于xml名称和java名称之间的互转,可以覆盖XStream的wrapMapper函数,添加自定义映射器实现
- Drivers (Writer and Reader):底层对xml读写的驱动,避免将XStream捆绑在一个特定的库上
- Context:序列化或反序列化时,会创建Context,用于数据遍历,然后委托给Converter
- Type Permissions:安全框架的一部分。这些实现是用来拒绝或允许根据java类型的名称或类型层次来进行反序列化的
- Facade:XStream为门面类,通常作为入口点
常用注解
@XStreamAlias
:定义别名@XStreamAsAttribute
:把字段设置为属性@XStreamImplicit
:省略集合根节点,和JAXB的@XmlElementWrapper
相反@XStreamOmitField
:隐藏字段@XStreamConverter
:设置该字段使用自定义转换器
2.2 使用方式
- 引入依赖
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.20</version>
</dependency>
- 配置权限,设置最低权限,或者指定类(这种方式需要涉及到的所有类,如果用到了泛型,需要把实际类型也加进来)
XStream xStream = new XStream();
// 允许任何类型反序列化
xStream.addPermission(AnyTypePermission.ANY);
// 允许自定义类型反序列化(需要所有类)
xStream.allowTypes(new Class[]{UserDO.class, FavoriteDO.class});
- 序列化,使用编程方式
UserDO user = createUser();
XStream xStream = new XStream();
xStream.addPermission(AnyTypePermission.ANY);
// 定义别名,否则默认输出的根路径为类的全类名
xStream.alias("user", UserDO.class);
// aliasField修改java字段和xml字段属性映射
xStream.aliasField("username", UserDO.class, "name");
// 字段输出成xml的属性
xStream.useAttributeFor(UserDO.class, "name");
String xml = xStream.toXML(user);
- 反序列化,使用编程方式
XStream xStream = new XStream();
xStream.addPermission(AnyTypePermission.ANY);
xStream.alias("user", UserDO.class);
UserDO user = (UserDO)xStream.fromXML(xml);
System.out.println(user);
反序列化需要先用alias注册别名,因为fromXML没有类型参数,Xstream是通过xml的根节点识别哪个java类型
5. 序列化和反序列化,注解方式
XStream xStream = new XStream();
xStream.addPermission(AnyTypePermission.ANY);
// 相当于注册,否则直接反序列化不知道类型
xStream.processAnnotations(UserDO.class);
// 序列化
UserDO user = createUser();
String xml = xStream.toXML(user);
// 反序列化
UserDO user2 = (UserDO)xStream.fromXML(xml);
2.3 总结
- XStream使用的是字段映射
- XStream反序列化需要配置权限
- XStream可以通过编程方式,或注解方式,进行序列化和反序列化配置。但不管哪种方式,都需要预先注册类(编程方式要注册更多类,注解方式只用注册根类)
- 处理空标签时,比如
<age></age>
,默认是解析为""
,如果该类型定义的是Integer之类的,会直接报错 - 默认不认识的标签也会报错,需要配置:
xStream.ignoreUnknownElements();
- XStream在配置阶段是非线程安全,配置完成后执行时是线程安全的
- 从maven仓库上看XStream还存在很多漏洞
三、Jackson
3.1 介绍
官网:https://github.com/FasterXML/jackson-dataformat-xml
jackson的xml模块目标是模仿JAXB数据绑定在 "代码优先 "方法下的工作方式,全面支持往返。支持使用jackson的注解,或者使用JAXB的注解(需要引入额外的包)。可以通过编程的方式手动读写xml元素(相当于读写dom节点一样,用的比较少,就不介绍了)
常用注解:
@JacksonXmlRootElement
:定义Xml根元素,默认使用类的SimpleName@JacksonXmlProperty
:指定属性名称,以及属性是否被写成一个XML元素或属性@JacksonXmlElementWrapper
:允许指定用于包装List和Map属性的XML元素。类似JAXB的@XmlElementWrapper
@JacksonXmlCData
:允许指定一个属性的值被序列化在一个CData标签中
常用的配置属性:
SerializationFeature.INDENT_OUTPUT
:是否格式化输出,默认falseSerializationFeature.WRITE_DATES_AS_TIMESTAMPS
:日期写为时间戳,默认trueMapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES
:反序列化忽略大小写,默认falseDeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
:反序列化时,未知字段是否直接失败,默认true
3.2 使用方式
- 引入依赖
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.15.0</version>
</dependency>
- 序列化和反序列化
通过使用XmlMapper进行序列化和反序列化
UserDO user = createUser();
XmlMapper mapper = XmlMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.build();
String xml = mapper.writeValueAsString(user);
System.out.println(xml);
UserDO user2 = mapper.readValue(xml, UserDO.class);
System.out.println(user2);
3.3 总结
- jackson使用的getter/setter方法进行映射(需要成对出现),注解可以加在方法或者字段上,如果都加了会进行合并,但不能有冲突,推荐就加在字段上
- 处理空标签的结果比较人性化,比如
<age></age>
,如果定义的是String,则为""
;如果定义的是Integer,则为null
- 默认不认识的标签也会报错,需要配置:
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
- XmlMapper配置好之后,执行时是线程安全的
四、框架比较
框架 | Jaxb | XStream | Jackson |
---|---|---|---|
实现方式 | 基于注解 | 编程或注解 | 基于注解 |
映射方式 | 默认get/set方法映射,可以指定Field | 默认Field映射 | 默认get/set方法映射 |
线程安全性 | JAXBContext是线程安全的,但Marshaller和Unmarshaller是非线程安全的 | XStream配置完成后执行时是线程安全的 | XmlMapper配置完成后执行时是线程安全的 |
空标签的处理 | Integer会解析为0,Long会解析为null |
默认解析为"" ,字段定义为数值类型会报错,需要自己再实现自定义转换 |
会根据类型自动判断(Integer为null , String为"" ) |
安全性 | 不用设置权限 | 有很多漏洞未解决,使用上也必须设置权限,不友好 | 不用设置权限 |
易用性 | 一般 | 一般 | 高 |
五、参考
https://zhuanlan.zhihu.com/p/343893930?utm_id=0
https://zhuanlan.zhihu.com/p/145849932