2019独角兽企业重金招聘Python工程师标准>>>

Simple Converter

Setting up a simple example

This is the most basic converter... let's start with a simple Person:

package com.thoughtworks.xstream.examples;public class Person {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}}

So let's create a person and convert it to XML...

package com.thoughtworks.xstream.examples;import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;public class PersonTest {public static void main(String[] args) {Person person = new Person();person.setName("Guilherme");XStream xStream = new XStream(new DomDriver());System.out.println(xStream.toXML(person));}}

This results in a really ugly XML code which contains the full class name (including package)...

<com.thoughtworks.xstream.examples.Person><name>Guilherme</name>
</com.thoughtworks.xstream.examples.Person>

So we make use of an 'alias' to change this full class name to something more 'human', for example 'person'.

XStream xStream = new XStream(new DomDriver());
xStream.alias("person", Person.class);
System.out.println(xStream.toXML(person));

And the outcome is much easier to read (and smaller):

<person><name>Guilherme</name>
</person>

Now that we have configured a simple class to play with, let's see what XStream converters can do for us...

Creating a PersonConverter

Let's create a simple converter capable of:

  1. telling its capable of converting Person's

  2. translating a Person instance in XML

  3. translate XML into a new Person

We begin creating the PersonConverter class and implementing the Converter interface:

package com.thoughtworks.xstream.examples;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 {public boolean canConvert(Class clazz) {return false;}public void marshal(Object value, HierarchicalStreamWriter writer,MarshallingContext context) {}public Object unmarshal(HierarchicalStreamReader reader,UnmarshallingContext context) {return null;}}

Now we tell whoever calls us that we can handle only Person's (and nothing else, including those classes which extends Person).

public boolean canConvert(Class clazz) {return clazz.equals(Person.class);
}

The second step is usually quite clean, unless you are dealing with generic converters.

The marshal method is responsible for translating an object to XML. It receives three arguments:

  1. the object we are trying to convert

  2. the writer were we should output the data

  3. the current marshalling context

We start casting the object to person:

Person person = (Person) value;

Now we can output the data... let's start creating a node called fullname and adding the person's name to it:

writer.startNode("fullname");
writer.setValue(person.getName());
writer.endNode();

Quite simple huh?

public void marshal(Object value, HierarchicalStreamWriter writer,MarshallingContext context) {Person person = (Person) value;writer.startNode("fullname");writer.setValue(person.getName());writer.endNode();
}

We could have called start/end node as many times as we would like (but remember to close everything you open)... and conversion usually takes place when calling the setValue method.

And now let's go to the unmarshal. We use the moveDown and moveUp methods to move in the tree hierarchy, so we can simply moveDown, read the value and moveUp.

Person person = new Person();
reader.moveDown();
person.setName(reader.getValue());
reader.moveUp();

Which gives us the following converter:

package com.thoughtworks.xstream.examples;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 {public boolean canConvert(Class clazz) {return clazz.equals(Person.class);}public void marshal(Object value, HierarchicalStreamWriter writer,MarshallingContext context) {Person person = (Person) value;writer.startNode("fullname");writer.setValue(person.getName());writer.endNode();}public Object unmarshal(HierarchicalStreamReader reader,UnmarshallingContext context) {Person person = new Person();reader.moveDown();person.setName(reader.getValue());reader.moveUp();return person;}}

Now let's register our converter and see how our application main method looks like:

package com.thoughtworks.xstream.examples;import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;public class PersonTest {public static void main(String[] args) {Person person = new Person();person.setName("Guilherme");XStream xStream = new XStream(new DomDriver());xStream.registerConverter(new PersonConverter());xStream.alias("person", Person.class);System.out.println(xStream.toXML(person));}}

Did you notice how we registered our converter? It's a simple call to registerConverter:

xStream.registerConverter(new PersonConverter());

The final result is:

<person><fullname>Guilherme</fullname>
</person>

So you might say... that only changed my tree, I want to convert data!

Try using an attribute called fullname in the person tag instead of creating a new child node.

An alternative for types with String representation

Let's enhance the Person with a String representation, that contains all necessary text to recreate the instance:

package com.thoughtworks.xstream.examples;public class Person {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public String toString() {return getName();}
}

In this case we can simplify our Converter to

