摘要
前几天在开发一个功能的时候,需要用到Java bean 和 xml 格式字符串之间的互转工具。
这边介绍两个工具,XStream 和 jdk 自带的 JAXB 系列工具类。
XStream
例如有如下的一个Java bean
Student s1 = new Student();
s1.setName("john");
s1.setAge(21);
使用XStream进行转换时,你将得到如下的xml字符串
<com.test.mytest.Student>
<name>john</name>
<age>21</age>
</com.test.mytest.Student>
也许你注意到了,XStream 在将java bean转化为xml格式的字符串时,根节点会默认转化为全路径。这显然不合理,我们生成xml格式字符串,作为报文传给对方系统,显然使用全路径是不合理的。然后XStream提供了别名功能,可以使用别名。这里有两种方式可以指定别名,一种是代码形式,一种是注解形式。推荐使用注解形式。
- 代码形式
XStream xstream = new XStream();
// 将Student类使用类名作为别名
xstream.alias(Student.class.getSimpleName(), Student.class);
Student student = new Student();
student.setName("pli");
student.setAge(18);
String xmlStr = xstream.toXML(student);
System.out.println(xmlStr);
序列化之后
<Student>
<name>pli</name>
<age>18</age>
</Student>
也可以通过xstream.aliasField("NAME", String.class, "name");
来指定字段别名
- 注解形式
Student类
@XStreamAlias("PERSON")
public class Student {
@XStreamAlias("NAME")
private String name;
@XStreamAlias("AGE")
private int age;
}
主类方法
XStream xstream = new XStream();
// 设置自动处理全部注解,或处理指定注解,二选一即可
//xstream.autodetectAnnotations(true);
xstream.processAnnotations(Student.class);
Student student = new Student();
student.setName("pli");
student.setAge(18);
String xmlStr = xstream.toXML(student);
System.out.println(xmlStr);
序列化结果:
<PERSON>
<NAME>pli</NAME>
<AGE>18</AGE>
</PERSON>
- 为什么推荐使用注解形式?
我想你也注意到了,使用注解可以很方便的改变属性的名称格式。所以原因有如下
Java bean 的属性命名格式为驼峰形式,而xml的节点命名为全大写。这种情况下,要想所有的属性都能和xml报文对上,使用注解无疑更加合理。
例如:
XStream xstream = new XStream();
xstream.alias(Student.class.getSimpleName().toUpperCase(), Student.class);
String xmlStr2 = "<PERSON>\n" +
" <NAME>pli</NAME>\n" +
" <AGE>18</AGE>\n" +
"</PERSON>";
Student student1 = (Student) xstream.fromXML(xmlStr2);
System.out.println(student1.toString());
尽管指定了别名,但是对于大写的属性和类属性名称无法对应,执行报异常
此时,如果使用注解,就可以轻松完成字段的映射。
JAXB
JAXB 其实就是注解版的 XStream,JAXB提供了自己的一套注解,通过注解来完成 Java bean 和 xml 节点之间的映射。
JAXBContext context = JAXBContext.newInstance(Teacher.class);
Teacher teacher = new Teacher();
teacher.setName("pli");
teacher.setAge(18);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
StringWriter writer = new StringWriter();
marshaller.marshal(teacher, writer);
String jaxbStr = writer.toString();
System.out.println(jaxbStr);
Unmarshaller unmarshaller = context.createUnmarshaller();
Teacher t1 = (Teacher) unmarshaller.unmarshal(new StringReader(jaxbStr));
System.out.println(t1.toString());
输出结果如下:
总结
- 推荐使用JAXB作为转换工具
- 作为jdk原生的工具,JAXB 提供了更好的兼容性
- XStream 在反序列化时,有代码注入风险(具体没有验证过)
- JAXB 能自动添加和解析 xml 头部,省去了处理 xml 头部的功夫
- XStream 在使用时,一定要注意创建的实例。因为xstream的配置都是在实例上,如果重新创建了实例,那之前设置的属性都将失效。