使用JAXB将XML Schema绑定到Java类
Java
Architecture for XML Binding (JAXB) 是一项可以根据XML 模式产生Java类的Java技术。该过程中,JAXB也提供了将XML实例文档反编组到Java内容树的方法,并能将Java内容树编组回XML实例文档。从另一方面来讲,JAXB提供了快速而简便的方法将XML模式绑定到Java表示,从而使得Java开发者在Java应用程序中能方便地结合XML数据和处理函数。
这意味着你不需要处理甚至不需要知道XML编程技巧就能在Java应用程序中利用平台核心XML数据的灵活性。而且,可以充分利用XML的优势而不用依赖于复杂的XML处理模型如SAX或DOM。JAXB 隐藏了细节并且取消了SAX和DOM中没用的关系——生成的JAXB类仅描述原始模型中定义的关系。其结果是结合了高度可移植Java代码的高度可移植的XML数据,其中这些代码可用来创建灵活、轻便的应用程序和Web服务。
本章介绍了JAXB体系结构、函数和核心概念。在学习第十章之前必须先阅读本章。第十章给出了示例代码和逐步使用JAXB的过程。
JAXB 体系结构
本节主要讨论JAXB处理模型中的组件和交互。在给出了总的概述之后,本节将详细讨论核心的JAXB特性。本节中的主题主要包括:
体系结构概述
图 9-1 给出了构成JAXB实现的组件。

