欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

jaxb 的使用介绍[转载]

程序员文章站 2022-03-20 17:57:04
...
[size=medium]什么是jaxb?
http://java.sun.com/xml/jaxb/about.html

主要能干什么?
当人们需要用java应用程序来访问数据库的时候,jdbc诞生了
当人们觉得频繁的jdbc操作很繁琐的时候,o/r mapping诞生了
当人们需要用java操作xml的时候,sax, dom诞生了
当人们觉得用dom操作xml很繁琐的时候, jaxb诞生了
jaxb---将xml与java对象绑定的sun规范.

使用:
jaxb的bin目录下有一个xcj.bat的批处理文件, 作用就是根据xml scheme文件比如xsd来生成java文件
sample.xsd
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="1.0" >
<xsd:element name="registry" type="RegistryType"/>

<xsd:complexType name="RegistryType">
<xsd:sequence>
<xsd:element name="module" type="ModuleType"/>
</xsd:sequence>
</xsd:complexType>

<xsd:complexType name="ModuleType">
<xsd:sequence>
<xsd:element name="serviceFactory" type="ServiceFactoryType"/>
<xsd:element name="serviceClientFactory" type="ServiceClientFactoryType"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>

<xsd:complexType name="ServiceFactoryType">
<xsd:sequence>
<xsd:element name="service" type="ServiceType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="class" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<jaxb:property name="clazz"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>

<xsd:complexType name="ServiceType">
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="class" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<jaxb:property name="clazz"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>

<xsd:complexType name="ServiceClientFactoryType">
<xsd:sequence>
<xsd:element name="serviceClient" type="ServiceClientType"/>
</xsd:sequence>
<xsd:attribute name="class" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<jaxb:property name="clazz"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>

<xsd:complexType name="ServiceClientType">
<xsd:sequence>
<xsd:element name="serviceRender" type="ServiceRenderType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string"/>
<xsd:attribute name="class" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<jaxb:property name="clazz"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="renderFactory" type="xsd:string"/>
</xsd:complexType>

<xsd:complexType name="ServiceRenderType">
<xsd:attribute name="class" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<jaxb:property name="clazz"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="id" type="xsd:string"/>
</xsd:complexType>
</xsd:schema>
在cmd窗口下 xjc -p com.hairroot.jaxb sample.xsd
这个命令会在com/hairroot/jaxb的目录下生成几个interface, 并在com/hairroot/jaxb/impl下面生成各自的实现类,实现类看起来还是很复杂的。为什么这么复杂,原因就是需要考虑很多的事情,比如进行marshal的时候,如果尽可能的将输出跟输入xml看起来一致的xml, 而不是元素,属性的顺序弄得乱七八糟的。

注意:除了生成的java文件之外,还有一个jaxb.properties, 和ser。这两个东西是不能 丢的,否则会报错。

unmarshall的操作:
两种方式
1)JAXBContext context = JAXBContext.newInstance("com.hairroot.jaxb");
context.createUnmarshaller().unmarshal(new File("d:/hairroot/jaxb/sample.xml"));
2)ObjectFactory factory = new ObjectFactory();
factory.createUnmarshaller().unmarshal(new File("d:/hairroot/jaxb/sample.xml"));
unmarshall返回的结果是一个object, 也就是根类型的一个实现类,可以强制转型了之后进行其它的操作。

marshall的操作:
同样有两种方式
1)JAXBContext context = JAXBContext.newInstance("com.hairroot.jaxb");
Object root = context.createUnmarshaller().unmarshal(new File("d:/hairroot/jaxb/sample.xml"));
context.createMarshaller().marshal(root, System.out);
2)ObjectFactory factory = new ObjectFactory();
Object root = factory.createUnmarshaller().unmarshal(new File("d:/hairroot/jaxb/sample.xml"));
factory.createMarshaller().marshal(root, System.out);
Validation的操作现在略;

如何将xsd:data类型进行格式化的输出:
如果在schema中定义一个xsd:date类型,那么jaxb会将其转化为java.util.Calendar的类型,然而这样有个问题,如果 sample.xml中数据为2005-03-09, 那么进行marshal的操作后生成的xml为2005-03-09+08:00, 解决方法, 在scheme中
<xsd:element name="shipDate" minOccurs="0">
<xsd:simpleType>
<xsd:annotation>
<xsd:appinfo>
<jaxb:javaType name="java.sql.Date" printMethod="toString" parseMethod="valueOf"/>
</xsd:appinfo>
</xsd:annotation>
<xsd:restriction base="xsd:date"/>
</xsd:simpleType>
</xsd:element>
并且还需要在xsd的namespace中加入
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="1.0" >
这样再进行xjc的时候不会报错,而且输入的date也就符合习惯了,如果不用
<jaxb:javaType name="java.sql.Date" printMethod="toString" parseMethod="valueOf"/>
则需要自己来写一个实现类,详细参考jaxb reference

如何处理java的一些保留字:
如果一个attribute的名字叫做class, 那么xjc产生的java中就有一个getClass的方法, 这与java.lang.Object 的getClass()相冲突,解决方法:
 <xsd:attribute name="class" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<jaxb:property name="clazz"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
可以用<jaxb:property name="clazz"/>来指定xjc生成的java的方法为getClazz()

jaxb1.0的问题:
目前我发现的主要问题是, attribute的输入的顺序跟schema中定义的顺序不一致,网上看到sun的工程师认为这不是一个很重要的问题,而且还认为attribute的顺序没有办法控制,这种借口简直好笑,如果能够做得更好为什么不去做?
推荐解决方法:
在xjc生成了java文件了之后,去看一下impl下面的每一个类的serializeAttributes()方法,调整这个方法的对应的 attribute的处理的上下顺序,就可以控制输出的xml的attribute出现的先后顺序,如此简单的事情,sun的工程师竟然说没有办法控制,当忽悠变成了一种时尚...

原文见 http://hairroot.blogchina.com/hairroot/899157.html[/size]