package com.thoughtworks.xstream.examples;import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter;public class PersonConverter extends AbstractSingleValueConverter {public boolean canConvert(Class clazz) {return clazz.equals(Person.class);}public Object fromString(String str) {Person person = new Person();person.setName(string);return person;}}

But even nicer, our XML is also simplified (using the alias for the Person class). Since the String representation is complete, a nested element is not necessary anymore:

<person>Guilherme</person>

Note, that in implementation of a SingleValueConverter is required for attributes, since these objects have to be represented by a single string only.

Date Converter

Now that we know how the Converter interface works, let's create a simple calendar converter which uses the locale to convert the information.

Our converter will receive the Locale in its constructor and we will keep a reference to it in a member variable:

package com.thoughtworks.xstream.examples;import java.util.Locale;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;}public boolean canConvert(Class clazz) {return false;}public void marshal(Object value, HierarchicalStreamWriter writer,MarshallingContext context) {}public Object unmarshal(HierarchicalStreamReader reader,UnmarshallingContext context) {return null;}}

Now let's convert anything which extends Calendar: means if instances of class clazz can be assigned to the Calendar class, they extends the abstract class Calendar:

public boolean canConvert(Class clazz) {return Calendar.class.isAssignableFrom(clazz);
}

Let's go for converting a Calendar in a localized string... we first cast the object to Calendar, extract its Date and then use a DateFormat factory method to get a date converter to our localized string.

public void marshal(Object value, HierarchicalStreamWriter writer,MarshallingContext context) {Calendar calendar = (Calendar) value;// grabs the dateDate date = calendar.getTime();// grabs the formatterDateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,this.locale);// formats and sets the valuewriter.setValue(formatter.format(date));}

And the other way around... in order to unmarshall, we create a GregorianCalendar, retrieves the localized DateFormat instance, parses the string into a Date and puts this date in the originalGregorianCalendar:

public Object unmarshal(HierarchicalStreamReader reader,UnmarshallingContext context) {// creates the calendarGregorianCalendar calendar = new GregorianCalendar();// grabs the converterDateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,this.locale);// parses the string and sets the timetry {calendar.setTime(formatter.parse(reader.getValue()));} catch (ParseException e) {throw new ConversionException(e.getMessage(), e);}// returns the new objectreturn calendar;}

Note 1: remember that some DateFormat implementations are not thread-safe, therefore don't put your formatter as a member of your converter.

Note 2: this implementation will convert other types of Calendar's to GregorianCalendar after save/load. If this is not what you want, change your canConvert method to return true only if class equalsGregorianCalendar.

So we get the following converter:

package com.thoughtworks.xstream.examples;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;}public boolean canConvert(Class clazz) {return Calendar.class.isAssignableFrom(clazz);}public void marshal(Object value, HierarchicalStreamWriter writer,MarshallingContext context) {Calendar calendar = (Calendar) value;Date date = calendar.getTime();DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,this.locale);writer.setValue(formatter.format(date));}public Object unmarshal(HierarchicalStreamReader reader,UnmarshallingContext context) {GregorianCalendar calendar = new GregorianCalendar();DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,this.locale);try {calendar.setTime(formatter.parse(reader.getValue()));} catch (ParseException e) {throw new ConversionException(e.getMessage(), e);}return calendar;}}

And let's try it out. We create a DateTest class with a main method:

  1. creates a calendar (current date)

  2. creates the XStream object

  3. registers the converter with a Brazilian Portuguese locale

  4. translates the object in XML

Well, we already know how to do all those steps... so let's go:

