JAXB(Java API for XML Binding),提供了一个快速便捷的方式将Java对象与XML进行转换。在JAX-WS(Java的WebService规范之一)中,JDK1.6 自带的版本JAX-WS2.1,其底层支持就是JAXB。JAXB 2.0是JDK 1.6的组成部分。JAXB 2.2.3是JDK 1.7的组成部分。
JAXB 可以实现Java对象与XML的相互转换,在JAXB中,将一个Java对象转换为XML的过程称之为Marshal,将XML转换为Java对象的过程称之为UnMarshal。
JAXB中的一些注解
JDK中JAXB相关的重要Class和Interface:
1、JAXBContext类,是应用的入口,用于管理XML/Java绑定信息。
2、Marshaller接口,将Java对象序列化为XML数据。
3、Unmarshaller接口,将XML数据反序列化为Java对象。
JDK中JAXB相关的重要Annotation:
1、@XmlType,将Java类或枚举类型映射到XML模式类型。用在class类的注解,常与@XmlRootElement,@XmlAccessorType一起使用。
2、@XmlAccessorType(XmlAccessType.FIELD) ,控制字段或属性的序列化。FIELD表示JAXB将自动绑定Java类中的每个非静态的(static)、非瞬态的(由@XmlTransient标注)字段到XML。其他值还有XmlAccessType.PROPERTY和XmlAccessType.NONE。
3、@XmlAccessorOrder,控制JAXB 绑定类中属性和字段的排序。
AccessorOrder.ALPHABETICAL:对生成的xml元素按字母书序排序
XmlAccessOrder.UNDEFINED:不排序
当同时使用@XmlType的propOrder属性指定顺序时,以指定为准
4、@XmlJavaTypeAdapter,使用定制的适配器(即扩展抽象类XmlAdapter并覆盖marshal()和unmarshal()方法),以序列化Java类为XML。
5、@XmlElementWrapper ,对于数组或集合(即包含多个元素的成员变量),生成一个包装该数组或集合的XML元素(称为包装器)。
6、@XmlRootElement,将Java类或枚举类型映射到XML元素。
7、@XmlElement,将Java类的一个属性映射到与属性同名的一个XML元素。
8、@XmlAttribute,将Java类的一个属性映射到与属性同名的一个XML属性。
Mapping interfaces
因为W3C XML Schema和Java类型系统引起的XML类型系统之间的差异,JAXB不能绑定接口开箱即用,但也有一些事情可以做。
使用@XmlRootElement
1 |
|
1 | <zoo> |
这种方法的主要特点是:
- 实现是开放式的; 任何人都可以实现这些接口,即使由不同的人从不同的模块,只要它们都被提供给JAXBContext.newInstance方法。没有必要列出的任何地方都实现类。
- 每个接口的实现都需要有一个独特的元素名称。
- 为每个接口参考需要有 XmlElementRef将 注释。该类型= Object.class部分告诉JAXB所有实现最大的公共基类是java.lang.Object继承。
分组,列表
1 |
|
1 | <zoo> |
使用@XmlJavaTypeAdapter
1 | .class) (FooImpl.Adapter |
1 | <somewhere> |
这种方法的主要特点是:
- 接口和实现将通过一个适配器紧密结合,虽然改变适配器代码将允许您支持多种实现。
- 有在使用接口,无需任何注释。
这种技术的一个变化是,当你有几个实现接口,不只是一个。
1 | .class) (AbstractFooImpl.Adapter |
1 | <somewhere> |
需要注意的是SomeFooImpl和AnotherFooImpl必须提交JAXBContext.newInstance一种方式或其他。
再举这个例子,你可以使用Object而不是AbstractFooImpl。如下
1 | .class) (AnyTypeAdapter |
1 | <xs:complexType name="somewhere"> |
正如你所看到的,模式将产生接受的xs:anyType的它比Java代码实际上需要更多的宽松。实例将是与上述相同的例子。从JAXB 2.1 RI开始,我们捆绑com.sun.xml.bind.AnyTypeAdapter在定义该适配器的运行时类。所以,你将不必编写此适配器在你的代码。
使用@XmlElement
1 | interface IFoo { |
1 | <somewhere> |
这实际上告诉JAXB运行时说:“即使字段是IFoo的,它实际上只是FooImpl。
在这种方法中,一个接口的引用必须具有实际实现类的知识。因此,尽管这需要输入最少的,它可能不会,如果这跨越模块的边界工作得很好。
像 XmlJavaTypeAdapter 方法,这可以甚至当存在多个实施方式中,只要它们共享共同的祖先中。
这种情况下的极端是指定@XmlElement(类型= Object.class) 。
Tips
指定XML字段顺序
默认JAXB生成的XML字段是随机的,可以使用注解@XmlType
的propOrder
属性来指定XML字段的顺序。
1 | "user", "profile","unit"}) (propOrder = { |
另外,使用@XmlElementWrapper
标注的属性,不能出现在@XmlType
的propOrder
列表中。但是对于使用@XmlElement
标注的属性,则必须出现在该列表中
集合中省略集合节点名
1 | //Example: code fragment |
The docs state the the @XmlElementWrapper annotation can be used for ‘unwrapped’ or ‘wrapped’ collections.
If you include @XmlElementWrapper it will add a grouping element:
1 |
|
1 | <root> |
and if you omit it, then it won’t.
1 | "foo") (name= |
1 | <root> |
另外,@XmlElementWrapper
仅允许出现在集合属性上。
转为XML文件时移除xmlns:xsi和xsi:type
How to remove xmlns:xsi and xsi:type from JAXB marshalled XML file
使用@XmlElement
指定Type
类型
1 | "DefaultCar", type=String.class) (name = |
在List中如果每个对象,类型不同,对象转XML时,可以用
1 | ({ |
但是在XML转换为对象时,这边可能需要额外判断一下,直接转换时,如果XML节点元素都为,指定了type,也可能会报错。
XmlElementRef的一些使用
@XmlElementRef annotation can be used with a JavaBean property or from within @XmlElementRefs
1 | ({ |
XML Schema substitution group support
The usage is subject to the following constraints:
- If the collection item type (for collection property) or property type (for single valued property) is JAXBElement, then @XmlElementRef}.name() and @XmlElementRef.namespace() must point an element factory method with an @XmlElementDecl annotation in a class annotated with @XmlRegistry (usually ObjectFactory class generated by the schema compiler) :
(1). @XmlElementDecl.name() must equal @XmlElementRef.name()
(2). @XmlElementDecl.namespace() must equal @XmlElementRef.namespace(). - If the collection item type (for collection property) or property type (for single valued property) is not JAXBElement, then the type referenced by the property or field must be annotated with XmlRootElement.
- This annotation can be used with the following annotations: XmlElementWrapper, XmlJavaTypeAdapter.
Example 1: Ant Task Example
The following Java class hierarchy models an Ant build script. An Ant task corresponds to a class in the class hierarchy. The XML element name of an Ant task is indicated by the @XmlRootElement
annotation on its corresponding class.
1 | "target") (name= |
1 | <!-- XML Schema fragment --> |
Thus the following code fragment:
1 | Target target = new Target(); |
It is not an error to have a class that extends Task that doesn’t have XmlRootElement
. But they can’t show up in an XML instance (because they don’t have XML element names).
Example 2: XML Schema Susbstitution group support
The following example shows the annotations for XML Schema substitution groups. The annotations and the ObjectFactory are derived from the schema.
1 |
|
nil 属性和其他属性
XML 架构规范允许其他 XML 属性出现在 xsi:nil 属性设置为 true 的元素中。由于只有当对应的对象被分配了空引用时,XmlSerializer 类才将 nil 属性设置为 true,因此,表示 XML 属性(通过类型为 System.Xml.Serialization.XmlAttributeAttribute 的属性)的任何对象字段此时甚至不能存在于内存中。
因此,XmlSerializer 类按如下方式处理其他属性:
在将对象序列化为 XML 文档时:如果 XmlSerializer 类遇到与某个 XML 元素对应的对象的空引用,并且应当为该元素指定 nil 属性,则它会省略任何其他属性。
在将 XML 文档反序列化为对象时:如果 XmlSerializer 类遇到指定 xsi:nil=”true” 的 XML 元素,它会为对应的对象分配一个空引用,并忽略其他任何属性。如果该 XML 文档是由某个 XML 架构实现创建的,而且该实现允许其他属性与 xsi:nil=”true” 一起出现 — 实际上是不将 nil 的 true 值绑定到空对象引用 — 则可能会出现这种情况。
XSD文件中的使用
These sequence tags will be under
1 |
|
一般建议使用如下
1 |
|
Xml Schema的派生复杂类型
XML Schema提供了一种机制,称为替换组(substitution group),允许在内容模型中声明的某个元素被其他元素所替换。替换组有头元素(head element)和替换成员组成,头元素和替换成员都必须是全局元素,有相同的类型,或都有头元素派生。替换成员需要使用一个特殊的属性sbustitutionGroup,用于指定要替换的头元素的名字。在内容模型中引用头元素,在实例文档中则用任意的替换组成员来替换头元素。详见他人博客
使用JDK中的xjc.exe命令,根据xsd文件生成java代码
实际上,有更懒的办法。
写好一个xsd文件,然后用jdk下bin xjc.exe test-scheme.xsd -d [your src dir]
命令自动生成java等文件。也可以用IDE,像eclipse 选中xsd右键-> Genarate -> JAXB Class生成 。在eclipse中,要先让项目运行环境在JDK 1.6 或以上。如默认项目运行在JRE,需要手工更改Build path为JDK
关于 xjc.exe For more info use this documentation
and this
如果生成的根元素对应的对象没有自动添加上@XmlRootElement
,则需要手动添加。