1、簡(jiǎn)單的轉(zhuǎn)換器:
首先創(chuàng)建示例的環(huán)境,
下面介紹的是最基礎(chǔ)的轉(zhuǎn)換器,首先創(chuàng)建一個(gè)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;
}
}
接著,我們創(chuàng)建一個(gè)實(shí)例,并轉(zhuǎn)化他:
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));
}
}
如你所料,得到下面的結(jié)果:
<com.thoughtworks.xstream.examples.Person>
<name>Guilherme</name>
</com.thoughtworks.xstream.examples.Person>
下面我們?yōu)閜erson類創(chuàng)建一個(gè)別名:
XStream xStream = new XStream(new DomDriver());
xStream.alias("person", Person.class);
System.out.println(xStream.toXML(person));
現(xiàn)在的結(jié)果就很易讀了:
<person>
<name>Guilherme</name>
</person>
到此,我們已經(jīng)建立好一個(gè)可以供我們實(shí)驗(yàn)的基礎(chǔ)例子了,下面我們來(lái)看看XStream的轉(zhuǎn)換器能為我們做些什么:
2,創(chuàng)建一個(gè)Person轉(zhuǎn)換器:
下面我們來(lái)創(chuàng)建一個(gè)簡(jiǎn)單的轉(zhuǎn)換器,它能:
1,用來(lái)轉(zhuǎn)換Person類
2,將Person實(shí)例轉(zhuǎn)換成XML
3,將xml轉(zhuǎn)換為Person實(shí)例
首先創(chuàng)建一個(gè)PersonConverter類,并讓這個(gè)類實(shí)現(xiàn)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 false;
}
public void marshal(Object value, HierarchicalStreamWriter writer,
MarshallingContext context) {
}
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
return null;
}
}
下面,我們首先告訴轉(zhuǎn)換器,我們只能轉(zhuǎn)換Person類,而不是別的類,包括其子類:
public boolean canConvert(Class clazz) {
return clazz.equals(Person.class);
}
這一步很簡(jiǎn)單,除非你是用來(lái)處理泛型的轉(zhuǎn)換器是會(huì)困難一點(diǎn)。
Marshal方法是用來(lái)將對(duì)象轉(zhuǎn)換為XML的,他有三個(gè)參數(shù):
1,我們準(zhǔn)備轉(zhuǎn)換的對(duì)象
2,我們準(zhǔn)備輸出對(duì)象的writer
3,當(dāng)前的marshaling context
首先我們將object轉(zhuǎn)換成Person
Person person = (Person) value;
接著,我們就可以開始輸出數(shù)據(jù)了,首先我們創(chuàng)建一個(gè)叫做fullname的節(jié)點(diǎn),并將person的名字傳給他:
writer.startNode("fullname");
writer.setValue(person.getName());
writer.endNode();
呵呵~很簡(jiǎn)單吧,
public void marshal(Object value, HierarchicalStreamWriter writer,
MarshallingContext context) {
Person person = (Person) value;
writer.startNode("fullname");
writer.setValue(person.getName());
writer.endNode();
}
我們可以任意次數(shù)的調(diào)用start/end node方法,但需要記住,你必須在打開一個(gè)節(jié)點(diǎn)之后記住關(guān)閉它。一般來(lái)說(shuō),執(zhí)行轉(zhuǎn)換的操作在setValue方法調(diào)用時(shí)發(fā)生。
下面,我們進(jìn)入unmarshal方法,我們使用moveDown和moveUp方法在節(jié)點(diǎn)樹層次中移動(dòng),所以,這里我們只需要簡(jiǎn)單的moveDown,得到值,再moveUp:
Person person = new Person();
reader.moveDown();
person.setName(reader.getValue());
reader.moveUp();
最后,我們得到了一個(gè)這樣的轉(zhuǎn)換器:
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;
}
}
接著,我們?cè)谖覀兊膍ain方法中注冊(cè)這個(gè)轉(zhuǎn)化器:
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));
}
}
注意到我們?cè)趺醋?cè)我們的轉(zhuǎn)換器了么?只需要下面簡(jiǎn)單的一句:
xStream.registerConverter(new PersonConverter());
最終得到的結(jié)果是:
<person>
<fullname>Guilherme</fullname>
</person>
也許你會(huì)說(shuō):這只改變了我輸出的樹,我需要用它來(lái)轉(zhuǎn)換數(shù)據(jù)。
下面我們來(lái)嘗試在person標(biāo)簽中創(chuàng)建一個(gè)叫做fullname的屬性,而不是新創(chuàng)建一個(gè)節(jié)點(diǎn):
3,一種可選的方式:
首先,為Person創(chuàng)建一個(gè)toString方法,里面包含了所有能用來(lái)重新創(chuàng)建一個(gè)Person實(shí)例的數(shù)據(jù):
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();
}
}
現(xiàn)在,我們就能把我們的轉(zhuǎn)化器簡(jiǎn)寫為:
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;
}
}
現(xiàn)在,輸出的XML也會(huì)變得更易讀(為person創(chuàng)建別名person之后):
<person>Guilherme</person>
名字變成了一個(gè)內(nèi)置的值,而不是一個(gè)單獨(dú)的節(jié)點(diǎn)。
4,轉(zhuǎn)換Date:
我們已經(jīng)知道Converter接口是怎樣工作的了,現(xiàn)在我們來(lái)創(chuàng)建一個(gè)使用Locale對(duì)象轉(zhuǎn)換時(shí)間的轉(zhuǎn)換器:
在我們的轉(zhuǎn)換器構(gòu)造方法中,我們將傳入一個(gè)Locale對(duì)象,該Locale對(duì)象會(huì)作為一個(gè)成員屬性被轉(zhuǎn)換器持有:
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;
}
}
現(xiàn)在,讓我們能轉(zhuǎn)換任何繼承了Calendar對(duì)象的類:
public boolean canConvert(Class clazz) {
return Calendar.class.isAssignableFrom(clazz);
}
首先,我們來(lái)將Calendar轉(zhuǎn)換成本地化的字符串:首先我們把object轉(zhuǎn)化成Calendar,得到Date對(duì)象,并使用DataFormatter來(lái)得到一個(gè)本地化的時(shí)間:
public void marshal(Object value, HierarchicalStreamWriter writer,
MarshallingContext context) {
Calendar calendar = (Calendar) value;
// grabs the date
Date date = calendar.getTime();
// grabs the formatter
DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
this.locale);
// formats and sets the value
writer.setValue(formatter.format(date));
}
另一方面,在unmarshall方法中,我們創(chuàng)建了一個(gè)GregorianCalendar,得到本地化的DataFormat實(shí)例,將字符串轉(zhuǎn)換成Date對(duì)象,并賦值給GregorianCalendar。
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
// creates the calendar
GregorianCalendar calendar = new GregorianCalendar();
// grabs the converter
DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
this.locale);
// parses the string and sets the time
try {
calendar.setTime(formatter.parse(reader.getValue()));
} catch (ParseException e) {
throw new ConversionException(e.getMessage(), e);
}
// returns the new object
return calendar;
}
注意:
1,記住一些DataFormat實(shí)現(xiàn)不是線程安全的,所以,不要讓你的轉(zhuǎn)換器持有DataFormat的引用
2,在經(jīng)過(guò)了保存和加載的過(guò)程后,該轉(zhuǎn)換器可以將其他Calendar實(shí)現(xiàn)轉(zhuǎn)換為GregorianCalendar。如果這不是你希望的,只需要修改canConvert方法,并在類型只有為GregorianCalendar的時(shí)候再返回true。
現(xiàn)在,我們得到了下面這個(gè)轉(zhuǎn)換器:
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;
}
}
現(xiàn)在,我們來(lái)測(cè)試一下,創(chuàng)建一個(gè)main方法:
1,創(chuàng)建一個(gè)calendar,
2,創(chuàng)建XStream對(duì)象
3,注冊(cè)該轉(zhuǎn)換器,并使用Brazilian Portuguese本地化對(duì)象
4,將對(duì)象轉(zhuǎn)化成XML
代碼如下:
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 machine
Calendar calendar = new GregorianCalendar();
// creates the xstream
XStream xStream = new XStream(new DomDriver());
// brazilian portuguese locale
xStream.registerConverter(new DateConverter(new Locale("pt", "br")));
// prints the result
System.out.println(xStream.toXML(calendar));
}
}
可以得到類似如下的結(jié)果:
<gregorian-calendar>Sexta-feira, 10 de Fevereiro de 2006</gregorian-calendar>
注意,我們沒(méi)有為GregorianCalendar創(chuàng)建任何別名,而gregorian-calendar就是默認(rèn)的名字。
下面我們來(lái)試試unmarshal 方法:
// loads the calendar from the string
Calendar loaded = (Calendar) xStream
.fromXML("<gregorian-calendar>Sexta-feira, 10 de Fevereiro de 2006</gregorian-calendar>");
然后打印出該日期:
// prints using the system defined locale
System.out.println(DateFormat.getDateInstance(DateFormat.SHORT).format(
loaded.getTime()));
得到的結(jié)果為:
2/10/06
5,復(fù)雜的轉(zhuǎn)換器:
創(chuàng)建另一個(gè)例子:
我們已經(jīng)創(chuàng)建了兩個(gè)對(duì)象了,現(xiàn)在把它們組合起來(lái):
package com.thoughtworks.xstream.examples;
public class Birthday {
private Person person;
private Calendar date;
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;
}
}
要轉(zhuǎn)換該類,XStream一點(diǎn)問(wèn)題都沒(méi)有。這里,我們實(shí)現(xiàn)自己的轉(zhuǎn)換器主要是為了驗(yàn)證,在這里,我們想重用我們剛才的PersonConverter和CalendarConverter。canConvert仍然很簡(jiǎn)單,不過(guò)這里,我們不需要再為每一個(gè)屬性重新寫轉(zhuǎn)換方法了,我們只需要使用已經(jīng)注冊(cè)了的轉(zhuǎn)換器來(lái)完成轉(zhuǎn)換:
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;
if (value.getPerson() != null) {
writer.startNode("person");
context.convertAnother(value.getPerson());
writer.endNode();
}
if (value.getDate() != null) {
writer.startNode("birth");
context.convertAnother(value.getDate());
writer.endNode();
}
}
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
Birthday birthday = new Birthday();
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;
}
}
如果birthday實(shí)例能夠確保不會(huì)出現(xiàn)null值,那么我們就可以去掉marshal和unmarshal方法中對(duì)null情況的判斷,也不需要循環(huán),而直接根據(jù)tag的名字進(jìn)行解析:
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.startNode("person");
context.convertAnother(value.getPerson());
writer.endNode();
writer.startNode("birth");
context.convertAnother(value.getDate());
writer.endNode();
}
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
Birthday birthday = new Birthday();
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;
}
}