package com.thoughtworks.xstream.examples;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 DateTest {public static void main(String[] args) {// grabs the current date from the virtual machineCalendar calendar = new GregorianCalendar();// creates the xstreamXStream xStream = new XStream(new DomDriver());// brazilian portuguese localexStream.registerConverter(new DateConverter(new Locale("pt", "br")));// prints the resultSystem.out.println(xStream.toXML(calendar));}}

The result? Well... it depends, but it will be something like:

<gregorian-calendar>Sexta-feira, 10 de Fevereiro de 2006</gregorian-calendar>

Note: we did not put any alias as gregorian-calendar is the default alias for GregorianCalendar.

And now let's try to unmarshal the result shown above:

// loads the calendar from the string
Calendar loaded = (Calendar) xStream.fromXML("<gregorian-calendar>Sexta-feira, 10 de Fevereiro de 2006</gregorian-calendar>");

And print it using the system locale, short date format:

// prints using the system defined locale
System.out.println(DateFormat.getDateInstance(DateFormat.SHORT).format(loaded.getTime()));

The result might be something like (if your system locale is American English):

2/10/06

Complex Converter

Setting up another example

We already defined some classes, so let them glue together:

package com.thoughtworks.xstream.examples;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';}}

While XStream is capable of converting this class without any problem, we write our own custom converter just for demonstration. This time we want to reuse our already written converters for the Person and the Calendar and add an own attribute for the gender. The canConvert method is plain simple. We convert no derived classes this time, since they might have additional fields. But we reuse the converters registered in XStream for our member fields and handle null values:

package com.thoughtworks.xstream.examples;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 {public boolean canConvert(Class clazz) {return Birthday.class == clazz;}public void marshal(Object value, HierarchicalStreamWriter writer,MarshallingContext context) {Birthday birthday = (Birthday)value;if (birthday.getGender() != '\0') {writer.addAttribute("gender", Character.toString(birthday.getGender()));}if (birthday.getPerson() != null) {writer.startNode("person");context.convertAnother(birthday.getPerson());writer.endNode();}if (birthday.getDate() != null) {writer.startNode("birth");context.convertAnother(birthday.getDate());writer.endNode();}}public Object unmarshal(HierarchicalStreamReader reader,UnmarshallingContext context) {Birthday birthday = new Birthday();String gender = reader.getAttribute("gender");if (gender != null) {if (gender.length() > 0) {              if (gender.char(0) == 'f') {birthday.setGenderFemale();} else if (gender.char(0) == 'm') {birthday.setFemale();} else {throw new ConversionException("Invalid gender value: " + gender);}} else {throw new ConversionException("Empty string is invalid gender value");}}while (reader.hasMoreChildren()) {reader.moveDown();if ("person".equals(reader.getNodeName())) {Person person = (Person)context.convertAnother(birthday, Person.class);birthday.setPerson(person);} else if ("birth".equals(reader.getNodeName())) {Calendar date = (Calendar)context.convertAnother(birthday, Calendar.class);birthday.setDate(date);}reader.moveUp();}return birthday;}}

The unmarshal method ensures the valid value for the gender by throwing a ConversionException for invalid entries.

Note, that attributes will always have to be written and read first. You work on a stream and accessing the value of a tag or its members will close the surrounding tag (that is still active when the method is called).

If the implementation of Birthday ensures, that none of its fields could hold a null value and gender contains a valid value, then we could drop the null condition in the marshal method and in unmarshal we could omit the loop as well as the comparison of the tag names:

package com.thoughtworks.xstream.examples;import java.util.Calendar;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 {public boolean canConvert(Class clazz) {return Birthday.class == clazz;}public void marshal(Object value, HierarchicalStreamWriter writer,MarshallingContext context) {Birthday birthday = (Birthday)value;writer.addAttribute("gender", Character.toString(birthday.getGender()));writer.startNode("person");context.convertAnother(birthday.getPerson());writer.endNode();writer.startNode("birth");context.convertAnother(birthday.getDate());writer.endNode();}public Object unmarshal(HierarchicalStreamReader reader,UnmarshallingContext context) {Birthday birthday = new Birthday();if (reader.getAttribute("gender").charAt(0) == 'm') {birthday.setGenderMale();} else {birthday.setGenderFemale();}reader.moveDown();Person person = (Person)context.convertAnother(birthday, Person.class);birthday.setPerson(person);reader.moveUp();reader.moveDown();Calendar date = (Calendar)context.convertAnother(birthday, Calendar.class);birthday.setDate(date);reader.moveUp();return birthday;}}

转载于:https://my.oschina.net/heroShane/blog/199202

Converter Tutorial相关推荐

  1. Vmware Links(转自VMware-land)

    这一阵子在专研虚拟机的VSS备份,无意中发现了VMware-land 很好的网站,不知道为什么无法访问,难道也被和谐掉了??? 以下内容是从Google的页面缓存弄出来的,在Google搜索http: ...

  2. 电子工程术语和定义列表

    按字母顺序排列: 电子工程术语和定义列表,按字母顺序排列 1-Wire 单线(加地线)通信协议. 更多信息,请参考: 1-Wire存储器产品 1-Wire接口方案 1-Wire软件工具 1-Wire ...

  3. GStreamer Tutorial 中文翻译:Basic tutorial 3: Dynamic pipelines

    GStreamer Tutorial 3中文翻译 文章目录 GStreamer Tutorial 3中文翻译 前言 [Basic tutorial 3: Dynamic pipelines](http ...

  4. 转换器(Converter)Struts 2.0中的魔术师

    转换器(Converter)--Struts 2.0中的魔术师  在我已往的Struts 1.x项目经验中,有个问题不时的出现--在创建FormBean时,对于某个属性到底应该用String还是其它类 ...

  5. 转换器(Converter)—Struts 2.0中的魔术师

    本系列文章导航 为Struts 2.0做好准备 Struts 2的基石--拦截器(Interceptor) 常用的Struts 2.0的标志(Tag)介绍 在Struts 2.0中国际化(i18n)您 ...

  6. Writing device drivers in Linux: A brief tutorial

    Writing device drivers in Linux: A brief tutorial FROM:http://www.freesoftwaremagazine.com/articles/ ...

  7. Acme CAD Converter 2015 8.7.0.1440 Multilingual 1CD CAD图形文件转换和查看软件

    Acme CAD Converter 2015 8.7.0.1440 Multilingual 1CD CAD图形文件转换和查看软件 一款专业的CAD图形文件转换和查看软件,支持DWG DXF DWF ...

  8. Python Tutorial(十):浏览标准库(一)

    10.1 操作系统接口 os模块提供很多函数用于和操作系统的交互: 确定使用import os风格而不是from os import *.这将避免os.open()被内建的open()函数遮住,它的操 ...

  9. ue5新手零基础学习教程 Unreal Engine 5 Beginner Tutorial - UE5 Starter Course

    ue5新手零基础学习教程 Unreal Engine 5 Beginner Tutorial - UE5 Starter Course! 教程大小解压后:4.96G 语言:英语+中英文字幕(机译)时长 ...

最新文章

  1. 传感器是大数据的重要来源
  2. python---基础知识回顾(五)(python2.7和python3.5中的编码)
  3. python 作用域 前缀_Python 之作用域和名字空间
  4. todo:DSB and ISB
  5. docker-compose.yml 启动jar 包
  6. boost::gil::scale_lanczos用法的测试程序
  7. 乘风破浪:LeetCode真题_038_Count and Say
  8. 为什么选择Docker?
  9. php的yii框架配置,php配置yii框架_PHP教程
  10. 面向模式的软件体系结构
  11. 模具计算机辅助设计笔试题,模具CADCAM试卷
  12. 当前音乐推荐系统研究中的挑战和愿景
  13. uni-app 使用高德地图
  14. win10安装影子系统导致的蓝屏,终止代码:BAD_SYSTEM_CONFIG
  15. 超级详细的pytest测试和allure测试报告
  16. Go语言log日志包详解及使用
  17. 【Uplift】评估方法篇
  18. 攻防世界(练习小题)
  19. 静脉炎的症状是什么?
  20. 谷歌ai人工智能叫什么_谷歌正在通过AI策展和内置订阅全面革新Google新闻

热门文章

  1. linux测试网络是否连通ping、telnet命令
  2. logback日志pattern_Logback pattern transactionid 中如何自定义灵活的日志过滤规则
  3. 为什么有时优盘是只读模式_JS专题之严格模式
  4. linux操作系统桌面应用与管理第2版,linux操作系统桌面应用与管理(62页)-原创力文档...
  5. linux用户命令快捷链接,linux简单命令
  6. 如何升级成鸿蒙,如何将自己的华为手机升级成鸿蒙系统
  7. html5中Canvas、绘制线条模糊、常见绘制工具、绘制基本图形、绘制图片、面向对象的方式绘制图形图片、绘制文本、帧动画绘制
  8. ElasticSearch范围查询(英文检索)
  9. 2021百度营销通案
  10. 面试题,你觉得XX和XX产品有何区别?