XStream Annotations 入門【翻譯】
1、簡單的轉(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ǔ)例子了,下面我們來看看XStream的轉(zhuǎn)換器能為我們做些什么:
2,創(chuàng)建一個(gè)Person轉(zhuǎn)換器:
下面我們來創(chuàng)建一個(gè)簡單的轉(zhuǎn)換器,它能:
1,用來轉(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); }
這一步很簡單,除非你是用來處理泛型的轉(zhuǎn)換器是會(huì)困難一點(diǎn)。
Marshal方法是用來將對(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();
呵呵~很簡單吧,
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)閉它。一般來說,執(zhí)行轉(zhuǎn)換的操作在setValue方法調(diào)用時(shí)發(fā)生。
下面,我們進(jìn)入unmarshal方法,我們使用moveDown和moveUp方法在節(jié)點(diǎn)樹層次中移動(dòng),所以,這里我們只需要簡單的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)換器了么?只需要下面簡單的一句:
xStream.registerConverter(new PersonConverter());
最終得到的結(jié)果是:
<person>
<fullname>Guilherme</fullname>
</person>
也許你會(huì)說:這只改變了我輸出的樹,我需要用它來轉(zhuǎn)換數(shù)據(jù)。
下面我們來嘗試在person標(biāo)簽中創(chuàng)建一個(gè)叫做fullname的屬性,而不是新創(chuàng)建一個(gè)節(jié)點(diǎn):
3,一種可選的方式:
首先,為Person創(chuàng)建一個(gè)toString方法,里面包含了所有能用來重新創(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)化器簡寫為:
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)在我們來創(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);
}
首先,我們來將Calendar轉(zhuǎn)換成本地化的字符串:首先我們把object轉(zhuǎn)化成Calendar,得到Date對(duì)象,并使用DataFormatter來得到一個(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)過了保存和加載的過程后,該轉(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)在,我們來測試一下,創(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>
注意,我們沒有為GregorianCalendar創(chuàng)建任何別名,而gregorian-calendar就是默認(rèn)的名字。
下面我們來試試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)在把它們組合起來:
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)問題都沒有。這里,我們實(shí)現(xiàn)自己的轉(zhuǎn)換器主要是為了驗(yàn)證,在這里,我們想重用我們剛才的PersonConverter和CalendarConverter。canConvert仍然很簡單,不過這里,我們不需要再為每一個(gè)屬性重新寫轉(zhuǎn)換方法了,我們只需要使用已經(jīng)注冊(cè)了的轉(zhuǎn)換器來完成轉(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; } }
posted on 2010-09-07 21:24 w@ns0ng 閱讀(518) 評(píng)論(0) 編輯 收藏 所屬分類: java