Jaxb2 转换XML文档
——完成Java对象和XML相互转换
前面有介绍过json-lib这个框架,在线博文:http://www.cnblogs.com/hoojo/archive/2011/04/21/2023805.html
以及Jackson这个框架,在线博文:http://www.cnblogs.com/hoojo/archive/2011/04/22/2024628.html
它们都可以完成Java对象到XML的转换,但是还不是那么的完善。
还有XStream对JSON及XML的支持,它可以对JSON或XML的完美转换。在线博文:
http://www.cnblogs.com/hoojo/archive/2011/04/22/2025197.html
以及介绍Castor来完成Java对象到xml的相互转换。在线博文:http://www.cnblogs.com/hoojo/archive/2011/04/25/2026819.html
这次介绍Jaxb2完成xml的转换,Jaxb2使用了JDK的新特性。如:Annotation、GenericType等,Jaxb2需要在即将转换的JavaBean中添加annotation注解。下面我们就来看看Jaxb2是怎么样完成Java对象到XML之间的相互转换吧。
一、 准备工作
1、 资源准备
a) 官方文档:http://www.oracle.com/technetwork/articles/javase/index-140168.html
b) Jar包下载:http://jaxb.java.net/2.2.3/JAXB2_20101209.jar
如果你有添加jdk的jar到工程中,在rt.jar中就带有jaxb2。一般情况下不用自己添加jaxb2的jar。
2、 程序前代码准备
package com.hoo.test;import java.io.IOException;import java.io.StringReader;import java.io.StringWriter;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.xml.bind.JAXBContext;import javax.xml.bind.JAXBException;import javax.xml.bind.Marshaller;import javax.xml.bind.Unmarshaller;import org.junit.After;import org.junit.Before;import org.junit.Test;import com.hoo.entity.Account;import com.hoo.entity.AccountBean;import com.hoo.entity.Birthday;import com.hoo.entity.ListBean;import com.hoo.entity.MapBean;/** * function:Jaxb2 完成Java和XML的编组、解组 * @author hoojo * @createDate 2011-4-25 上午11:54:06 * @file Jaxb2Test.java * @package com.hoo.test * @project WebHttpUtils * @blog http://blog.csdn.net/IBM_hoojo * @email hoojo_@126.com * @version 1.0 */public class Jaxb2Test {
    private JAXBContext context = null;    private StringWriter writer = null;    private StringReader reader = null;    private AccountBean bean = null;@Before
public void init() {
        bean = new AccountBean();        bean.setAddress("北京");        bean.setEmail("email");bean.setId(1);
        bean.setName("jack");        Birthday day = new Birthday();        day.setBirthday("2010-11-22");bean.setBirthday(day);
        try {            context = JAXBContext.newInstance(AccountBean.class);        } catch (Exception e) {e.printStackTrace();
}
}
@After
public void destory() {
context = null;
bean = null;
        try {            if (writer != null) {writer.flush();
writer.close();
}
            if (reader != null) {reader.close();
}
        } catch (IOException e) {e.printStackTrace();
}
System.gc();
}
public void fail(Object o) {
System.out.println(o);
}
public void failRed(Object o) {
System.err.println(o);
}
}
通过JAXBContext的newInstance方法,传递一个class就可以获得一个上下文。 newInstance方法也可以传递一个xml的文件的path。通过xml文件,对class的描述进行转换。然后,就可以通过这个上下文的来创建一个Marshaller,通过Marshaller对象的marshal方法就可以转换JavaBean对象到xml。同样JAXBContext也可以创建一个Unmarshall的unmarshal方法可以进行xml到Java对象的解组。
二、 对Java编组、XML解组
1、 JavaBean和XML的相互转换
代码如下:
@Test
public void testBean2XML() {
    try {        //下面代码演示将对象转变为xmlMarshaller mar = context.createMarshaller();
        writer = new StringWriter();mar.marshal(bean, writer);
fail(writer);
        //下面代码演示将上面生成的xml转换为对象        reader = new StringReader(writer.toString());Unmarshaller unmar = context.createUnmarshaller();
bean = (AccountBean)unmar.unmarshal(reader);
fail(bean);
    } catch (JAXBException e) {e.printStackTrace();
}
}
上面的context是在init方法中创建的,它传递了一个AccountBean的class,这个AccountBean不是一般的普通的bean。除了它带有getter、setter方法外,还有Annotation注解。下面我们就看看这个bean的代码。
package com.hoo.entity;import javax.xml.bind.annotation.XmlAttribute;import javax.xml.bind.annotation.XmlRootElement;import com.sun.xml.internal.txw2.annotation.XmlElement;@XmlRootElement(name = "account")public class AccountBean {
private int id;
    private String name;    private String email;    private String address;    private Birthday birthday;@XmlElement
    public Birthday getBirthday() {        return birthday;}
public void setBirthday(Birthday birthday) {
        this.birthday = birthday;}
    @XmlAttribute(name = "number")public int getId() {
        return id;}
public void setId(int id) {
        this.id = id;}
@XmlElement
    public String getName() {        return name;}
public void setName(String name) {
        this.name = name;}
@XmlElement
    public String getEmail() {        return email;}
public void setEmail(String email) {
        this.email = email;}
@XmlElement
    public String getAddress() {        return address;}
public void setAddress(String address) {
        this.address = address;}
@Override
    public String toString() {return this.name + "#" + this.id + "#" + this.address + "#" + this.birthday + "#" + this.email;
}
}
上面的XmlRootElement是设置当前对象转换成xml后的根节点,name的值是设置根节点的名称。在getter方法上设置XmlElement表示这个方法对应的属性是一个xml元素,如果这个注解还设置了name,那么这个name就是转换后xml的名称。在一个属性上设置XmlAttribute,表示这个方法对应的属性在转换xml后是父元素的一个属性。XmlAttribute的name就是转换后xml的属性的name。
运行后,结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><account number="1"><address>北京</address>
<birthday><birthday>2010-11-22</birthday></birthday><email>email</email><name>jack</name></account>
jack#1#北京#2010-11-22#email
把转换后的xml和上面的AccountBean对应看看
2、 对List类型对象,进行编组、解组
@Test
public void testList2XML() {
    ListBean listBean = new ListBean();    listBean.setName("list to xml");    List<Object> list = new ArrayList<Object>();list.add(bean);
    bean = new AccountBean();    bean.setAddress("china");    bean.setEmail("tom@125.com");bean.setId(2);
    bean.setName("tom");Birthday day = new Birthday("2010-11-22");
bean.setBirthday(day);
    Account acc = new Account();    acc.setAddress("china");    acc.setEmail("tom@125.com");acc.setId(2);
    acc.setName("tom");day = new Birthday("2010-11-22");
acc.setBirthday(day);
list.add(bean);
list.add(acc);
listBean.setList(list);
    try {        context = JAXBContext.newInstance(ListBean.class);        //下面代码演示将对象转变为xmlMarshaller mar = context.createMarshaller();
        writer = new StringWriter();mar.marshal(listBean, writer);
fail(writer);
        //下面代码演示将上面生成的xml转换为对象        reader = new StringReader(writer.toString());Unmarshaller unmar = context.createUnmarshaller();
listBean = (ListBean)unmar.unmarshal(reader);
fail(listBean.getList().get(0));
fail(listBean.getList().get(1));
fail(listBean.getList().get(2));
    } catch (JAXBException e) {e.printStackTrace();
}
}
你不能直接new 一个List,然后将对象放到List中。进行编组、解组,这样会出现异常情况的。你需要构建一个JavaBean,在bean中创建一个List的属性。然后在这个属性的getter方法上进行Annotation注解。下面我们看看ListBean的代码:
package com.hoo.entity;import java.util.List;import javax.xml.bind.annotation.XmlAttribute;import javax.xml.bind.annotation.XmlElement;import javax.xml.bind.annotation.XmlElements;import javax.xml.bind.annotation.XmlRootElement;@SuppressWarnings("unchecked")@XmlRootElement(name = "list-bean")public class ListBean {
    private String name;    private List list;    @XmlElements({@XmlElement(name = "account", type = Account.class),
@XmlElement(name = "bean", type = AccountBean.class)
})
    public List getList() {        return list;}
public void setList(List list) {
        this.list = list;}
@XmlAttribute
    public String getName() {        return name;}
public void setName(String name) {
        this.name = name;}
}
XmlElements表示是一个集合类型,然后注解在集合中存放上面类型的对象。
XmlElement表示在集合中存放的一个对象类型和元素名称。
转换后结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<list-bean name="list to xml">
<bean number="1"><address>北京</address><birthday><birthday>2010-11-22</birthday></birthday>
<email>email</email><name>jack</name></bean>
<bean number="2"><address>china</address><birthday><birthday>2010-11-22</birthday></birthday>
<email>tom@125.com</email><name>tom</name></bean>
<account><address>china</address><birthday><birthday>2010-11-22</birthday></birthday>
<email>tom@125.com</email><id>2</id><name>tom</name></account>
</list-bean>
jack#1#北京#2010-11-22#email
tom#2#china#2010-11-22#tom@125.com2#tom#tom@125.com#china#2010-11-22转换后的XML和Bean的注解的描述是一样的吧。
2、 对Map集合进行解组、编组
/** * <b>function:</b>Map需要自己实现,可以构造一个简单的Map对象实现 * http://metro.1045641.n5.nabble.com/Does-JAXB-2-0-support-Map-td1058084.html * @author hoojo * @createDate 2010-12-1 上午10:23:26 */@Test
public void testMap2XML() {
    MapBean mapBean = new MapBean();    HashMap<String, AccountBean> map = new HashMap<String, AccountBean>();    map.put("NO1", bean);    bean = new AccountBean();    bean.setAddress("china");    bean.setEmail("tom@125.com");bean.setId(2);
    bean.setName("tom");Birthday day = new Birthday("2010-11-22");
bean.setBirthday(day);
    map.put("NO2", bean);mapBean.setMap(map);
    try {        context = JAXBContext.newInstance(MapBean.class);        //下面代码演示将对象转变为xmlMarshaller mar = context.createMarshaller();
        writer = new StringWriter();mar.marshal(mapBean, writer);
fail(writer);
        //下面代码演示将上面生成的xml转换为对象        reader = new StringReader(writer.toString());Unmarshaller unmar = context.createUnmarshaller();
mapBean = (MapBean)unmar.unmarshal(reader);
fail(mapBean.getMap());
    } catch (JAXBException e) {e.printStackTrace();
}
}
下面看看MapBean的代码
package com.hoo.entity;import java.util.HashMap;import javax.xml.bind.annotation.XmlRootElement;import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;import com.hoo.util.MapAdapter;@XmlRootElement
public class MapBean {
    private HashMap<String, AccountBean> map;    @XmlJavaTypeAdapter(MapAdapter.class)    public HashMap<String, AccountBean> getMap() {        return map;}
public void setMap(HashMap<String, AccountBean> map) {
        this.map = map;}
}
上面的map集合的getter方法有一个XmlJavaTypeAdapter,需要传递一个Adapter的类型。
下面看看MyAdapter的代码
package com.hoo.util;import java.util.HashMap;import java.util.Map;import javax.xml.bind.annotation.adapters.XmlAdapter;import com.hoo.entity.AccountBean;/** * <b>function:</b>AccountBean 编组、解组的XmlAdapter * @author hoojo * @createDate 2011-4-25 下午05:03:18 * @file MyAdetper.java * @package com.hoo.util * @project WebHttpUtils * @blog http://blog.csdn.net/IBM_hoojo * @email hoojo_@126.com * @version 1.0 */public class MapAdapter extends XmlAdapter<MapElements[], Map<String, AccountBean>> {
public MapElements[] marshal(Map<String, AccountBean> arg0) throws Exception {
        MapElements[] mapElements = new MapElements[arg0.size()];        int i = 0;        for (Map.Entry<String, AccountBean> entry : arg0.entrySet())            mapElements[i++] = new MapElements(entry.getKey(), entry.getValue());        return mapElements;}
public Map<String, AccountBean> unmarshal(MapElements[] arg0) throws Exception {
        Map<String, AccountBean> r = new HashMap<String, AccountBean>();        for (MapElements mapelement : arg0)r.put(mapelement.key, mapelement.value);
        return r;}
}
MapElements
package com.hoo.util;import javax.xml.bind.annotation.XmlElement;import com.hoo.entity.AccountBean;/** * <b>function:</b> MapElements * @author hoojo * @createDate 2011-4-25 下午05:04:04 * @file MyElements.java * @package com.hoo.util * @project WebHttpUtils * @blog http://blog.csdn.net/IBM_hoojo * @email hoojo_@126.com * @version 1.0 */public class MapElements {
@XmlElement
    public String key;@XmlElement
    public AccountBean value;    @SuppressWarnings("unused")    private MapElements() {    } // Required by JAXB    public MapElements(String key, AccountBean value) {        this.key = key;        this.value = value;}
}
运行结果如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><mapBean><map><item><key>NO2</key><value number="2"><address>china</address>
<birthday><birthday>2010-11-22</birthday></birthday><email>tom@125.com</email><name>tom</name></value></item>
<item><key>NO1</key><value number="1"><address>北京</address><birthday><birthday>2010-11-22</birthday></birthday>
<email>email</email><name>jack</name></value></item></map></mapBean>
{NO2=tom#2#china#2010-11-22#tom@125.com, NO1=jack#1#北京#2010-11-22#email}