`

使用XStream是实现XML与Java对象的转换(4)--转换器

阅读更多

七、转换器(Converter)

我们程序中的POJO是千变万化的,而且需求也是千奇百怪的,所以XStream中的内置的转换器的功能不一定能够满足我们的要求,所以我们就需要自己构建转换器。

1,一个基本的转换器

有如下代码:

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
 
public class XStreamTest4 {
   public static void main(String[] args) {
      Person person = new Person();
      person.setName("张三");
 
      XStream xstream = new XStream(new DomDriver());
      xstream.alias("person", Person.class);
      System.out.println(xstream.toXML(person));
   }
}
 
class Person {
 
   private String name;
 
   public String getName() {
      return name;
   }
 
   public void setName(String name) {
      this.name = name;
   }
 
   public String toString() {
      return getName();
   }
}

 

运行结果是:

<person>
  <name>张三</name>
</person>

 

如果我们需要输出如下信息:

<person>
  <fullname>张三</fullname>
</person>

 

该怎么办?

当然,我们可以使用XStream默认的转换器

xstream.aliasField("fullname", Person.class,"name");

 

,甚至我们可以直接使用注解@XStreamAlias。但是这不是我们要介绍的,我们需要创建自己的转换器PersonConverter

PersonConverter需要有3个功能:

a)告诉XStream对象,它能够转换Person类的对象(canConvert方法)

b)能够将Person对象转换为XMLmarshal方法)

c)能够将XML转换成为Person对象(unmarshal方法)

 

现在,我们实现第一个功能(canConvert方法):

//告诉XStream对象,它能够转换Person类的对象
   public boolean canConvert(Class clazz) {
      return clazz.equals(Person.class);
   }

 

就这么简单!

 

然后,我们实现第二个功能(marshal方法):

//能够将Person对象转换为XML
   public void marshal(
        Object value,            //我们将要转换的对象,这里是Person对象
        HierarchicalStreamWriter writer,//用于输出XML结果的writer
        MarshallingContext context     //序列化环境上下文
        ) {
      //写入顺序
      //1,强制转换为我们我们需要的类型
      Person person = (Person) value;
      //2,开始写入fullname节点,相当于写入<fullname>
      writer.startNode("fullname");
      //3,给fullname节点赋值
      writer.setValue(person.getName());
      //4,结束fullname节点,相当于写入</fullname>
      writer.endNode();
     
     
//    //如果你愿意,顺便也可以写一点其他的东西
//    writer.startNode("otherContent");
//    writer.setValue("这是一大串其他内容,你可以根据自己的需要写内容!");
//    writer.endNode();
   }

 

 

最后,我们实现第三个功能(unmarshal方法):

//能够将XML转换成为Person对象
   public Object unmarshal(
        HierarchicalStreamReader reader,//用于读取XML的reader
        UnmarshallingContext context   //反序列化环境上下文
        ) {
      //1,先创建一个Person对象
      Person person = new Person();
      //2,判断<person>节点下还有没有其他可以读取的节点
      while(reader.hasMoreChildren()){
        //3,开始读取下一个(也可能是第一个)节点,选择当前<person>节点的子节点作为当前节点
        reader.moveDown();
        //4,获取当前节点的值
        String value = reader.getValue();
        if("fullname".equals(reader.getNodeName())){
           person.setName(value);
        }
        //输出当前节点的内容
        System.out.println("node="+reader.getNodeName()+";value="+value);
        //5,返回上一层节点<person>
        reader.moveUp();
      }
      return person;
   }

 

 

于是我们的PersonConverter就是:

package cn.tjpu.zhw.xml.xstream4;
 
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;
 
public class PersonConverter implements Converter {
 
   //告诉XStream对象,它能够转换Person类的对象
   public boolean canConvert(Class clazz) {
      return clazz.equals(Person.class);
   }
 
   //能够将Person对象转换为XML
   public void marshal(
        Object value,            //我们将要转换的对象,这里是Person对象
        HierarchicalStreamWriter writer,//用于输出XML结果的writer
        MarshallingContext context     //序列化环境上下文
        ) {
      //写入顺序
      //1,强制转换为我们我们需要的类型
      Person person = (Person) value;
      //2,开始写入fullname节点,相当于写入<fullname>
      writer.startNode("fullname");
      //3,给fullname节点赋值
      writer.setValue(person.getName());
      //4,结束fullname节点,相当于写入</fullname>
      writer.endNode();
     
     
//    //如果你愿意,顺便也可以写一点其他的东西
//    writer.startNode("otherContent");
//    writer.setValue("这是一大串其他内容,你可以根据自己的需要写内容!");
//    writer.endNode();
   }
 
   //能够将XML转换成为Person对象
   public Object unmarshal(
        HierarchicalStreamReader reader,//用于读取XML的reader
        UnmarshallingContext context   //反序列化环境上下文
        ) {
      //1,先创建一个Person对象
      Person person = new Person();
      //2,判断<person>节点下还有没有其他可以读取的节点
      while(reader.hasMoreChildren()){
        //3,开始读取下一个(也可能是第一个)节点,选择当前<person>节点的子节点作为当前节点
        reader.moveDown();
        //4,获取当前节点的值
        String value = reader.getValue();
        if("fullname".equals(reader.getNodeName())){
           person.setName(value);
        }
        //输出当前节点的内容
        System.out.println("node="+reader.getNodeName()+";value="+value);
        //5,返回上一层节点<person>
        reader.moveUp();
      }
      return person;
   }
}

 

同时我们修改main方法文件:

package cn.tjpu.zhw.xml.xstream4;
 
 
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
 
public class XStreamTest4 {
   public static void main(String[] args) {
      //创建Person对象
      Person person = new Person();
      person.setName("张三");
 
      //创建XStream对象
      XStream xstream = new XStream(new DomDriver());
      xstream.alias("person", Person.class);
     
      //注册PersonConverter转换器
      xstream.registerConverter(new PersonConverter());
     
      //使用marshal方法,将Person对象转换成为XML
      System.out.println("****使用marshal方法,将Person对象转换成为XML==>");
      String xml = xstream.toXML(person);
      System.out.println(xml);
     
      //使用unmarshal方法,将XML转换成为Person对象
      System.out.println();
      System.out.println("****使用unmarshal方法,将XML转换成为Person对象==>");
      Person p = (Person)xstream.fromXML(xml);
     
      //输出Person对象
      System.out.println();
      System.out.println("****输出Person对象==>");
      System.out.println(p);
   }
}
 
class Person {
 
   private String name;
 
   public String getName() {
      return name;
   }
 
   public void setName(String name) {
      this.name = name;
   }
 
   public String toString() {
      return "Person对象的name="+getName();
   }
}

 

 

运行结果如下:

****使用marshal方法,将Person对象转换成为XML==>
<person>
  <fullname>张三</fullname>
</person>
 
****使用unmarshal方法,将XML转换成为Person对象==>
node=fullname;value=张三
 
****输出Person对象==>
Person对象的name=张三

 

 

我们成功了!!!!!!

 

2,另一个简单的转换器

现在我们需要程序输出如下:

<person>张三</person>

该咋办?

我们再创建一个转换器:

package cn.tjpu.zhw.xml.xstream4;
 
import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter;
 
public class AnotherPersonConverter extends AbstractSingleValueConverter {
 
   // 告诉XStream对象,它能够转换Person类的对象
   public boolean canConvert(Class clazz) {
      return clazz.equals(Person.class);
   }
 
   // 将Person对象转换为XML,参数obj就是要转换的Person对象,返回值就是<person>节点的值
   public String toString(Object obj) {
      Person p = (Person) obj;
      return p.getName();
   }
 
   // 将XML转换成为Person对象,参数str就是<person>节点的值,返回值就是转换得到的Person对象
   public Object fromString(String str) {
      Person person = new Person();
      person.setName(str);
      System.out.println("参数str="+str);
      return person;
   }
}

 

 

修改Main方法:

public class XStreamTest4 {
   public static void main(String[] args) {
      //创建Person对象
      Person person = new Person();
      person.setName("张三");
 
      //创建XStream对象
      XStream xstream = new XStream(new DomDriver());
      xstream.alias("person", Person.class);
     
//    //注册PersonConverter转换器
//    xstream.registerConverter(new PersonConverter());
     
      //注册AnotherPersonConverter转换器
      xstream.registerConverter(new AnotherPersonConverter());
     
      //使用toString方法,将Person对象转换成为XML
      System.out.println("****使用toString方法,将Person对象转换成为XML==>");
      String xml = xstream.toXML(person);
      System.out.println(xml);
     
      //使用fromString方法,将XML转换成为Person对象
      System.out.println();
      System.out.println("****使用fromString方法,将XML转换成为Person对象==>");
      Person p = (Person)xstream.fromXML(xml);
     
      //输出Person对象
      System.out.println();
      System.out.println("****输出Person对象==>");
      System.out.println(p);
   }
}

 

运行结果:

****使用toString方法,将Person对象转换成为XML==>
<person>张三</person>
 
****使用fromString方法,将XML转换成为Person对象==>
参数str=张三
 
****输出Person对象==>
Person对象的name=张三

 

 

这正是我们预期的结果!!!

 

3,时间转换器

通过上面两个例子我们知道了Converter接口的简单工作方式,现在我们创建一个新的时间转换器DateConverter,这个时间转换器将以Local对象作为构造方法的参数。

这个时间转换器同样有类似PersonConverter转换器的功能:

a)告诉XStream对象,它能够转换Calendar类的对象(canConvert方法)

b)能够将Calendar对象转换为XMLmarshal方法)

c)能够将XML转换成为Calendar对象(unmarshal方法)

 

现在实现第一个功能:

// 告诉XStream对象,它能够转换Calendar类及其所有子类定义的对象
   public boolean canConvert(Class clazz) {
      return Calendar.class.isAssignableFrom(clazz);
   }

 

 

然后,实现第二个功能:

// 能够将Calendar对象转换为XML
   public void marshal(Object value, HierarchicalStreamWriter writer,
        MarshallingContext context) {
      //value是将要转换的Calendar对象
      Calendar calendar = (Calendar) value;
      Date date = calendar.getTime();
     
      //设定格式化格式
      DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
           this.locale);
     
      //格式化并输出Calendar对象
      writer.setValue(formatter.format(date));
   }

 

 

最后,实现最后一个功能:

// 能够将XML转换成为Calendar对象
   public Object unmarshal(HierarchicalStreamReader reader,
        UnmarshallingContext context) {
      //创建一个Calendar对象
      GregorianCalendar calendar = new GregorianCalendar();
     
      //设定解析格式
      DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
           this.locale);
      try {
        //解析指定格式的Calendar对象
        calendar.setTime(formatter.parse(reader.getValue()));
      } catch (ParseException e) {
        throw new ConversionException(e.getMessage(), e);
      }
      //返回解析成功的Calendar对象
      return calendar;
   }

 

于是,我们的DateConverter定义如下:

package cn.tjpu.zhw.xml.xstream4;
 
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
 
import com.thoughtworks.xstream.converters.ConversionException;
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;
 
public class DateConverter implements Converter {
 
   private Locale locale;
 
   public DateConverter(Locale locale) {
      super();
      this.locale = locale;
   }
 
   // 告诉XStream对象,它能够转换Calendar类及其所有子类定义的对象
   public boolean canConvert(Class clazz) {
      return Calendar.class.isAssignableFrom(clazz);
   }
 
   // 能够将Calendar对象转换为XML
   public void marshal(Object value, HierarchicalStreamWriter writer,
        MarshallingContext context) {
      //value是将要转换的Calendar对象
      Calendar calendar = (Calendar) value;
      Date date = calendar.getTime();
     
      //设定格式化格式
      DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
           this.locale);
     
      //格式化并输出Calendar对象
      writer.setValue(formatter.format(date));
   }
 
   // 能够将XML转换成为Calendar对象
   public Object unmarshal(HierarchicalStreamReader reader,
        UnmarshallingContext context) {
      //创建一个Calendar对象
      GregorianCalendar calendar = new GregorianCalendar();
     
      //设定解析格式
      DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
           this.locale);
      try {
        //解析指定格式的Calendar对象
        calendar.setTime(formatter.parse(reader.getValue()));
      } catch (ParseException e) {
        throw new ConversionException(e.getMessage(), e);
      }
      //返回解析成功的Calendar对象
      return calendar;
   }
}

 

 

再写我们的main方法:

package cn.tjpu.zhw.xml.xstream4;
 
import java.text.DateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;
 
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
 
public class DateMain {
 
   public static void main(String[] args) {
      // 获取当前时间
      Calendar calendar = new GregorianCalendar();
 
      // 创建XStream对象
      XStream xstream = new XStream(new DomDriver());
      xstream.alias("date", Calendar.class);
 
      // 注册我们定义的时间转换器
      xstream.registerConverter(new DateConverter(new Locale("zh", "cn")));
 
      // 转换并输出XML
      String xml = xstream.toXML(calendar);
      System.out.println(xstream.toXML(calendar));
 
      // 加载XML中的时间数据
      Calendar loaded = (Calendar) xstream.fromXML(xml);
      //格式化并输出时间
      System.out.println(DateFormat.getDateInstance(DateFormat.MEDIUM).format(
           loaded.getTime()));
   }
}

 

 

运行,结果如下:

<date>2013年12月24日 星期二</date>
2013-12-24

 

 

 

4,更加复杂的转换器

复杂的转换器都是由一系列基本的转换器组成的,我们只需要将这些基本的转换器按照适当的顺序排列组合就行了。

下面有一个复杂的Birthday类:

package cn.tjpu.zhw.xml.xstream4;
 
import java.util.Calendar;
 
 
public class Birthday {
 
   private Person person;
   private Calendar date;
   private char gender;
 
   public Person getPerson() {
      return person;
   }
 
   public void setPerson(Person person) {
      this.person = person;
   }
 
   public Calendar getDate() {
      return date;
   }
 
   public void setDate(Calendar date) {
      this.date = date;
   }
 
   public char getGender() {
      return gender;
   }
 
   public void setGenderMale() {
      this.gender = 'm';
   }
 
   public void setGenderFemale() {
      this.gender = 'f';
   }
  
   public String toString(){
      return "{person="+person+"};{date="+date.getTime()+"};{gender="+gender+"}";
   }
 
}

 

我们将怎样转换这个类呢?

答案是,我们只需要将现有的转换器组合成一个BirthdayConverter转换器就成了!

package cn.tjpu.zhw.xml.xstream4;
 
import java.util.Calendar;
 
import com.thoughtworks.xstream.converters.ConversionException;
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;
 
public class BirthdayConverter implements Converter {
 
   // 告诉XStream对象,它能够转换Birthday类的对象
   public boolean canConvert(Class clazz) {
      return Birthday.class == clazz;
   }
 
   // 能够将Birthday对象转换为XML
   public void marshal(Object value, HierarchicalStreamWriter writer,
        MarshallingContext context) {
      //value是将要被转换的Birthday对象
      Birthday birthday = (Birthday) value;
     
      //给<birthday>节点添加gender属性
      if (birthday.getGender() != '\0') {
        writer.addAttribute("gender",
              Character.toString(birthday.getGender()));
      }
     
      //给<birthday>节点添加子节点<person>
      if (birthday.getPerson() != null) {
        writer.startNode("person");
        context.convertAnother(birthday.getPerson());
        writer.endNode();
      }
     
      //给<birthday>节点添加子节点<birth>
      if (birthday.getDate() != null) {
        writer.startNode("birth");
        context.convertAnother(birthday.getDate());
        writer.endNode();
      }
   }
 
   // 能够将XML转换成为Birthday对象
   public Object unmarshal(HierarchicalStreamReader reader,
        UnmarshallingContext context) {
      //创建Birthday对象
      Birthday birthday = new Birthday();
     
      //当前节点是<birthday>
      //解析<birthday>节点的gender属性
      String gender = reader.getAttribute("gender");
      if (gender != null) {
        if (gender.length() > 0) {
           if (gender.charAt(0) == 'f') {
              birthday.setGenderFemale();
           } else if (gender.charAt(0) == 'm') {
              birthday.setGenderMale();
           } else {
              throw new ConversionException("Invalid gender value: "
                    + gender);
           }
        } else {
           throw new ConversionException(
                 "Empty string is invalid gender value");
        }
      }
     
      //遍历解析<birthday>节点的所有子节点
      while (reader.hasMoreChildren()) {
        //将下一个(也可能是第一个)子节点作为当前节点
        reader.moveDown();
       
        //解析<person>节点
        if ("person".equals(reader.getNodeName())) {
           Person person = (Person) context.convertAnother(birthday,
                 Person.class);
           birthday.setPerson(person);
        }
        //解析<birth>节点
        else if ("birth".equals(reader.getNodeName())) {
           Calendar date = (Calendar) context.convertAnother(birthday,
                 Calendar.class);
           birthday.setDate(date);
        }
        //返回到<birthday>节点作为当前节点
        reader.moveUp();
      }
     
      //返回解析得到的Birthday对象
      return birthday;
   }
 
}

 

下面写main方法:

 

package cn.tjpu.zhw.xml.xstream4;
 
import java.util.GregorianCalendar;
 
import com.thoughtworks.xstream.XStream;
 
public class BirthdayMain {
 
   public static void main(String[] args) {
 
      //创建Birthday对象
      Birthday birthday = new Birthday();
      Person p = new Person();
      p.setName("张三");
      birthday.setPerson(p);
      birthday.setDate(new GregorianCalendar());
      birthday.setGenderMale();
     
      //创建XStream对象
      XStream xstream = new XStream();
      xstream.alias("birthday", Birthday.class);
     
      //注册BirthdayConverter转换器
      xstream.registerConverter(new BirthdayConverter());
     
      //将Birthday对象转换成为XML并输出
      String xml = xstream.toXML(birthday);
      System.out.println("**************将Birthday对象转换成为XML并输出**************");
      System.out.println(xml);
     
      //将XML转换成为Birthday对象
      Birthday b = (Birthday)xstream.fromXML(xml);
      //输出Birthday对象
      System.out.println();
      System.out.println("**************将XML转换成为Birthday对象**************");
      System.out.println(b);
     
   }
 
}

 

运行结果:

**************将Birthday对象转换成为XML并输出**************
<birthday gender="m">
  <person>
    <name>张三</name>
  </person>
  <birth>
    <time>1387897906531</time>
    <timezone>Asia/Shanghai</timezone>
  </birth>
</birthday>
 
**************将XML转换成为Birthday对象**************
{person=Person对象的name=张三};{date=Tue Dec 24 23:11:46 CST 2013};{gender=m}

 

 

 

 

 

 

 

 

 

 

 

2
0
分享到:
评论

相关推荐

    XStream XML与Json转换

    XStream在运行时使用Java反射机制对要进行序列化的对象树的结构进行探索,并不需要对对象作出修改。XStream可以序列化内部字段,包括私private和final字段,并且支持非公开类以及内部类。 在缺省情况下,XStream不...

    xstream-1.4.7.jar及源码;xml-pull-1.3.1.jar

    xstream-1.4.7.jar及源码;... Stream对象相当Java对象和XML之间的转换器,转换过程是双向的。创建XSteam对象的方式很简单,只需要new XStream()即可。 Java到xml,用toXML()方法。 Xml到Java,用fromXML()方法。

    XStream使用方法总结附实例代码

    XStream对象相当Java对象和XML之间的转换器,转换过程是双向的。创建XSteam对象的方式很简单,只需要new XStream()即可。 Java到xml,用toXML()方法。 Xml到Java,用fromXML()方法。 在没有任何设置默认情况下,...

    xstream-1.4.7

    XStream是一个Java对象和XML相互转换的工具,很好很强大。提供了所有的基础类型、数组、集合等...Stream对象相当Java对象和XML之间的转换器,转换过程是双向的。创建XSteam对象的方式很简单,只需要new XStream()即可。

    json,xstream,ezmorph jar包

    //json的转换器及帮助 ezmorph-1.0.6.jar ezmorph-1.0.6-javadoc.jar //java将数据类型转为json格式及帮助 json-lib-2.2.3-jdk15.jar json-lib-2.2.3-jdk15-javadoc.jar commons-collections-3.2.jar commons-lang-...

    spring O/X 映射

    它的目的是在 Java 对象(几乎总是一个 plain old Java object,或简写为 POJO)和 XML 文档之间来回转换。 例如,您可能有一个带有几个属性的简单 bean,且您的业务需要将那个 Java 对象转换为一个 XML 文档。...

    Spring.3.x企业应用开发实战(完整版).part2

    14.2.4 XStream转换器 14.2.5 XStream注解 14.2.6 流化对象 14.2.7 持久化API 14.2.8 额外功能:处理JSON 14.3 其他常见O/X Mapping开源项目 14.3.1 JAXB 14.3.2 XMLBeans 14.3.3 Castor 14.3.4 JiBX 14.3.5 总结...

    Spring3.x企业应用开发实战(完整版) part1

    14.2.4 XStream转换器 14.2.5 XStream注解 14.2.6 流化对象 14.2.7 持久化API 14.2.8 额外功能:处理JSON 14.3 其他常见O/X Mapping开源项目 14.3.1 JAXB 14.3.2 XMLBeans 14.3.3 Castor 14.3.4 JiBX 14.3.5 总结...

    Android集成主流优秀第三方组件框架

    XML解析XStream 动画开源库nineoldandroids 表单验证库android-validation-komensky 更多优秀开源库等待集成... 已封装工具类: HTTP网络通信工具类(ToolHTTP.java),get/post请求,支持多种接口回调 SOAP协议通信...

    微信公众平台应用开发:方法、技巧与案例.(机械工业.柳峰)

     4.3.4 响应消息对象转XML 85  4.4 案例:消息的接收与响应 88  4.4.1 开发准备工作 88  4.4.2 消息封装类 88  4.4.3 封装消息处理工具 89  4.4.4 使用CoreServlet类完成消息的接收与响应 93  4.4.5 ...

    Android典型技术模块开发详解

    12.4.1 简单对象类型转换 12.4.2 数组和集合类型转换 12.5 xStream 12.6 本章小结 第四篇 Android应用开发案例 第13章 Ksoap2 13.1 SOAP协议 13.1.1 请求 13.1.2 响应 13.2 WSDL介绍 13.3 Ksoap2应用——天气预报 ...

Global site tag (gtag.js) - Google Analytics