XStream笔记


XStream是一个将对象序列化为xml并解析xml为对象的框架,主页位于http://xstream.codehaus.org。使用非常简单

 

引入依赖:


<dependency>  
    <groupId>com.thoughtworks.xstream</groupId>  
    <artifactId>xstream</artifactId>  
    <version>1.4.2</version>  
</dependency>


需要的依赖

XmlPull一个xmlpull parser api用来判断具体的xml解析实现(DOM、StAX等)工厂

其他可供选择的Xpp3、DOM4J

 

1、创建待序列化的对象:

Person.java


public class Person {  
  
    private Integer id;  
    private String  username;  
    private String  password;  
    private Address address;  
    ...  
}


 Person中包含一个Address作为Field

public class Address {  
  
    private String street;  
    private String city;  
    ......  
}

 

2、序列化和反序列化

使用XStream只需要实例化一个XStream对象即可:

Java代码   收藏代码
  1. XStream xstream = new XStream();  
  2. //采用这个构造器默认需要依赖:xstream-[version].jar, xpp3-[version].jar and xmlpull-[version].jar  
 或者采用DOM的方式解析:
Java代码   收藏代码
  1. XStream xstream = new XStream(new DomDriver());   
  2. //此时不需要XPP3  

或者基于事件的StAX

Java代码   收藏代码
  1. XStream xstream = new XStream(new StaxDriver());   
  2. //如果采用Java 6,也不需要xpp3.将采用默认的JAXB  
Java代码   收藏代码
  1. //对象序列化为xml  
  2. xstream.toXML(Object)  
  3.   
  4. //xml反序列化为对象  
  5. xstream.fromXML(xml)  

 一个例子:

Java代码   收藏代码
  1. Person p = new Person();  
  2. p.setId(1);  
  3. p.setUsername("robin");  
  4. p.setPassword("123");  
  5. p.setAddress(new Address("xxRoad""chengdu"));  
  6. xstream.toXML(p);  

 输出为:

Xml代码   收藏代码
  1. <org.java.codelib.xstream.Person>  
  2.   <id>1</id>  
  3.   <username>robin</username>  
  4.   <password>123</password>  
  5.   <address>  
  6.     <street>xxRoad</street>  
  7.     <city>chengdu</city>  
  8.   </address>  
  9. </org.java.codelib.xstream.Person>  

 

3、alias

这里可以看到生成的xml中root element名字为class,如果需要修改就需要用到

Java代码   收藏代码
  1. xstream.alias("person", Person.class);  

这样就会用person替代org.java.codelib.xstream.Person

同样对于field也可以使用alias:

Java代码   收藏代码
  1. xstream.aliasField("personId", Person.class"id");  

这样就会将Person中的id替换为<personId>1</personId>

其他的还有aliasAttribute即将field作为attribute时并采用别名,当前前提是需要设置field作为attribute:

Java代码   收藏代码
  1. XStream xstream = new XStream(new StaxDriver());  
  2. xstream.alias("person", Person.class);  
  3. xstream.useAttributeFor(Person.class"id");  
  4. xstream.aliasAttribute("personId""id");  
  5. xstream.toXML(p);  

输出为:

Xml代码   收藏代码
  1. <?xml version="1.0" ?><person personId="1"><username>robin</username><password>123</password><address><street>xxRoad</street><city>chengdu</city></address></person>   

说到设置field作为attribute如果field是一个自定义对象,或者需要将Date之类的属性格式化输出,如本例中的Address该如何处理?这就是另外一个话题

需要说明的是以上在序列化为xml的时候使用了alias,那么在反序列化的时候同样需要这些相应的代码,不然可能会抛出UnknownFieldException

 

4、convertors

convertor的作用是在做序列化或反序列化的时候,将对象中的属性按照特定的形式输出或转化,在XStream 中默认初始化了大量的必要convertors,见http://xstream.codehaus.org/converters.html 或者在XStream.java中有方法setupConverters()。

自定义一个convertor需要两步:

1、实现Converter接口及相关方法:

Java代码   收藏代码
  1. public class DateConverter implements Converter {  
  2.   
  3.     @Override  
  4.     public boolean canConvert(Class type) {  
  5.         return type.equals(Date.class);  
  6.     }  
  7.   
  8.     @Override  
  9.     public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {  
  10.         DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  11.         writer.setValue(dateFormat.format((Date) source));  
  12.     }  
  13.   
  14.     @Override  
  15.     public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {  
  16.         DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  17.         try {  
  18.             return dateFormat.parse(reader.getValue());  
  19.         } catch (ParseException e) {  
  20.             e.printStackTrace();  
  21.         }  
  22.         return null;  
  23.     }  
  24.   
  25. }  

 

2、在xstream中注册该convertor:

Java代码   收藏代码
  1. xstream.registerConverter(new DateConverter());  

 输出

Xml代码   收藏代码
  1. <?xml version="1.0" ?><person><id>1</id><username>robin</username><password>123</password><birthday>2013-02-17 15:12:53</birthday><address><street>xxRoad</street><city>chengdu</city></address></person>  

当然,xstream针对Date也做了默认的实现,只不过默认输出为UTC格式

