XStream Annotations 入門【翻譯】
1、簡單的轉(zhuǎn)換器:
首先創(chuàng)建示例的環(huán)境,
下面介紹的是最基礎(chǔ)的轉(zhuǎn)換器,首先創(chuàng)建一個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)建一個實例,并轉(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)建一個別名:
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)建立好一個可以供我們實驗的基礎(chǔ)例子了,下面我們來看看XStream的轉(zhuǎn)換器能為我們做些什么:
2,創(chuàng)建一個Person轉(zhuǎn)換器:
下面我們來創(chuàng)建一個簡單的轉(zhuǎn)換器,它能:
1,用來轉(zhuǎn)換Person類
2,將Person實例轉(zhuǎn)換成XML
3,將xml轉(zhuǎn)換為Person實例
首先創(chuàng)建一個PersonConverter類,并讓這個類實現(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)換器是會困難一點。
Marshal方法是用來將對象轉(zhuǎn)換為XML的,他有三個參數(shù):
1,我們準備轉(zhuǎn)換的對象
2,我們準備輸出對象的writer
3,當前的marshaling context
首先我們將object轉(zhuǎn)換成Person
Person person = (Person) value;
接著,我們就可以開始輸出數(shù)據(jù)了,首先我們創(chuàng)建一個叫做fullname的節(jié)點,并將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方法,但需要記住,你必須在打開一個節(jié)點之后記住關(guān)閉它。一般來說,執(zhí)行轉(zhuǎn)換的操作在setValue方法調(diào)用時發(fā)生。
下面,我們進入unmarshal方法,我們使用moveDown和moveUp方法在節(jié)點樹層次中移動,所以,這里我們只需要簡單的moveDown,得到值,再moveUp:
Person person = new Person(); reader.moveDown(); person.setName(reader.getValue()); reader.moveUp();
最后,我們得到了一個這樣的轉(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; } }
接著,我們在我們的main方法中注冊這個轉(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)); } }
注意到我們怎么注冊我們的轉(zhuǎn)換器了么?只需要下面簡單的一句:
xStream.registerConverter(new PersonConverter());
最終得到的結(jié)果是:
<person>
<fullname>Guilherme</fullname>
</person>
也許你會說:這只改變了我輸出的樹,我需要用它來轉(zhuǎn)換數(shù)據(jù)。
下面我們來嘗試在person標簽中創(chuàng)建一個叫做fullname的屬性,而不是新創(chuàng)建一個節(jié)點:
3,一種可選的方式:
首先,為Person創(chuàng)建一個toString方法,里面包含了所有能用來重新創(chuàng)建一個Person實例的數(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也會變得更易讀(為person創(chuàng)建別名person之后):
<person>Guilherme</person>
名字變成了一個內(nèi)置的值,而不是一個單獨的節(jié)點。
4,轉(zhuǎn)換Date:
我們已經(jīng)知道Converter接口是怎樣工作的了,現(xiàn)在我們來創(chuàng)建一個使用Locale對象轉(zhuǎn)換時間的轉(zhuǎn)換器:
在我們的轉(zhuǎn)換器構(gòu)造方法中,我們將傳入一個Locale對象,該Locale對象會作為一個成員屬性被轉(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對象的類:
public boolean canConvert(Class clazz) {
return Calendar.class.isAssignableFrom(clazz);
}
首先,我們來將Calendar轉(zhuǎn)換成本地化的字符串:首先我們把object轉(zhuǎn)化成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方法中,我們創(chuàng)建了一個GregorianCalendar,得到本地化的DataFormat實例,將字符串轉(zhuǎn)換成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實現(xiàn)不是線程安全的,所以,不要讓你的轉(zhuǎn)換器持有DataFormat的引用
2,在經(jīng)過了保存和加載的過程后,該轉(zhuǎn)換器可以將其他Calendar實現(xiàn)轉(zhuǎn)換為GregorianCalendar。如果這不是你希望的,只需要修改canConvert方法,并在類型只有為GregorianCalendar的時候再返回true。
現(xiàn)在,我們得到了下面這個轉(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)建一個main方法:
1,創(chuàng)建一個calendar,
2,創(chuàng)建XStream對象
3,注冊該轉(zhuǎn)換器,并使用Brazilian Portuguese本地化對象
4,將對象轉(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就是默認的名字。
下面我們來試試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)建另一個例子:
我們已經(jīng)創(chuàng)建了兩個對象了,現(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一點問題都沒有。這里,我們實現(xiàn)自己的轉(zhuǎn)換器主要是為了驗證,在這里,我們想重用我們剛才的PersonConverter和CalendarConverter。canConvert仍然很簡單,不過這里,我們不需要再為每一個屬性重新寫轉(zhuǎn)換方法了,我們只需要使用已經(jīng)注冊了的轉(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實例能夠確保不會出現(xiàn)null值,那么我們就可以去掉marshal和unmarshal方法中對null情況的判斷,也不需要循環(huán),而直接根據(jù)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; } }
posted on 2010-09-07 21:24 w@ns0ng 閱讀(518) 評論(0) 編輯 收藏 所屬分類: java