XML是开发中常用的配置文件类型,在常用的组件包里也能时常看到它的踪影,如Spring中的applicationContext.xml、Hibernate中的hbm.xml,都是用的XML来配置相关的参数信息。可见其使用是十分广泛的。

但是在Java中,要解析一个XML,并封装为一个对象,可能大家首先会想到Dom4j、Jdom等第三方类库,使用其中的解析器对每一个节点解析,并生成自己想要的对象。这样写的话,代码显得是很混乱,不是很易读。如果在Webservice交互中,用到XML传递数据,那么工作量就会更大了。


一、介绍

JAXB允许JAVA开发人员将JAVA类映射为XML,也可以逆向的将XML转换为JAVA。可以不用手动的去写解析XML的方法,只需要书写对应的JAVA Bean,并配置好相应的注解,就可以完成转换,大大简化了程序员的工作量。

二、集成

讲了这么多,大家可能在想,如何集成呢,其实咱们不用集成就可以使用,这个功能是直接集成在JDK中的。完全不用集成,是不更简单呢,不用集成任何类库。

三、前置学习

JAXB实现转换是依赖于Annotation的,那么咱们应该如何使用呢,可以看下面各个Annotation的作用:

a)、@XmlRootElement

用来定义一个XML的根节点信息,其参数有name和namespace。

其中name用来定义根节点的名称,非必填。

namespace用来定义XML的命名空间,非必填。

例如下定义:

如果咱们定义了一个JAVA Bean,名叫Property:











Java






1



public class Property { }



1.咱们给他加上@XmlRootElement信息:







Java






1



2



@XmlRootElement



public class Property { }



那么用表明生成的XML的根节点就是类名的小写,如下:











XHTML






1



2



<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?>



<property/>



2.如果定义了name信息,则根节点名称就会是你定义的名称:







Java






1



2



3



@XmlRootElement ( name = "Test" )



public class Property {



}



生成的XML如下:











XHTML






1



2



<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?>



<Test/>



3.如果定义了namespace,根节点就会显示出你定义的namespace,如下代码







Java






1



2



@XmlRootElement ( name = "Test" , namespace = "com.jialeens" )



public class Property { }



生成的XML如下











XHTML






1



2



<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?>



<Test xmlns = "com.jialeens" />



b)、@XmlAccessorType

控制字段或属性的序列化。常用的有XmlAccessType.FIELD、XmlAccessType.PROPERTY和XmlAccessType.NONE。

如果定义的是FIELD(全自动),则表明JAXB 绑定类中的每个非静态(static)、非瞬态(transient)字段将会自动绑定到 XML,除非由 XmlTransient 注释。

如果定义的是PROPERTY(半自动),则表明JAXB 绑定类中的每个获取方法(get)/设置方法(set)对将会自动绑定到 XML,除非由 XmlTransient 注释。需要注意的是要实现get/set方法。

如果定义的是NONE(手动),则表所有字段或属性都不能绑定到 XML,除非使用一些 JAXB 注释专门对它们进行注释。如果使用了这个属性,咱们就需要对每个要映射的成员变量做设置才可以。

1.XmlAccessType.FIELD







Java






1



2



3



4



5



@XmlRootElement ( name = "Test" )



@XmlAccessorType ( XmlAccessType . FIELD )



public class Property {



public String name ;



}



生成的xml如下











Java






1



2



3



4



<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?>



<Test>



     <name> a < / name >



< / Test >



2.XmlAccessType.PROPERTY

如果咱们定义的时候不生成get/set方法,看看效果。







Java






1



2



3



4



5



@XmlRootElement ( name = "Test" )



@XmlAccessorType ( XmlAccessType . PROPERTY )



public class Property {



public String name ;



}



输出结果











Java






1



2



<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?>



< Test / >



可以看到没有生成name的内容。

咱们现在生成get/set方法,再看看效果。







Java






1



2



3



4



5



6



7



8



9



10



11



12



13



@XmlRootElement ( name = "Test" )



@XmlAccessorType ( XmlAccessType . PROPERTY )



public class Property {



public String name ;



 



public String getName ( ) {



return name ;



}



 



public void setName ( String name ) {



this . name = name ;



}



}



生成XML的结果如下











Java






1



2



3



4



<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?>



<Test>



     <name> a < / name >



< / Test >



可以看到,这个类型是和get/set方法是否存在相关,如果写get/set方法,就生成xml。

c)、@XmlElement

将Java类的一个属性映射到与属性同名的一个XML元素。例如上面的例子,生成的是一个子标签。







