导读
在Spring OXM-XStream快速入门 的案例中,我们看到生成的xml报文如下:
<com.xgj.oxm.xstream.quickDemo.domain.User> <id>1</id> <userName>Artisan</userName> <password>artisan</password> <credits>1000</credits> <lastVisit>2017-12-05 07:30:46.772 UTC</lastVisit> <logs> <com.xgj.oxm.xstream.quickDemo.domain.LoginLog> <loginLogId>99</loginLogId> <userId>1</userId> <ip>127.0.0.1</ip> <loginDate>2017-12-05 07:30:46.772 UTC</loginDate> </com.xgj.oxm.xstream.quickDemo.domain.LoginLog> </logs> </com.xgj.oxm.xstream.quickDemo.domain.User>
在默认情况下,Java对象到XML的映射是Java对象属性名对应XML的元素名,Java类的全名对应XML根元素的名字。
事实上,在实际应用中,如果XML和Java类都已经存在相应的名称,那么在进行转换时,需要设置别名进行映射。
别名配置的三种情况
类别名: 使用alias(String name,Class type)
类成员别名:使用aliasField(String alias, Class definedIn, String fieldName)
类成员作为xml属性别名:使用aliasAttribute(Class definedIn, String attributeName, String alias)方法。 并且需要通过 useAttributeFor(Class definedIn, String fieldName) 应用到某个类上。
从上面的实例中我们看到XML元素结构不是很友好,接下来我们通过XStream提供的别名机制来修饰生成的XML元素的结构。
package com.xgj.oxm.xstream.quickDemo.aliasDemo; import java.text.ParseException; import java.util.Date; import com.thoughtworks.xstream.XStream; import com.xgj.oxm.xstream.quickDemo.domain.LoginLog; import com.xgj.oxm.xstream.quickDemo.domain.User; public class XStreamAliasDemo { private static XStream xstream; static { // 创建一个Xstream实例,使用默认的XPP解析器 xstream = new XStream(); // (1)设置类别名,修改默认的全限定名的名称 xstream.alias("user", User.class); xstream.alias("loginLog", LoginLog.class); // (2)设置类成员别名 <id>1</id> 改为<userId>1</userId> xstream.aliasField("userId", User.class, "id"); // (3)把LoginLog的userId属性视为xml属性,默认为xml的元素 xstream.aliasAttribute(LoginLog.class, "userId", "id"); xstream.useAttributeFor(LoginLog.class, "userId"); // (4)去掉集合类型生成XML的父节点,即忽略xml中的<logs></logs>标记 xstream.addImplicitCollection(User.class, "logs"); } /** * * * @Title: getUser * * @Description: 初始化转换对象 * * @return * * @return: User * @throws ParseException */ public static User getUser() throws ParseException { LoginLog log = new LoginLog(); log.setIp("127.0.0.1"); log.setLoginLogId(99); log.setUserId(1); log.setLoginDate(new Date()); LoginLog log2 = new LoginLog(); log2.setIp("192.168.1.1"); log2.setLoginLogId(22); log2.setUserId(2); log2.setLoginDate(new Date()); User user = new User(); user.setId(1); user.setUserName("Artisan"); user.setPassword("artisan"); user.setCredits(1000); user.setLastVisit(new Date()); user.addLoginLog(log); user.addLoginLog(log2); return user; } /** * * * @Title: objectToXml * * @Description: Java对象转换成XML * * @throws Exception * * @return: void */ public static void objectToXml() throws Exception { // 获取转换的User对象实例 User user = getUser(); // 输出内容到控制台,查看一下 System.out.println(xstream.toXML(user)); System.out.println("objectToXml successfully"); } public static void main(String[] args) throws Exception { objectToXml(); } }
输出
<user> <userId>1</userId> <userName>Artisan</userName> <password>artisan</password> <credits>1000</credits> <lastVisit>2017-12-05 13:39:32.698 UTC</lastVisit> <loginLog id="1"> <loginLogId>99</loginLogId> <ip>127.0.0.1</ip> <loginDate>2017-12-05 13:39:32.698 UTC</loginDate> </loginLog> <loginLog id="2"> <loginLogId>22</loginLogId> <ip>192.168.1.1</ip> <loginDate>2017-12-05 13:39:32.698 UTC</loginDate> </loginLog> </user>
说明:
在(1)处,通过XStream的alias方法来设置类别名。
在(2)处,通过XStream的aliasField方法将User类的id属性设置为userId
在(3)处,通过XStream的aliasAttribute和useAttributeFor方法将LoginLog类的userId属性设置为id,并设置为LoginLog元素的属性。 默认为LoginLog元素的子元素。
在(4)处,通过XStream的addImplicitCollection方法删除集合节点logs,即忽略XML中的<logs></logs>标记。
官方Demo
问题
假设我们有如下的XML,我们如何使用XStream去读写呢?
<blog author="Guilherme Silveira"> <entry> <title>first</title> <description>My first blog entry.</description> </entry> <entry> <title>tutorial</title> <description> Today we have developed a nice alias tutorial. Tell your friends! NOW! </description> </entry> </blog>
结合XStream中的方法,我们来分析一下
blog 节点有个 author 属性 ,可以使用aliasAttribute 和 useAttributeFor方法应用到Blog类上,也可以使用XStream的转换器,这里我们使用转换器的方式。 因为要使用转换器,所以需要一个Author类以及对应的一个name属性用于存储name的值
子节点是多个entry,可以使用List来存储
entry节点有title 和 description 属性 ,所以需要一个Entry类以及2个属性
Model
接下来我们来看下我们创建的几个model类
package com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo; import java.util.ArrayList; import java.util.List; public class Blog { // Author private Author writer; // Entry集合 private List<Entry> entries = new ArrayList<Entry>(); /** * * * @Title:Blog * * @Description:构造函数 * * @param writer */ public Blog(Author writer) { this.writer = writer; } /** * * * @Title: add * * @Description: 添加Entry * * @param entry * * @return: void */ public void add(Entry entry) { entries.add(entry); } /** * * * @Title: getContent * * @Description: 获取Entry List集合 * * @return * * @return: List<Entry> */ public List<Entry> getContent() { return entries; } }
package com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo; public class Author { private String name; public Author(String name) { this.name = name; } public String getName() { return name; } }
package com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo; public class Entry { private String title, description; public Entry(String title, String description) { this.title = title; this.description = description; } }
我们没有创建set/get方法,可根据需要创建。
A Simple Test
接下来,我们来测试一下
public static void main(String[] args) { Blog teamBlog = new Blog(new Author("Guilherme Silveira")); teamBlog.add(new Entry("first","My first blog entry.")); teamBlog.add(new Entry("tutorial", "Today we have developed a nice alias tutorial. Tell your friends! NOW!")); XStream xstream = new XStream(); System.out.println(xstream.toXML(teamBlog)); }
输出如下
<com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo.Blog> <writer> <name>Guilherme Silveira</name> </writer> <entries> <com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo.Entry> <title>first</title> <description>My first blog entry.</description> </com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo.Entry> <com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo.Entry> <title>tutorial</title> <description>Today we have developed a nice alias tutorial. Tell your friends! NOW!</description> </com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo.Entry> </entries> </com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo.Blog>
Class aliasing
我们需要把com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo.Blog 和com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo.Entry 转换成 blog 和 entry.
通过
xstream.alias("blog", Blog.class); xstream.alias("entry", Entry.class);
Blog teamBlog = new Blog(new Author("Guilherme Silveira")); teamBlog.add(new Entry("first", "My first blog entry.")); teamBlog.add(new Entry("tutorial", "Today we have developed a nice alias tutorial. Tell your friends! NOW!")); XStream xstream = new XStream(); // alias Class xstream.alias("blog", Blog.class); xstream.alias("entry", Entry.class); System.out.println(xstream.toXML(teamBlog));
输出结果如下
<blog> <writer> <name>Guilherme Silveira</name> </writer> <entries> <entry> <title>first</title> <description>My first blog entry.</description> </entry> <entry> <title>tutorial</title> <description>Today we have developed a nice alias tutorial. Tell your friends! NOW!</description> </entry> </entries> </blog>
Field aliasing
下面把wirter转换为 author .通过
xstream.aliasField("author", Blog.class, "writer");
输出如下
<blog> <author> <name>Guilherme Silveira</name> </author> <entries> <entry> <title>first</title> <description>My first blog entry.</description> </entry> <entry> <title>tutorial</title> <description>Today we have developed a nice alias tutorial. Tell your friends! NOW!</description> </entry> </entries> </blog>
Implicit Collections
去掉entries节点,通过
xstream.addImplicitCollection(Blog.class, "entries");
输出如下
<blog> <author> <name>Guilherme Silveira</name> </author> <entry> <title>first</title> <description>My first blog entry.</description> </entry> <entry> <title>tutorial</title> <description>Today we have developed a nice alias tutorial. Tell your friends! NOW!</description> </entry> </blog>
Attribute aliasing
下一步是将writer成员变量转换为xml的属性 , 为了做到这一点,我们需要告诉XStream将Blog#writer字段同义为author
问题 : how does XStream converts an Author in a String so it can be written as a XML tag attribute?
Attributes cannot be written for types that are handled by Converter implementations, we have to use a SingleValueConverter and implement our own converter for the Author:
package com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo; import com.thoughtworks.xstream.converters.SingleValueConverter; public class AuthorConverter implements SingleValueConverter { /** * tells XStream which types it can deal with */ public boolean canConvert(Class type) { return type.equals(Author.class); } /** * extract a String from an Author */ public String toString(Object obj) { return ((Author) obj).getName(); } /** * takes a String and returns an Author */ public Object fromString(String name) { return new Author(name); } }
然后注册转换器
xstream.useAttributeFor(Blog.class, "writer"); xstream.registerConverter(new AuthorConverter());
完整的代码如下
package com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo; import com.thoughtworks.xstream.XStream; public class AliasTest { public static void main(String[] args) { Blog teamBlog = new Blog(new Author("Guilherme Silveira")); teamBlog.add(new Entry("first", "My first blog entry.")); teamBlog.add(new Entry("tutorial", "Today we have developed a nice alias tutorial. Tell your friends! NOW!")); XStream xstream = new XStream(); xstream.alias("blog", Blog.class); xstream.alias("entry", Entry.class); xstream.aliasField("author", Blog.class, "writer"); xstream.addImplicitCollection(Blog.class, "entries"); xstream.useAttributeFor(Blog.class, "writer"); xstream.registerConverter(new AuthorConverter()); System.out.println(xstream.toXML(teamBlog)); } }
输出
<blog author="Guilherme Silveira"> <entry> <title>first</title> <description>My first blog entry.</description> </entry> <entry> <title>tutorial</title> <description>Today we have developed a nice alias tutorial. Tell your friends! NOW!</description> </entry> </blog>
Package aliasing
xstream.aliasPackage("my.company", "org.thoughtworks");
比如
package com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo; import com.thoughtworks.xstream.XStream; public class AliasPackage { public static void main(String[] args) { Blog teamBlog = new Blog(new Author("Guilherme Silveira")); teamBlog.add(new Entry("first", "My first blog entry.")); teamBlog.add(new Entry("tutorial", "Today we have developed a nice alias tutorial. Tell your friends! NOW!")); XStream xstream = new XStream(); xstream.aliasPackage( "com.artisan", "com.xgj.oxm.xstream.quickDemo.aliasDemo.officeDemo"); System.out.println(xstream.toXML(teamBlog)); } }
输出
<com.artisan.Blog> <writer> <name>Guilherme Silveira</name> </writer> <entries> <com.artisan.Entry> <title>first</title> <description>My first blog entry.</description> </com.artisan.Entry> <com.artisan.Entry> <title>tutorial</title> <description>Today we have developed a nice alias tutorial. Tell your friends! NOW!</description> </com.artisan.Entry> </entries> </com.artisan.Blog>
示例源码
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster