1、簡單的轉換器:
首先創建示例的環境,
下面介紹的是最基礎的轉換器,首先創建一個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;
}
}
接著,我們創建一個實例,并轉化他:
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));
}
}
如你所料,得到下面的結果:
<com.thoughtworks.xstream.examples.Person>
<name>Guilherme</name>
</com.thoughtworks.xstream.examples.Person>
下面我們為person類創建一個別名:
XStream xStream = new XStream(new DomDriver());
xStream.alias("person", Person.class);
System.out.println(xStream.toXML(person));
現在的結果就很易讀了:
<person>
<name>Guilherme</name>
</person>
到此,我們已經建立好一個可以供我們實驗的基礎例子了,下面我們來看看XStream的轉換器能為我們做些什么:
2,創建一個Person轉換器:
下面我們來創建一個簡單的轉換器,它能:
1,用來轉換Person類
2,將Person實例轉換成XML
3,將xml轉換為Person實例
首先創建一個PersonConverter類,并讓這個類實現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;
}
}
下面,我們首先告訴轉換器,我們只能轉換Person類,而不是別的類,包括其子類:
public boolean canConvert(Class clazz) {
return clazz.equals(Person.class);
}
這一步很簡單,除非你是用來處理泛型的轉換器是會困難一點。
Marshal方法是用來將對象轉換為XML的,他有三個參數:
1,我們準備轉換的對象
2,我們準備輸出對象的writer
3,當前的marshaling context
首先我們將object轉換成Person
Person person = (Person) value;
接著,我們就可以開始輸出數據了,首先我們創建一個叫做fullname的節點,并將person的名字傳給他:
writer.startNode("fullname");
writer.setValue(person.getName());
writer.endNode();
呵呵~很簡單吧,
public void marshal(Object value, HierarchicalStreamWriter writer,
MarshallingContext context) {
Person person = (Person) value;
writer.startNode("fullname");
writer.setValue(person.getName());
writer.endNode();
}
我們可以任意次數的調用start/end node方法,但需要記住,你必須在打開一個節點之后記住關閉它。一般來說,執行轉換的操作在setValue方法調用時發生。
下面,我們進入unmarshal方法,我們使用moveDown和moveUp方法在節點樹層次中移動,所以,這里我們只需要簡單的moveDown,得到值,再moveUp:
Person person = new Person();
reader.moveDown();
person.setName(reader.getValue());
reader.moveUp();
最后,我們得到了一個這樣的轉換器:
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;
}
}
接著,我們在我們的main方法中注冊這個轉化器:
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));
}
}
注意到我們怎么注冊我們的轉換器了么?只需要下面簡單的一句:
xStream.registerConverter(new PersonConverter());
最終得到的結果是:
<person>
<fullname>Guilherme</fullname>
</person>
也許你會說:這只改變了我輸出的樹,我需要用它來轉換數據。
下面我們來嘗試在person標簽中創建一個叫做fullname的屬性,而不是新創建一個節點:
3,一種可選的方式:
首先,為Person創建一個toString方法,里面包含了所有能用來重新創建一個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;
}
public String toString() {
return getName();
}
}
現在,我們就能把我們的轉化器簡寫為:
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;
}
}
現在,輸出的XML也會變得更易讀(為person創建別名person之后):
<person>Guilherme</person>
名字變成了一個內置的值,而不是一個單獨的節點。
4,轉換Date:
我們已經知道Converter接口是怎樣工作的了,現在我們來創建一個使用Locale對象轉換時間的轉換器:
在我們的轉換器構造方法中,我們將傳入一個Locale對象,該Locale對象會作為一個成員屬性被轉換器持有:
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;
}
}
現在,讓我們能轉換任何繼承了Calendar對象的類:
public boolean canConvert(Class clazz) {
return Calendar.class.isAssignableFrom(clazz);
}
首先,我們來將Calendar轉換成本地化的字符串:首先我們把object轉化成Calendar,得到Date對象,并使用DataFormatter來得到一個本地化的時間:
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方法中,我們創建了一個GregorianCalendar,得到本地化的DataFormat實例,將字符串轉換成Date對象,并賦值給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實現不是線程安全的,所以,不要讓你的轉換器持有DataFormat的引用
2,在經過了保存和加載的過程后,該轉換器可以將其他Calendar實現轉換為GregorianCalendar。如果這不是你希望的,只需要修改canConvert方法,并在類型只有為GregorianCalendar的時候再返回true。
現在,我們得到了下面這個轉換器:
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;
}
}
現在,我們來測試一下,創建一個main方法:
1,創建一個calendar,
2,創建XStream對象
3,注冊該轉換器,并使用Brazilian Portuguese本地化對象
4,將對象轉化成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));
}
}
可以得到類似如下的結果:
<gregorian-calendar>Sexta-feira, 10 de Fevereiro de 2006</gregorian-calendar>
注意,我們沒有為GregorianCalendar創建任何別名,而gregorian-calendar就是默認的名字。
下面我們來試試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()));
得到的結果為:
2/10/06
5,復雜的轉換器:
創建另一個例子:
我們已經創建了兩個對象了,現在把它們組合起來:
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;
}
}
要轉換該類,XStream一點問題都沒有。這里,我們實現自己的轉換器主要是為了驗證,在這里,我們想重用我們剛才的PersonConverter和CalendarConverter。canConvert仍然很簡單,不過這里,我們不需要再為每一個屬性重新寫轉換方法了,我們只需要使用已經注冊了的轉換器來完成轉換:
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實例能夠確保不會出現null值,那么我們就可以去掉marshal和unmarshal方法中對null情況的判斷,也不需要循環,而直接根據tag的名字進行解析:
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;
}
}