Java






1



2



3



4



<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?>



<Test>



     <name> a < / name >



< / Test >



d)、@XmlAttribute

将Java类的一个属性映射到与属性同名的一个XML属性。











Java






1



2



3



<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?>



< Test name = "a" >



< / Test >



如上,name是在Test标签内部,当作Test标签的一个属性。

e)、@XmlElementWrapper

对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的XML元素(称为包装器)。

f)、@XmlTransient

阻止将 JavaBean 属性映射到 XML 表示形式。主要用来解决映射冲突的情况。

四、简单使用

上面说了这么多,大家可能还不是很理解到底应该怎么用,下面咱们来讲一个简单的例子。

XML-->JAVA

现在咱们有一段XML。如下结构。







Java






1



2



3



4



5



<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?>



< property type = "string" >



     <key> testKey < / key >



     <value> testValue < / value >



< / property >



咱们先分析一下这个XML,可以看到这个XML的根节点是property。其中有个属性是type。其下面有两个标签,分别是key和value。那么咱们可以先定义一个bean。











Java






1



2



3



4



5



6



7



8



9



10



11



12



13



14



15



16



17



18



19



20



21



22



23



24



25



26



27



28



29



30



31



32



33



34



35



36



37



38



39



40



41



42



43



44



45



46



47



48



49



50



51



52



53



public class Property {



/**



* 键



*/



private String key ;



/**



* 值



*/



private String value ;



/**



* 类型



*/



private String type ;



/**



* @return the key



*/



public String getKey ( ) {



return key ;



}



/**



* @param key



*            the key to set



*/



public void setKey ( String key ) {



this . key = key ;



}



/**



* @return the value



*/



public String getValue ( ) {



return value ;



}



/**



* @param value



*            the value to set



*/



public void setValue ( String value ) {



this . value = value ;



}



/**



* @return the type



*/



public String getType ( ) {



return type ;



}



/**



* @param type



*            the type to set



*/



public void setType ( String type ) {



this . type = type ;



}



}



现在咱们先定义一下根节点,根节点咱们使用@XmlRootElement注解。这样配置@XmlRootElement(name="property")。

上面的XML里有一个属性type,咱们可以使用@XmlAttribute(name = "type")来标注type的成员变量

对于name和value这两个成员变量,可以使用@XmlElement来标注。那么咱们的JAVA Bean可以改成这样。







Java






1



2



3



4



5



6



7



8



9



10



11



12



13



14



15



16



17



18



19



20



21



22



23



24



25



26



27



28



29



30



31



32



33



34



35



36



37



38



39



40



41



42



43



44



45



46



47



48



49



50



51



52



53



54



55



56



57



58



59



60



61



62



63



64



import javax . xml . bind . annotation . XmlAccessType ;



import javax . xml . bind . annotation . XmlAccessorType ;



import javax . xml . bind . annotation . XmlAttribute ;



import javax . xml . bind . annotation . XmlElement ;



import javax . xml . bind . annotation . XmlRootElement ;



 



@XmlAccessorType ( XmlAccessType . FIELD )



@XmlRootElement



public class Property {



/**



* 键



*/



@XmlElement ( name = "key" )



private String key ;



/**



* 值



*/



@XmlElement ( name = "value" )



private String value ;



/**



* 类型



*/



@XmlAttribute ( name = "type" )



private String type ;



/**



* @return the key



*/



public String getKey ( ) {



return key ;



}



/**



* @param key



*            the key to set



*/



public void setKey ( String key ) {



this . key = key ;



}



/**



* @return the value



*/



public String getValue ( ) {



return value ;



}



/**



* @param value



*            the value to set



*/



public void setValue ( String value ) {



this . value = value ;



}



/**



* @return the type



*/



public String getType ( ) {



return type ;



}



/**



* @param type



*            the type to set



*/



public void setType ( String type ) {



this . type = type ;



}



}



咱们现在写一个调用的测试类。如:













Java






1



2



3



4



5



6



7



8



9



10



11



12



13



14



15



16



public class JaxbTest {



@Test



public void test ( ) throws JAXBException , IOException {



String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"



         + "<property type=\"string\">"



         + "<key>testKey</key>"



         + "<value>testValue</value>" + "</property>" ;



JAXBContext context ;



context = JAXBContext . newInstance ( Property . class ) ;



Unmarshaller unmarshal = context . createUnmarshaller ( ) ;



Property obj = ( Property ) unmarshal . unmarshal ( new StringReader ( xml ) ) ;



System . out . println ( obj . getKey ( ) ) ;



System . out . println ( obj . getValue ( ) ) ;



System . out . println ( obj . getType ( ) ) ;



}



}



