XStream是基于OXMapping技术,在xml和java对象之间序列化和反序列化的一个库,使用简单,对java对象要求少,没有共有私有或者构造方法上的要求,还支持json转化;
使用XStream需要maven引用:
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.18</version>
</dependency>
使用JettisonMappedXmlDriver处理json需要maven引用:
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.4.1</version>
</dependency>
Demo1不使用注解:
/**
* 2021年8月25日下午3:34:50
*/
package testXStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.json.JsonWriter;
import com.thoughtworks.xstream.io.xml.Dom4JDriver;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.StaxDriver;
import com.thoughtworks.xstream.persistence.FilePersistenceStrategy;
import com.thoughtworks.xstream.persistence.PersistenceStrategy;
import com.thoughtworks.xstream.persistence.XmlArrayList;
import com.thoughtworks.xstream.persistence.XmlMap;
import com.thoughtworks.xstream.persistence.XmlSet;
import com.thoughtworks.xstream.security.AnyTypePermission;
/**
* @author XWF
*
*/
public class TestXStream1 {
public static int i = 1;
@BeforeEach
public void before() {
System.out.println(String.format("--------------%d--------------", i++));
}
@AfterEach
public void after() {
System.out.println();
}
@Test
public void test1() {
Student stu1 = new Student(1, "Jack", 21);
Student stu2 = new Student(2, "Tom", 22);
School sch = new School();
sch.schoolName = "HelloSchool";
sch.students.add(stu1);
sch.students.add(stu2);
// XStream x = new XStream(new Dom4JDriver());
// XStream x = new XStream(new DomDriver());
// XStream x = new XStream(new StaxDriver());
XStream x = new XStream();//默认XppDriver
String str = x.toXML(sch);//obj转xml
System.out.println(str);
x.alias("SCHOOL", School.class);//给类起别名
x.aliasPackage("X", "testXStream");//给包起别名
x.aliasField("StuName", Student.class, "name");//给字段起别名
// x.useAttributeFor(Student.class, "id");//将字段设置为属性
x.aliasAttribute(Student.class, "id", "ID");//设置属性并起别名
x.omitField(Student.class, "age");//忽略字段
x.ignoreUnknownElements();//忽略未知元素
String str2 = x.toXML(sch);
System.out.println(str2);
x.addPermission(AnyTypePermission.ANY);//设置许可,移除ForbiddenClassException异常
School newSchool = (School) x.fromXML(str2);//xml转obj
System.out.println(newSchool);
}
@Test
public void test2() {
Student stu1 = new Student(3, "Marry", 17);
Student stu2 = new Student(4, "Jerry", 16);
School sch = new School();
sch.schoolName = "MySchool";
sch.students.add(stu1);
sch.students.add(stu2);
XStream x = new XStream();
System.out.println(x.toXML(sch));
// x.alias("STU", Student.class);
x.addImplicitCollection(School.class, "students", "NEWstudent", Student.class);//将集合的根节点隐藏
String str = x.toXML(sch);
System.out.println(str);
x.addPermission(AnyTypePermission.ANY);
System.out.println(x.fromXML(str));
}
@Test
public void test3() {
Student stu = new Student(5, "Jack", 20);
XStream x = new XStream(new JettisonMappedXmlDriver());//序列化、反序列化json,需要引入jettison依赖
// XStream x = new XStream(new JsonHierarchicalStreamDriver());//只能序列化json
x.setMode(XStream.NO_REFERENCES);//禁用引用
x.alias("STUDENT", Student.class);
String str = x.toXML(stu);
System.out.println(str);
x.addPermission(AnyTypePermission.ANY);
Student newStu = (Student) x.fromXML(str);
System.out.println(newStu);
}
@Test
public void test4() {
Student stu = new Student(6, "John", 18);
XStream x = new XStream(new JsonHierarchicalStreamDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new JsonWriter(out, JsonWriter.DROP_ROOT_MODE);//去掉根节点
}
});
String str = x.toXML(stu);
System.out.println(str);
// x.addPermission(AnyTypePermission.ANY);
// Student newStu = (Student) x.fromXML(str);//无根节点无法反序列化,也不需使用JettisonMappedXmlDriver
// System.out.println(newStu);
}
@Test
public void test5() {
Student stu = new Student(7, "Bill", 25);
XStream x = new XStream();
x.registerConverter(new MyConverter());//注册自定义转换器
String str = x.toXML(stu);
System.out.println(str);
x.addPermission(AnyTypePermission.ANY);
System.out.println(x.fromXML(str));
}
@Test
public void test6() {
Student stu = new Student(8, "James", 24);
XStream x = new XStream();
//默认根节点object-stream,也可以通过createObjectOutputStream第二个参数设置
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = x.createObjectOutputStream(bos)) {
oos.writeObject(stu);
oos.writeBoolean(true);
oos.writeInt(100);
} catch (IOException e) {
e.printStackTrace();
}
byte[] byteArray = bos.toByteArray();
System.out.println(new String(byteArray));
String str = "<root>"
+ "<STU><id>9</id><name>Mark</name><age>16</age></STU>"
+ "<boolean>false</boolean>"
+ "</root>";
try (ObjectInputStream ois = x.createObjectInputStream(new StringReader(str))) {
x.alias("STU", Student.class);
x.addPermission(AnyTypePermission.ANY);
Student readStu = (Student) ois.readObject();
System.out.println(readStu);
boolean b = ois.readBoolean();
System.out.println(b);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Test
public void test7() {
XStream x = new XStream();
File baseDirectory = new File("./src/testXStream/list/");
if (!baseDirectory.exists()) {
baseDirectory.mkdir();
}
PersistenceStrategy strategy = new FilePersistenceStrategy(baseDirectory, x);
//写到xml文件里
//(XmlArrayList,XmlMap,XmlSet不要写到同一个文件夹下,否则读取的时候it.hasNext永远为true并且后面的it.next为null)
System.out.println("XmlArrayList");
XmlArrayList list = new XmlArrayList(strategy);
list.add(new Student(10, "AAA", 21));//int@0.xml
list.add(new Student(11, "BBB", 22));
list.add(new Student(12, "CCC", 23));
File f2 = new File("./src/testXStream/map/");
if (!f2.exists()) {
f2.mkdir();
}
x.addPermission(AnyTypePermission.ANY);//XmlSet,XmlMap在添加的时候可能会用到反序列化校验
PersistenceStrategy strategy2 = new FilePersistenceStrategy(f2, x);
System.out.println("XmlMap");
XmlMap map = new XmlMap(strategy2);
map.put("A", new Student(13, "DDDD", 24));//string@A.xml
map.put("B", new Student(14, "EEEE", 25));
File f3 = new File("./src/testXStream/set/");
if (!f3.exists()) {
f3.mkdir();
}
PersistenceStrategy strategy3 = new FilePersistenceStrategy(f3, x);
System.out.println("XmlSet");
XmlSet set = new XmlSet(strategy3);
set.add(new Student(15, "FF", 26));//long@xxxxxxxxxxxxx.xml
set.add(new Student(16, "GG", 27));
}
@Test
public void test8() {
XStream x = new XStream();
x.addPermission(AnyTypePermission.ANY);
File f1 = new File("./src/testXStream/list/");
PersistenceStrategy strategy = new FilePersistenceStrategy(f1, x);
//读取xml文件
XmlArrayList list = new XmlArrayList(strategy);
Iterator<Student> it = list.iterator();
while (it.hasNext()) {
System.out.println("list->" + it.next());
it.remove();//删除文件
}
File f2 = new File("./src/testXStream/map/");
PersistenceStrategy strategy2 = new FilePersistenceStrategy(f2, x);
XmlMap map = new XmlMap(strategy2);
for(Object k : map.keySet()) {
System.out.println("map->key:" + k + " val:" + map.get(k));
map.remove(k);//删除
}
File f3 = new File("./src/testXStream/set/");
PersistenceStrategy strategy3 = new FilePersistenceStrategy(f3, x);
XmlSet set = new XmlSet(strategy3);
Iterator<Student> it2 = set.iterator();
while (it2.hasNext()) {
System.out.println("set->" + it2.next());
it2.remove();//删除
}
f1.delete();//删除空文件夹
f2.delete();
f3.delete();
}
}
class Student {
public int id;
public String name;
public int age;
public Student(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
class School {
public String schoolName;
public List<Student> students = new ArrayList<>();
@Override
public String toString() {
return "School [schoolName=" + schoolName + ", students=" + students + "]";
}
}
class MyConverter implements Converter {
@Override
public boolean canConvert(Class type) {
System.out.println("--准备判断类型");
return type.equals(Student.class);//判断可转换的数据类型
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
//序列化为xml/json
System.out.println("--准备序列化");
Student stu = (Student) source;
writer.addAttribute("ID", stu.id + "");
writer.startNode("StuId");
writer.setValue(stu.id + "");
writer.endNode();
writer.startNode("StuName");
writer.addAttribute("age", stu.age + "");
writer.setValue(stu.name);
writer.endNode();
writer.startNode("StuAge");
writer.setValue(stu.age + "");
writer.endNode();
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
//反序列化为obj
System.out.println("--准备反序列化");
int sId = -1;
String sName = "";
int sAge = -1;
System.out.println("--Attribute:" + reader.getAttributeName(0) + reader.getAttribute(0));
reader.moveDown();//选择当前子节点作为当前节点,跟moveUp对应调用
sId = Integer.parseInt(reader.getValue());
reader.moveUp();//选择父节点作为当前节点
reader.moveDown();
System.out.println("sName attribute:age=" + reader.getAttribute("age"));//需要在getValue前(读取value节点前的开始节点才有属性)
sName = reader.getValue();
reader.moveUp();
reader.moveDown();
sAge = Integer.parseInt(reader.getValue());
reader.moveUp();
return new Student(sId, sName, sAge);
}
}
运行结果:
执行test7(执行test8之前)生成的xml文件:
实例化XStream的Driver参数有:
Demo2使用标签:
/**
* 2021年8月25日下午3:35:27
*/
package testXStream;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.SingleValueConverter;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.basic.BooleanConverter;
import com.thoughtworks.xstream.converters.basic.IntConverter;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
import com.thoughtworks.xstream.security.AnyTypePermission;
/**
* @author XWF
*
*/
public class TestXStream2 {
public static int i = 1;
@BeforeEach
public void before() {
System.out.println(String.format("================ %d ================", i++));
}
@AfterEach
public void after() {
System.out.println();
}
@Test
public void test1() {
Book b1 = new Book("10001", "BookA", 30.3d);
Book b2 = new Book("10002", "BookB", 100.1d);
Library lib = new Library();
lib.name = "MyLibrary";
lib.books.add(b1);
lib.books.add(b2);
XStream x = new XStream();
x.processAnnotations(Book.class);//设置应用注解的类
x.processAnnotations(Library.class);
String str = x.toXML(lib);
System.out.println(str);
x.addPermission(AnyTypePermission.ANY);
System.out.println(x.fromXML(str));
}
@Test
public void test2() {
Book b1 = new Book("10001", "BookA", 30.3d);
Book b2 = new Book("10002", "BookB", 100.1d);
Library lib = new Library();
lib.name = "MyLibrary";
lib.books.add(b1);
lib.books.add(b2);
XStream x = new XStream(new JettisonMappedXmlDriver());
x.processAnnotations(new Class[] {Book.class, Library.class});//设置应用注解的类
x.addPermission(AnyTypePermission.ANY);
String str = x.toXML(lib);
System.out.println(str);
System.out.println(x.fromXML(str));
}
@Test
public void test3() {
A aObj = new A();
aObj.a = "AAAA";
aObj.b = 10;
aObj.c = true;
B b = new B("dddddd", -12);
aObj.bObj = b;
aObj.bObj2 = b;//跟aObj.bObj引用同一对象
XStream x = new XStream();
x.autodetectAnnotations(true);//自动检测注解
x.addPermission(AnyTypePermission.ANY);
x.setMode(XStream.NO_REFERENCES);//禁止aObj.bObj2使用引用,否则会序列化为<bObj2 reference="../BCls"/>
String str = x.toXML(aObj);
System.out.println(str);
System.out.println(x.fromXML(str));
}
}
@XStreamAlias("BOOK") //别名
class Book {
@XStreamAsAttribute() //设置为属性
@XStreamAlias("BookNo") //别名
public String no;
public String name;
public double price;
@XStreamOmitField //忽略字段
public String temp = "xxx";
public Book(String no, String name, double price) {
super();
this.no = no;
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "Book [no=" + no + ", name=" + name + ", price=" + price + "]";
}
}
@XStreamAlias("LIBRARY")
class Library {
public String name;
@XStreamImplicit(itemFieldName = "MyBook") //隐藏集合根节点books,itemFieldName设置下面子节点别名
public List<Book> books = new ArrayList<>();
@Override
public String toString() {
return "Library [name=" + name + ", books=" + books + "]";
}
}
@XStreamAlias("ACls")
class A {
public String a;
public int b;
@XStreamConverter(value = BooleanConverter.class, booleans = {false}, strings = {"yes", "no"})
public boolean c;
@XStreamAlias("BCls")
@XStreamConverter(BConverter.class)//需要为public class
public B bObj;
@XStreamConverter(BConverter2.class)
public B bObj2;
@Override
public String toString() {
return "A [a=" + a + ", b=" + b + ", c=" + c + ", bObj=" + bObj + ", bObj2=" + bObj2 + "]";
}
}
class B {
public String d;
public int e;
public B(String d, int e) {
super();
this.d = d;
this.e = e;
}
@Override
public String toString() {
return "B [d=" + d + ", e=" + e + "]";
}
}
BConverter.java
/**
* 2021年8月27日上午10:21:21
*/
package testXStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
/**
* @author XWF
*
*/
public class BConverter implements Converter {
@Override
public boolean canConvert(Class type) {
return type.equals(B.class);
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
B b = (B) source;
writer.setValue(b.d + "_" + b.e);
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
String str = reader.getValue();
String[] s = str.split("_");
String bd = s[0];
int be = Integer.parseInt(s[1]);
return new B(bd, be);
}
}
BConverter2.java
/**
* 2021年8月27日上午10:28:04
*/
package testXStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
/**
* @author XWF
*
*/
public class BConverter2 implements Converter {
@Override
public boolean canConvert(Class type) {
return type.equals(B.class);
}
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
B b = (B) source;
writer.startNode("BD");
writer.setValue(b.d);
writer.endNode();
writer.startNode("BE");
writer.setValue(b.e + "");
writer.endNode();
}
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
reader.moveDown();
String bd = reader.getValue();
reader.moveUp();
reader.moveDown();
int be = Integer.parseInt(reader.getValue());
reader.moveUp();
return new B(bd, be);
}
}
运行结果:
需要注意的地方:
1.反序列化的时候有未知标签需使用ignoreUnknownElements()忽略;
2.反序列化的时候通常需要addPermission(AnyTypePermission.ANY);
3.JettisonMappedXmlDriver支持序列化和反序列化,需要引入jettison包,JsonHierarchicalStreamDriver只能序列化;
4.无根节点的json反序列化会失败;
5.使用XmlArrayList、XmlMap、XmlSet生成xml文件的时候,最好生成到不同目录,在生成的时候需要addPermission(AnyTypePermission.ANY);
6.使用注解的时候需要使用processAnnotations()或者autodetectAnnotations(true);
7.使用@XStreamConverter指定转换器的时候,自定义转换器类需要是public class(而使用registerConverter()方法指定的时候可以不用public);
8.字段有相同引用的时候可以用setMode(XStream.NO_REFERENCES)禁用引用;
9.自定义转换器反序列化方法里获得属性getAttribute()方法的位置需要在开始标签的位置;
参考: