Xstream個人覺得是一個挺簡單的XML解析工具,使用一些註解就可以簡單完成xml數據和java實體之間的轉換。sxtream還支持對流的操作。這裏只講簡單的字符串數據和實體之間的轉換。
一、依賴
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.11.1</version>
</dependency>
二、一些常用的註解
這邊只講自己用到,比較熟悉的3個註解,後面如果有使用到其餘的註解在補充
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按照我們想要的格式轉爲字符串,那就需要自定義一個轉換的規則
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));
}
}