是不是很简单,完全没有解析XML的代码。
输出结果







XHTML






1



2



3



testKey



testValue



string



JAVA-->XML

咱们还是用上面的例子来将一个JAVA Bean转换成一个XML,咱们只需要修改调用方法即可,如下。











Java






1



2



3



4



5



6



7



8



9



10



11



12



13



14



15



16



17



18



19



20



public class JaxbTest {



@Test



public void test ( ) throws JAXBException , IOException {



Property a = new Property ( ) ;



a . setKey ( "testKey" ) ;



a . setValue ( "testValue" ) ;



a . setType ( "string" ) ;



ByteArrayOutputStream os = new ByteArrayOutputStream ( ) ;



try {



JAXBContext jc = JAXBContext . newInstance ( a . getClass ( ) ) ;



Marshaller m = jc . createMarshaller ( ) ;



m . setProperty ( Marshaller . JAXB_FORMATTED_OUTPUT , true ) ;



m . marshal ( a , os ) ;



String xml = new String ( os . toByteArray ( ) , "UTF-8" ) ;



System . out . println ( xml ) ;



} finally {



os . close ( ) ;



}



}



}



结果如下:







XHTML






1



2



3



4



5



<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?>



<property type = "string" >



     <key> testKey </key>



     <value> testValue </value>



</property>



五、实现一个通用的工具类

咱们可以针对上面两种转换的方式写一个工具类,如下:











Java






1



2



3



4



5



6



7



8



9



10



11



12



13



14



15



16



17



18



19



20



21



22



23



24



25



26



27



28



29



30



31



32



33



34



35



36



37



38



39



40



41



42



43



44



45



46



47



48



49



50



51



52



53



54



55



56



57



58



import java . io . ByteArrayOutputStream ;



import java . io . IOException ;



import java . io . InputStream ;



import java . io . StringReader ;



 



import javax . xml . bind . JAXBContext ;



import javax . xml . bind . JAXBException ;



import javax . xml . bind . Marshaller ;



import javax . xml . bind . Unmarshaller ;



 



/**



* Object<-->XML转换类



*



* @param <T> 对应的类



*/



public class JAXBUtil <T> {



 



/**



* 对象转换为xml



*



* @param element



* @return



* @throws JAXBException



* @throws IOException



*/



public String marshal ( T element ) throws JAXBException , IOException {



ByteArrayOutputStream os = new ByteArrayOutputStream ( ) ;



try {



JAXBContext jc = JAXBContext . newInstance ( element . getClass ( ) ) ;



Marshaller m = jc . createMarshaller ( ) ;



m . setProperty ( Marshaller . JAXB_FORMATTED_OUTPUT , true ) ;



m . marshal ( element , os ) ;



String xml = new String ( os . toByteArray ( ) , "UTF-8" ) ;



return xml ;



} finally {



os . close ( ) ;



}



}



 



@SuppressWarnings ( { "unchecked" , "rawtypes" } )



public T unmarshal ( Class c , String xml ) throws JAXBException {



JAXBContext context ;



context = JAXBContext . newInstance ( c ) ;



Unmarshaller unmarshal = context . createUnmarshaller ( ) ;



T obj = ( T ) unmarshal . unmarshal ( new StringReader ( xml ) ) ;



return obj ;



 



}



 



@SuppressWarnings ( { "unchecked" , "rawtypes" } )



public T unmarshal ( Class c , InputStream is ) throws JAXBException {



JAXBContext context ;



context = JAXBContext . newInstance ( c ) ;



Unmarshaller unmarshal = context . createUnmarshaller ( ) ;



T obj = ( T ) unmarshal . unmarshal ( is ) ;



return obj ;



}



}



上面的这个工具类就可以方便的把一个JAVA转换为一个XML字符串,也可以把一个XML字符串或者一个XML输入流转换成一个JAVA对象了。

调用的时候也很简单。







Java






1



2



3



4



5



6



7



8



9



10



11



public class JaxbTest {



@Test



public void test ( ) throws JAXBException , IOException {



Property a = new Property ( ) ;



a . setKey ( "testKey" ) ;



a . setValue ( "testValue" ) ;



a . setKey ( "testKey" ) ;



JAXBUtil <Property> util = new JAXBUtil <Property> ( ) ;



System . out . println ( util . marshal ( a ) ) ;



}



}