——完成Java對象和XML相互轉換
前面有介紹過json-lib這個框架,在線博文:[http://www.cnblogs.com/hoojo/archive/2011/04/21/2023805.html](http://www.cnblogs.com/hoojo/archive/2011/04/21/2023805.html)
以及Jackson這個框架,在線博文:[http://www.cnblogs.com/hoojo/archive/2011/04/22/2024628.html](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](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](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](http://www.oracle.com/technetwork/articles/javase/index-140168.html)
b) Jar包下載:[http://jaxb.java.net/2.2.3/JAXB2_20101209.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 {
//下面代碼演示將對象轉變為xml
Marshaller 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"?>"1">
北京
2010-11-22emailjack
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);
//下面代碼演示將對象轉變為xml
Marshaller 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.com
2#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);
//下面代碼演示將對象轉變為xml
Marshaller 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}
~~~