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


使用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 对象转换为XML (marshal 方法)

   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.thoughtworknverters.Converter; import com.thoughtworknverters.MarshallingContext; import com.thoughtworknverters.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==$amp;>quot;$); String xml = xstream.toXML(person); System.out.println(xml); //使用unmarshal方法,将XML转换成为Person对象 System.out.println(); System.out.println("****使用unmarshal方法,将XML转换成为Person对象==$amp;>quot;$); Person p = (Person)xstream.fromXML(xml); //输出Person对象 System.out.println(); System.out.println("****输出Person对象==$amp;>quot;$); 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.thoughtworknverters.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==$amp;>quot;$); String xml = xstream.toXML(person); System.out.println(xml); //使用fromString方法,将XML转换成为Person对象 System.out.println(); System.out.println("****使用fromString方法,将XML转换成为Person对象==$amp;>quot;$); Person p = (Person)xstream.fromXML(xml); //输出Person对象 System.out.println(); System.out.println("****输出Person对象==$amp;>quot;$); 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 对象转换为XML (marshal 方法)

   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.thoughtworknverters.ConversionException; import com.thoughtworknverters.Converter; import com.thoughtworknverters.MarshallingContext; import com.thoughtworknverters.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.thoughtworknverters.ConversionException; import com.thoughtworknverters.Converter; import com.thoughtworknverters.MarshallingContext; import com.thoughtworknverters.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}

xml XML基础知识 程序开发

枯萎的树海 15 years, 7 months ago

Your Answer