图
9-1 JAXB体系结构概述
如图9-1所示,JAXB实现包含下列八个核心组件:
|
表 9-1 JAXB实现中的核心组件
|
|
组件
|
描述
|
|
XML Schema
|
XML模式使用XML语法描述XML文档中元素、属性和实体之间的关系。XML模式的目标是定义一个XML文档类,该类必须坚持特定的结构规则和数据约束。例如,你可能希望给面向章的书、在线采购系统或个人数据库定义不同的模式。在JAXB上下文中,将包含数据的受到XML模式约束的XML文档叫做文档实例,并且将文档实例中的结构和数据叫做内容树
|
|
Binding
Declarations
|
默认情况下,JAXB绑定编译器根据JAXB规范第5节“将XML Schema绑定到Java表示”中定义的规则将Java类和包绑定到原始XML模式。多数情况下,利用默认的规则已经能够从大量的模式中产生一组强壮的模式派生类。但是,有的时候,默认的绑定规则就不够用了。JAXB支持通过绑定声明自定义或覆盖默认的绑定规则。这些绑定声明或者是内部源模式的注释或者是传递给JAXB绑定编译器的外部绑定自定义文件中的语句。注意,自定义的JAXB绑定声明也允许摆脱XML模式中特定于XML的束缚,来自定义生成的JAXB类,以包含特定于Java的改进,如类和包名映射
|
|
Binding
Compiler
|
JAXB绑定编译器是JAXB处理模型的核心。它的功能是将源XML模式转换或绑定到Java编程语言中的一组JAXB内容类。基本上,可以通过将一个XML模式 (可以选择使用自定义绑定声明)用作输入来运行JAXB绑定编译器。绑定编译器产生Java类,这些Java类映射到了源XML 模式中的约束条件
|
|
Binding
Framework
Implementation
|
JAXB绑定框架实现是运行时API,它提供了反编组、编组和验证Java应用程序中的XML内容的接口。绑定框架包括javax.xml.bind 包中的接口
|
|
Schema-Derived
Classes
|
这些是JAXB编译器产生的模式派生类。根据输入的模式将采用不同的类
|
|
Java
Application
|
在JAXB上下文中,Java应用程序是客户端应用程序,它使用JAXB绑定框架来反编组XML数据,验证并修改Java内容对象,并将Java内容编组成XML数据。特别是,JAXB绑定框架包装在一个能提供UI功能、XML转换功能、数据处理或其他所需要的功能的大型Java应用程序中
|
|
XML Input
Documents
|
这是反编组出来用作JAXB绑定框架输入的XML内容——即XML实例文档,从这里将产生内容树形式的Java表示。实际上, 术语“文档”不再是传统意义上的文档了,因为XML实例文档不一定要是形式完整的、自立的文档文件;相反它具有流的形式,这些流可以是应用程序之间传递的数据、数据库字段集合、XML信息集合,其中信息块包含了描述它们在模式结构中的位置的足够信息。
在JAXB中,反编组过程支持根据源模式定义的约束验证XML输入文档。然而该验证过程是可选的,在某些情况下你可能通过其他途径知道输入文档是有效的,出于对性能的考虑你可能选择在反编组过程中跳过验证。但是,无论在哪种情况下,反编组之前(通过第三方应用程序)或之后验证都很重要,这是因为它确保了关于源模式编组过程中产生的XML文档也是有效的。在本章的后面部分将详细介绍验证
|
|
XML Output
Documents
|
这是编组到XML文档的XML内容。在JAXB中,编组包括解析XML内容对象树并写出一个XML文档,该文档是原始XML文档的精确表示并且相对于原始模式来说是有效的。JAXB能够将XML数据编组成XML 文档、SAX内容处理程序和DOM节点。
|
JAXB绑定过程
图9-2显示了JAXB的绑定过程。
图
9-2 JAXB绑定过程步骤
JAXB数据绑定过程的常用步骤是:
1.
生成类。将XML模式放入JAXB绑定编译器,以产生基于该模式的JAXB类。
2.
编译类。 必须编译所有生成的类、源文件和应用程序代码。
3.
反编组。JAXB绑定框架反编组根据原始模式中的约束编写的XML文档。注意JAXB也支持反编组来自除了文件/文档之外XML数据,如DOM节点、字符串缓冲、SAX Source等等。
4.
生成内容树。 反编组过程产生从生成的JAXB类实例化而来的数据对象内容树,该内容树代表了源XML文档的结构和内容。
5.
验证(可选)。 反编组过程中,可以在生成内容树之前验证源XML文档。注意,如果在第6步中修改内容树,下面,你也能使用JAXB验证操作在将内容编组到XML文档之前验证变化。
6.
处理内容。客户端应用程序通过绑定编译器产生的接口方法可以修改Java内容树表示的XML数据。
7.
编组。将处理过的内容树编组到一个或多个XML输出文档中。在编组之前要验证内容。
总而言之,使用JAXB涉及到两个独立的活动集:
- 根据源模式生成并编译JAXB类,并且建立一个实现这些类的应用程序。
- 在JAXB绑定框架中运行应用程序,以反编组、处理、验证和编组XML内容。
通常分时间分阶段执行这两个步骤。典型地,例如,需要在应用程序开发阶段生成并编译JAXB类,并且建立绑定实现,接着是部署阶段,在该阶段使用生成的JAXB类在“现场”产品环境中处理XML内容。
注意:反编组不是创建内容树的唯一的方法。模式派生的内容类通过直接调用合适的工厂方法也支持按计划构建内容树。一旦创建了,任何时候都可以重新验证内容树的一部分或全部。查看示例应用程序 3 中的使用ObjectFactory 类直接给内容树添加内容的例子。
JAXB绑定框架
JAXB绑定框架由三个Java包实现:
javax.xml.bind 包定义直接和内容类一起使用的抽象类和接口。
javax.xml.bind 包定义Unmarshaller、Validator和Marshaller 类,它们是提供各自操作的辅助对象。
JAXBContext 类是Java应用程序到JAXB框架的入口点。JAXBContext 实例为反编组、编组和验证操作使用的JAXB实现将XML元素名绑定到Java内容接口。
javax.xml.bind 包也定义了编组或反编组错误出现时、违反约束时及出现其他类型的错误时使用的丰富的验证事件和异常类的层次结构。
javax.xml.bind.util 包包含工具类,客户端应用程序可以使用它们来管理编组、反编组和验证事件。
javax.xml.bind.helper 包为一些javax.xml.bind 接口提供了部分默认的实现。JAXB的实现能够扩展这些类并且实现抽象方法。使用JAXB体系结构的应用程序不能直接使用这些API。
下面将详细介绍JAXB绑定框架中的主要的包javax.bind.xml。
关于javax.xml.bind的更多信息
主要绑定框架包javax.xml.bind提供的三个核心功能是编组、反编组和验证。到绑定框架的主要的客户端入口点是JAXBContext 类。
JAXBContext 提供了一个抽象,该抽象可以管理实现反编组、编组和验证操作必要的XML/Java绑定信息。客户端应用程序通过newInstance(contextPath)方法得到该类的新实例。例如:
JAXBContext jc = JAXBContext.newInstance(
"com.acme.foo:com.acme.bar" );
contextPath 参数包含一个Java包名,这些包包含模式派生的接口—特别是JAXB绑定编译器产生的接口。该参数值初始化JAXBContext 对象,使得它能够管理模式派生的接口。为此目的,JAXB提供程序实现必须提供一个包含下列特征的实现类:
public static JAXBContext createContext( String contextPath,
ClassLoader classLoader )
throws JAXBException;
注意:在每个包含模式派生类的包中,JAXB提供程序实现必须生成一个jaxb.properties 文件。该属性文件必须包含一个叫做javax.xml.bind.context.factory 的属性,它的值是实现createContext API的类的名字。
不一定要将提供程序提供的类分配给javax.xml.bind.JAXBContext,它只是必须提供一个实现 createContext API的类。允许指定多个Java包,JAXBContext 实例允许同时管理多个模式。
关于反编组的更多信息
javax.xml.bind 包中的Unmarshaller 类使得客户端应用程序能够将XML数据转换成Java内容对象树。模式的unmarshal 方法(在命名空间内)允许将模式中声明的任何全局XML元素反编组成实例文档的根。JAXBContext 对象允许在一组模式内合并全局元素(列在contextPath中)。由于模式集中的每个模式属于不同的命名空间,将模式统一到反编组上下文中是独立于命名空间的。这意味着客户端应用程序能够反编组contextPath 中列出的任何模式的实例XML文档。例如:
JAXBContext jc = JAXBContext.newInstance(
"com.acme.foo:com.acme.bar" );
Unmarshaller u = jc.createUnmarshaller();
FooObject fooObj =
(FooObject)u.unmarshal( new File( "foo.xml" ) ); // ok
BarObject barObj =
(BarObject)u.unmarshal( new File( "bar.xml" ) ); // ok
BazObject bazObj =
(BazObject)u.unmarshal( new File( "baz.xml" ) );
// error, "com.acme.baz" not in contextPath
客户端应用程序也能明显地生成Java内容树而不是反编组现有XML数据。这样做,应用程序必须能够存取并了解contextPath 中的每个Java包中模式派生的ObjectFactory 类。对于每个模式派生Java类,将有一个静态工厂方法能产生该类型的对象。例如,假设编译了模式之后,得到一个包含PurchaseOrder 模式派生接口的包com.acme.foo 。要创建这类对象,客户端应用程序将使用下列工厂方法:
ObjectFactory objFactory = new ObjectFactory();
com.acme.foo.PurchaseOrder po =
objFactory.createPurchaseOrder();
注意:由于当contextPath 上有多个包时,会产生多个ObjectFactory 类,所以如果你有多个contextPath上的包,在引用某个包中的ObjectFactory 类时,必须使用完整的包名。
一旦客户端应用程序有模式派生对象的实例,它就能使用赋值方法来设置它的内容。
注意:JAXB 提供程序实现必须在每个包中生成一个类,这些包包含ObjectFactory 包的必要的对象工厂方法和newInstance( javaContentInterface ) 方法。
关于编组的更多信息
javax.xml.bind 包中的Marshaller 类使得客户端应用程序能够将Java内容树转换成XML数据。编组一个使用工厂方法人为创建的内容树和反编组操作得到的内容树之间没有什么区别。客户端能够将Java内容树编组回到java.io.OutputStream 或java.io.Writer的XML数据中。编组过程能够在注册的ContentHandler 中生成SAX2 事件流或生成DOM Node 对象。
下面是一个简单的例子,它反编组一个XML文档,然后在将它编组回去:
JAXBContext jc = JAXBContext.newInstance( "com.acme.foo" );
// unmarshal from foo.xml
Unmarshaller u = jc.createUnmarshaller();
FooObject fooObj =
(FooObject)u.unmarshal( new File( "foo.xml" ) );
// marshal to System.out
Marshaller m = jc.createMarshaller();
m.marshal( fooObj, System.out );
默认情况下,在java.io.OutputStream 或 java.io.Writer中生成XML数据时,Marshaller使用UTF-8
编码。使用setProperty API 改变编组操作中输出的编码。客户端应用程序提供W3C XML 1.0 推荐中定义的有效的字符编码名( |