现在我们回到上面的问题,即将对象Address作为Person的属性,下面是一个convertor的实现:

Java代码   收藏代码
  1. public class PersonConverter implements Converter {  
  2.   
  3.     @SuppressWarnings("rawtypes")  
  4.     @Override  
  5.     public boolean canConvert(Class type) {  
  6.         return type.equals(Person.class);  
  7.     }  
  8.   
  9.     @Override  
  10.     public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {  
  11.         Person person = (Person) source;  
  12.         if (person != null) {  
  13.             Address address = person.getAddress();  
  14.             if (address != null) {  
  15.                 if (StringUtils.isNotBlank(address.getStreet())) {  
  16.                     writer.addAttribute("street", address.getStreet());  
  17.                 }  
  18.                 if (StringUtils.isNotBlank(address.getCity())) {  
  19.                     writer.addAttribute("city", address.getCity());  
  20.                 }  
  21.             }  
  22.   
  23.             //address  
  24.             if (person.getBirthday() != null) {  
  25.                 writer.startNode("birthday");  
  26.                 context.convertAnother(person.getBirthday(), new DateConverter());  
  27.                 writer.endNode();  
  28.             }  
  29.   
  30.             //username  
  31.             if (person.getUsername() != null) {  
  32.                 writer.startNode("username");  
  33.                 context.convertAnother(person.getUsername());  
  34.                 writer.endNode();  
  35.             }  
  36.             //other fields  
  37.         }  
  38.     }  
  39.   
  40.     @Override  
  41.     public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {  
  42.         Person p = new Person();  
  43.         Address address = new Address();  
  44.         address.setCity(reader.getAttribute("city"));  
  45.         address.setStreet(reader.getAttribute("street"));  
  46.         p.setAddress(address);  
  47.   
  48.         while (reader.hasMoreChildren()) {  
  49.             reader.moveDown();  
  50.             if ("birthday".equals(reader.getNodeName())) {  
  51.                 Date date = (Date) context.convertAnother(p, Date.classnew DateConverter());  
  52.                 p.setBirthday(date);  
  53.             } else if ("username".equals(reader.getNodeName())) {  
  54.                 p.setUsername((String) context.convertAnother(p, String.class));  
  55.             }  
  56.             //other fields  
  57.             reader.moveUp();  
  58.         }  
  59.   
  60.         return p;  
  61.     }  
  62. }  

其中序列化时输出:

Xml代码   收藏代码
  1. <?xml version="1.0" ?><person street="xxRoad" city="chengdu"><birthday>2013-02-17 16:34:24</birthday><username>robin</username></person>  

当然如果作为fields的对象只有一个属性就简单得多了,在http://xstream.codehaus.org/alias-tutorial.html#attributes有例子可供参考

 

5、implicitCollections
考虑Person有列表属性:

Java代码   收藏代码
  1. private List<Address> addresses;  

 在序列化为xml时:

Xml代码   收藏代码
  1. <?xml version="1.0" ?><person><addresses><address><street>road_1</street><city>chengdu</city></address><address><street>road_2</street><city>chengdu</city></address></addresses></person>  

 当然有时候并不想要addresses,这就是XStream中的implicitCollections:对集合的属性在序列化是不想显示roottag。值需要很简单的处理:

Java代码   收藏代码
  1. XStream xstream = new XStream(new StaxDriver());  
  2. xstream.alias("person", Person.class);  
  3. xstream.alias("address", Address.class);  
  4. xstream.addImplicitCollection(Person.class"addresses");  
  5. return xstream.toXML(formatPerson());  

 输出为: 


Xml代码   收藏代码
  1. <?xml version="1.0" ?><person><address><street>road_1</street><city>chengdu</city></address><address><street>road_2</street><city>chengdu</city></address></person>  

 

6、annotation
以上说的内容都支持annotation:

Java代码   收藏代码
  1. @XStreamAlias("person")  
  2. public class Person {  
  3.   
  4.     @XStreamAlias("personId")  
  5.     @XStreamAsAttribute  
  6.     private Integer       id;  
  7.     private String        username;  
  8.     private String        password;  
  9.     @XStreamConverter(DateConverter.class)  
  10.     private Date          birthday;  
  11.     private Address       address;  
  12.     @XStreamImplicit(itemFieldName = "address")  
  13.     private List<Address> addresses;  
  14. }  
Java代码   收藏代码
  1. @XStreamAlias("person")  
  2. public class Address {  
  3.   
  4.     @XStreamAsAttribute  
  5.     private String street;  
  6.     @XStreamAsAttribute  
  7.     private String city;  
  8. }  

需要加上autodetectAnnotations(true)

Java代码   收藏代码
  1. XStream xstream = new XStream(new StaxDriver());  
  2. xstream.autodetectAnnotations(true);  
  3. return xstream.toXML(p);  

输出:

Xml代码   收藏代码
  1. <?xml version="1.0" ?><person personId="1"><username>robin</username><password>123</password><birthday>2013-02-17 17:08:00</birthday><address street="road_1" city="chengdu"></address><address street="road_2" city="chengdu"></address></person>  

7、其他

xstream提供了对json的解析以及持久化(文件系统)的支持,这里就不再介绍了

你可能感兴趣的:(XStream笔记)