【我在项目组使用的是xstream-1.4.3.jar】
最近在项目中遇到了JAVA bean 和XML互转的需求, 本来准备循规蹈矩使用dom4j忽然想起来之前曾接触过的XStream, 一番研究豁然开朗,利器啊利器, 下来就XStream的一些用法与大家分享。
XStream是大名鼎鼎的thought works下的一个开源项目, 主要功能是提供JAVA bean 和XML文本之间的转换,另外还提供JAVA bean和JSON之间的转换,这个不在本次讨论的范围内。
XStream进行转换是非常简单的,对JAVA bean没有任何要求:
package xstreamTest; public class Person { private String name; private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } }转换代码是这样的:
XStream xstream = new XStream(); Person person = new Person(); person.setName("pli"); person.setAge(18); System.out.println(xstream.toXML(person));我们得到了这样的结果:
<xstreamTest.Person> <name>pli</name> <age>18</age> </xstreamTest.Person>
package xstreamTest; @XStreamAlias("person") public class Person { private String name; private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } }而执行代码会变成这样:
XStream xstream = new XStream(); xstream.autodetectAnnotations(true); Person person = new Person(); person.setName("pli"); person.setAge(18); System.out.println(xstream.toXML(person));这样我们就得到了想要的:
<person> <name>pli</name> <age>18</age> </person>
@XStreamAlias("person") public class Person { private String name; @XStreamAsAttribute private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } }结果是这样的:
<person age="18"> <name>pli</name> </person>好玩吧。
@XStreamAlias("person") public class Person { private String name; @XStreamAsAttribute private int age; List<String> girlFriends; public List<String> getGirlFriends() { return girlFriends; } public void setGirlFriends(List<String> girlFriends) { this.girlFriends = girlFriends; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } }直接转换我们会得到这样的结果:
<person age="18"> <name>pli</name> <girlFriends> <string>YuanYuanGao</string> <string>QiShu</string> <string>BoZhiZhang</string> </girlFriends> </person>结果其实也不赖,XStream在这里提供了一个@XStreamImplicit(itemFieldName=***)的annotation来满足用户想将List的根节点去掉和改变列表名字的需求,对应到我们的例子上就是去掉<girlFriends>标签和改变"<string>".我们来看看效果。
@XStreamAlias("person") public class Person { private String name; @XStreamAsAttribute private int age; @XStreamImplicit(itemFieldName="girl") List<String> girlFriends; public List<String> getGirlFriends() { return girlFriends; } public void setGirlFriends(List<String> girlFriends) { this.girlFriends = girlFriends; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } }结果是这样:
<person age="18"> <name>pli</name> <girl>YuanYuanGao</girl> <girl>QiShu</girl> <girl>BoZhiZhang</girl> </person>
@XStreamAlias("person") public class Person { private String name; @XStreamAsAttribute private int age; @XStreamImplicit(itemFieldName="girl") @XStreamOmitField List<String> girlFriends; public List<String> getGirlFriends() { return girlFriends; } public void setGirlFriends(List<String> girlFriends) { this.girlFriends = girlFriends; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } }结果是这样:
<person age="18"> <name>pli</name> </person>
@XStreamAlias("person") public class Person { private String name; @XStreamAsAttribute private int age; @XStreamImplicit(itemFieldName="girl") @XStreamOmitField List<String> girlFriends; Date birthday; public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public List<String> getGirlFriends() { return girlFriends; } public void setGirlFriends(List<String> girlFriends) { this.girlFriends = girlFriends; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } }看看直接序列化的结果:
<person age="18"> <name>pli</name> <birthday>2012-08-04 04:35:01.857 UTC</birthday> </person>还不错,但是生日只需要年月日就行了,没必要精确到毫秒,这怎么办呢,只能使用converter,我们这是就需要写代码了。
public class DateConverter implements Converter { @Override public boolean canConvert(Class clazz) { return (Date.class).equals(clazz); } @Override public void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { Date date = (Date) object; Calendar calendar = Calendar.getInstance(); calendar.setTime(date); SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd"); writer.setValue(format.format(calendar.getTime())); } @Override public Object unmarshal(HierarchicalStreamReader arg0, UnmarshallingContext arg1) { return null; } }
@XStreamAlias("person") public class Person { private String name; @XStreamAsAttribute private int age; @XStreamImplicit(itemFieldName="girl") @XStreamOmitField List<String> girlFriends; @XStreamConverter(value=DateConverter.class) Date birthday; public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public List<String> getGirlFriends() { return girlFriends; } public void setGirlFriends(List<String> girlFriends) { this.girlFriends = girlFriends; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } }看看结果:
<person age="18"> <name>pli</name> <birthday>2012-50-04</birthday> </person>
public class Person { private String firstname; private String lastname; private PhoneNumber phone; private PhoneNumber fax; public Person() { super(); } public Person(String firstname, String lastname) { super(); this.firstname = firstname; this.lastname = lastname; } public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } public PhoneNumber getPhone() { return phone; } public void setPhone(PhoneNumber phone) { this.phone = phone; } public PhoneNumber getFax() { return fax; } public void setFax(PhoneNumber fax) { this.fax = fax; } @Override public String toString() { return "Person [firstname=" + firstname + ", lastname=" + lastname + ", phone=" + phone + ", fax=" + fax + "]"; } }PhoneNumber javabean类
public class PhoneNumber { private int code; private String number; public PhoneNumber() { super(); } public PhoneNumber(int code, String number) { super(); this.code = code; this.number = number; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } @Override public String toString() { return "PhoneNumber [ code =" + code + ", number=" + number + "]"; }转换测试类
public class ConvertTest { /** * 将Person转换成xml字符串 */ @Test public void personToXML() { XStream xstream = new XStream(); xstream.alias("person", Person.class); xstream.alias("phonenumber", PhoneNumber.class); Person joe = new Person("Joe", "Walnes"); joe.setPhone(new PhoneNumber(123, "1234-456")); joe.setFax(new PhoneNumber(123, "9999-999")); String xml = xstream.toXML(joe); System.out.println(xml); } }xstream.alias("person", Person.class);
<person> <firstname>Joe</firstname> <lastname>Walnes</lastname> <phone> <code>123</code> <number>1234-456</number> </phone> <fax> <code>123</code> <number>9999-999</number> </fax> </person>
@Test public void xmlToPerson() { String site = "CAN"; XStream xstream = new XStream(); xstream.alias("person", Person.class); xstream.alias("phonenumber", PhoneNumber.class); String xml = "<person><firstname>Joe</firstname><lastname>Walnes</lastname><phone><code>123</code><number>1234-456</number></phone><fax><code>123</code><number>9999-999</number></fax></person>"; xstream.omitField(Person.class, site); Person newJoe = (Person) xstream.fromXML(xml); System.out.println(newJoe.toString()); }
@XStreamAlias("person") public class Person { private String name = "pli"; @XStreamAsAttribute private int age = 19; @XStreamImplicit(itemFieldName="girl") @XStreamOmitField List<String> girlFriends; @XStreamConverter(value=DateConverter.class) Date birthday = new Date(); public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public List<String> getGirlFriends() { return girlFriends; } public void setGirlFriends(List<String> girlFriends) { this.girlFriends = girlFriends; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void setName(String name) { this.name = name; } public String getName() { return this.name; } }我想将其它属性都进行了初始化但是没有将girlFriends这个属性初始化,即使说girlFriends==null. 序列化以后会怎样呢?
<person age="18"> <name>pli</name> <birthday>2012-36-04</birthday> </person>girlFriends这个属性压根就没有被序列化,其实我是想让它序列化成这个样子:
<person age="18"> <name>pli</name> <birthday>2012-36-04</birthday> <girlFriends/> </person>
package com.openeap.webservice.base; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Date; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.openeap.modules.taskBoard.entity.TaskBoardSjToQd; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; public class XmlUtil { private static Logger log = LoggerFactory.getLogger(XmlUtil.class); /** * java 转换成xml * * @Title: toXml * @Description: TODO * @param obj * 对象实例 * @return String xml字符串 */ public static String toXml(Object obj) { XStream xstream = new XStream(); // XStream xstream=new XStream(new DomDriver()); //直接用jaxp dom来解释 // XStream xstream=new XStream(new DomDriver("utf-8")); // //指定编码解析器,直接用jaxp dom来解释 // //如果没有这句,xml中的根元素会是<包.类名>;或者说:注解根本就没生效,所以的元素名就是类的属性 xstream.processAnnotations(obj.getClass()); // 通过注解方式的,一定要有这句话 return xstream.toXML(obj); } /** * 将传入xml文本转换成Java对象 * * @Title: toBean * @Description: TODO * @param xmlStr * @param cls * xml对应的class类 * @return T xml对应的class类的实例对象 * * 调用的方法实例:PersonBean person=XmlUtil.toBean(xmlStr, * PersonBean.class); */ public static <T> T toBean(String xmlStr, Class<T> cls) { // 注意:不是new Xstream(); 否则报错:java.lang.NoClassDefFoundError: // org/xmlpull/v1/XmlPullParserFactory XStream xstream = new XStream(new DomDriver()); xstream.alias(cls.getSimpleName(), cls); //xstream.processAnnotations(cls); T obj = (T) xstream.fromXML(xmlStr); return obj; } /** * 写到xml文件中去 * * @Title: writeXMLFile * @Description: TODO * @param obj * 对象 * @param absPath * 绝对路径 * @param fileName * 文件名 * @return boolean */ public static boolean toXMLFile(Object obj, String absPath, String fileName) { String strXml = toXml(obj); String filePath = absPath + fileName; File file = new File(filePath); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { log.error("创建{" + filePath + "}文件失败!!!"); return false; } }// end if OutputStream ous = null; try { ous = new FileOutputStream(file); ous.write(strXml.getBytes()); ous.flush(); } catch (Exception e1) { log.error("写{" + filePath + "}文件失败!!!"); return false; } finally { if (ous != null) try { ous.close(); } catch (IOException e) { log.error("写{" + filePath + "}文件关闭输出流异常!!!"); } } return true; } /** * 从xml文件读取报文 * * @Title: toBeanFromFile * @Description: TODO * @param absPath * 绝对路径 * @param fileName * 文件名 * @param cls * @throws Exception * @return T */ public static <T> T toBeanFromFile(String filePath, Class<T>[] cls) throws Exception { //String filePath = absPath + fileName; InputStream ins = null; try { ins = new FileInputStream(new File(filePath)); } catch (Exception e) { throw new Exception("读{" + filePath + "}文件失败!", e); } String encode = "UTF-8";// useEncode(cls); XStream xstream = new XStream(new DomDriver(encode)); xstream.processAnnotations(cls); /*for(Class tempCls : cls){ xstream.alias(tempCls.getSimpleName(), tempCls); }*/ T obj = null; try { obj = (T) xstream.fromXML(ins); } catch (Exception e) { // TODO Auto-generated catch block throw new Exception("解析{" + filePath + "}文件失败!", e); } if (ins != null) ins.close(); return obj; } public static void main(String[] args) { // TODO Auto-generated method stub } }