Xstream个人觉得是一个挺简单的XML解析工具,使用一些注解就可以简单完成xml数据和java实体之间的转换。sxtream还支持对流的操作。这里只讲简单的字符串数据和实体之间的转换。
一、依赖
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.11.1</version>
</dependency>
二、一些常用的注解
这边只讲自己用到,比较熟悉的4个注解,后面如果有使用到其余的注解在补充
1、@XStreamAlias 用于实体类或者字段上,可以设置别名,相当于alias方法。
/**
* Annotation used to define an XStream class or field alias.
* @see com.thoughtworks.xstream.XStream#alias(String, Class)
* @see com.thoughtworks.xstream.XStream#alias(String, Class, Class)
* @see com.thoughtworks.xstream.XStream#addDefaultImplementation(Class, Class)
*/
2、@XStreamAsAttribute
把字段作为xml文件节点中的属性
3、@XStreamImplicit
可以去除节点中的集合或数组元素
4、@XStreamConverter
可以使用我们自定义的格式来转换,如date转为各种样式的string
三、使用
先简单建立一个班级-学生关系的类。
SchoolClass.java
@Data
public class SchoolClass {
private String className;
private String classMaster;
private Song song;
private List<Student> studentList;
}
Song.java
@Data
public class Song {
private String name;
private String author;
}
Student.java
@Data
public class Student {
private int id;
private String name;
private int age;
private Date birthDay;
}
1、类转字符串
这边赋值后转成xml
public class SchoolXmlTest {
public static void main(String[] args) {
beanToString();
}
public static void beanToString(){
SchoolClass class1 = new SchoolClass();
class1.setClassName("班级1");
class1.setClassMaster("班主任1");
Song classSong = new Song();
classSong.setName("班歌");
class1.setSong(classSong);
List<Student> students = new ArrayList<>();
class1.setStudentList(students);
Student student1 = new Student();
student1.setId(1);
student1.setName("学生1");
student1.setAge(19);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2000);
calendar.set(Calendar.MONTH, 0);
calendar.set(Calendar.DATE, 1);
student1.setBirthDay(calendar.getTime());
students.add(student1);
Student student2 = new Student();
student2.setId(2);
student2.setName("学生2");
student2.setAge(16);
students.add(student2);
XStream stream = new XStream();
String result = stream.toXML(class1);
System.out.println(result);
}
}
打印的结果如下,肯定不是我们想要的数据
<xml.SchoolClass>
<className>班级1</className>
<classMaster>班主任1</classMaster>
<song>
<name>班歌</name>
</song>
<studentList>
<xml.Student>
<id>1</id>
<name>学生1</name>
<age>17</age>
<birthDay>2000-01-01 03:07:42.300 UTC</birthDay>
</xml.Student>
<xml.Student>
<id>2</id>
<name>学生2</name>
<age>16</age>
</xml.Student>
</studentList>
</xml.SchoolClass>
改一下SchoolClass和Student的类
@Data
@XStreamAlias("class")
public class SchoolClass {
@XStreamAlias("class_name")
private String className;
private String classMaster;
private Song song;
@XStreamAlias("STUDENT")
// @XStreamImplicit
private List<Student> studentList;
}
@Data
@XStreamAlias("student")
public class Student {
@XStreamAsAttribute
private int id;
private String name;
private int age;
@XStreamConverter(DateConverter.class)
private Date birthDay;
}
我们想把Date按照我们想要的格式转为字符串,那就需要自定义一个转换的规则
当date作为节点时
public class DateConverter implements Converter {
/**
* bean转为xml
* @param source
* @param writer
* @param context
*/
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
Date date = (Date)source;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String time = format.format(date);
writer.setValue(time);
}
/**
* xml转成bean
* @param reader
* @param context
* @return
*/
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
if (StringUtils.isEmpty(reader.getValue())){
return null;
}
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
return format.parse(reader.getValue());
} catch (ParseException e) {
return null;
}
}
@Override
public boolean canConvert(Class type) {
return Date.class == type;
}
}
2、如果date字段作为属性,那么就要使用另外一种转换,并且要加上@XStreamAsAttribute注解
public class DateValueConverter implements SingleValueConverter {
@Override
public String toString(Object obj) {
Date date = (Date)obj;
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String time = format.format(date);
return time;
}
@Override
public Object fromString(String str) {
if (StringUtils.isEmpty(str)){
return null;
}
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
return format.parse(str);
} catch (ParseException e) {
return null;
}
}
@Override
public boolean canConvert(Class type) {
return Date.class == type;
}
}
转换方法处在改动一下
//new Xpp3Driver(new NoNameCoder())如果使用new XStream()构造,下划线_会变成__
XStream stream = new XStream(new Xpp3Driver(new NoNameCoder()));
//使用注解解析要设置为true
stream.autodetectAnnotations(true);
//@XStreamAlias相当于alias方法
// stream.alias("class", SchoolClass.class);
//有时候解析会在属性里出现class,<STUDENT class="singleton-list">,去除class
stream.aliasSystemAttribute(null,"class");
String result = stream.toXML(class1);
System.out.println(result);
结果如下
<class>
<class_name>班级1</class_name>
<classMaster>班主任1</classMaster>
<song>
<name>班歌</name>
</song>
<STUDENT>
<student id="1">
<name>学生1</name>
<age>17</age>
<birthDay>2000-01-01</birthDay>
</student>
</STUDENT>
</class>
@XStreamImplicit注解可以去除上面的STUDENT节点,可以根据实际情况使用。
2、字符串转实体类
public static void xmlToBean(){
String xml = "<class>\n" +
" <class_name>班级1</class_name>\n" +
" <classMaster>班主任1</classMaster>\n" +
" <song>\n" +
" <name>班歌</name>\n" +
" </song>\n" +
" <STUDENT>\n" +
" <student id=\"1\">\n" +
" <name>学生1</name>\n" +
" <age>17</age>\n" +
" </student>\n" +
" </STUDENT>\n" +
"</class>";
XStream xStream = new XStream();
xStream.autodetectAnnotations(true);
//设置要转换的类
xStream.processAnnotations(SchoolClass.class);
SchoolClass schoolClass = (SchoolClass) xStream.fromXML(xml);
System.out.println(schoolClass);
}
打印结果
Security framework of XStream not initialized, XStream is probably vulnerable.
SchoolClass(className=班级1, classMaster=班主任1, song=Song(name=班歌, author=null), studentList=[Student(id=1, name=学生1, age=17)])
控制台打印结果有个安全警告,我们可以通过下面的方式处理
XStream xStream = new XStream();
XStream.setupDefaultSecurity(xStream);
//自己实体类的路径
xStream.allowTypesByWildcard(new String[]{"xml.*"});
xStream.autodetectAnnotations(true);
xStream.processAnnotations(SchoolClass.class);
SchoolClass schoolClass = (SchoolClass) xStream.fromXML(xml);
System.out.println(schoolClass);
三、整理成工具类
把xml和实体之间的转换弄成一个工具类。
public class XmlUtils {
public static String beanToString(Object o){
XStream xStream = new XStream(new Xpp3Driver(new NoNameCoder()));
xStream.aliasSystemAttribute(null,"class");
xStream.autodetectAnnotations(true);
String result = xStream.toXML(o);
return result;
}
public static <T>T stringToClass(String xml, Class<T> clazz){
XStream xStream = new XStream();
XStream.setupDefaultSecurity(xStream);
//自己实体类的路径
xStream.allowTypesByWildcard(new String[]{"xml.*"});
xStream.autodetectAnnotations(true);
xStream.processAnnotations(clazz);
return clazz.cast(xStream.fromXML(xml));
}
}