Java 中文官方教程 2022 版(四十九)(1)https://developer.aliyun.com/article/1488526
基本示例
本节描述了基本的 JAXB 示例(修改 Marshal、Unmarshal Validate),演示了如何:
- 将 XML 文档解组为 Java 内容树,并访问其中包含的数据。
- 修改 Java 内容树。
- 使用
ObjectFactory
类创建 Java 内容树,然后将其编组为 XML 数据。 - 在解组期间执行验证。
- 在运行时验证 Java 内容树。
修改 Marshal 示例
修改 Marshal 示例演示了如何修改 Java 内容树。
- jaxb-ri-install
/samples/modify-marshal/src/Main.java
类声明导入了三个标准 Java 类,五个 JAXB 绑定框架类和primer.po
包:
import java.io.FileInputStream; import java.io.IOException; import java.math.BigDecimal; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import primer.po.*;
- 创建一个用于处理在
primer.po
中生成的类的JAXBContext
实例。
JAXBContext jc = JAXBContext.newInstance( "primer.po" );
- 创建一个
Unmarshaller
实例,并解组po.xml
文件。
Unmarshaller u = jc.createUnmarshaller(); PurchaseOrder po = (PurchaseOrder) u.unmarshal(new FileInputStream("po.xml"));
- 使用
set
方法修改内容树中address
分支中的信息。
USAddress address = po.getBillTo(); address.setName("John Bob"); address.setStreet("242 Main Street"); address.setCity("Beverly Hills"); address.setState("CA"); address.setZip(new BigDecimal address.setName("John Bob"); address.setStreet("242 Main Street"); address.setCity("Beverly Hills"); address.setState("CA"); address.setZip(new BigDecimal("90210"));
- 创建一个
Marshaller
实例,并将更新后的 XML 内容编组到system.out
。使用setProperty
API 指定输出编码;在本例中为格式化(易读)的 XML。
Marshaller m = jc.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.marshal(po, System.out);
使用 Ant 构建和运行修改 Marshal 示例
要使用 Ant 编译和运行修改 Marshal 示例,在终端窗口中,转到 jaxb-ri-install/samples/modify-marshal/
目录,并输入以下内容:
ant
Unmarshal Validate 示例
Unmarshal Validate 示例演示了如何在解组期间启用验证。请注意,JAXB 提供了在解组期间进行验证但不在编组期间进行验证的功能。有关验证的更多详细信息,请参阅更多关于验证。
- jaxb-ri-install
/samples/unmarshal-validate/src/Main.java
类声明导入了一个标准 Java 类,十一个 JAXB 绑定框架类和primer.po
包:
import java.io.File; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.UnmarshalException; import javax.xml.bind.Unmarshaller; import javax.xml.bind.ValidationEvent; import javax.xml.bind.ValidationEventHandler; import javax.xml.bind.ValidationEventLocator; import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Schema; import primer.po.*;
- 创建一个用于处理在
primer.po
包中生成的类的JAXBContext
实例。
JAXBContext jc = JAXBContext.newInstance("primer.po");
- 创建一个
Unmarshaller
实例。
Unmarshaller u = jc.createUnmarshaller();
- 默认的 JAXB
Unmarshaller
ValidationEventHandler
已启用,以将验证警告和错误发送到system.out
。默认配置导致在遇到第一个验证错误时解组操作失败。
u.setValidating( true );
- 尝试将
po.xml
文件解组为 Java 内容树。在此示例中,po.xml
文件包含一个故意的错误。
PurchaseOrder po = (PurchaseOrder)u.unmarshal( new FileInputStream("po.xml"));
- 默认验证事件处理程序处理验证错误,生成输出到
system.out
,然后抛出异常。
} catch( UnmarshalException ue ) { System.out.println("Caught UnmarshalException"); } catch( JAXBException je ) { je.printStackTrace(); } catch( IOException ioe ) { ioe.printStackTrace(); }
使用 Ant 构建和运行 Unmarshal Validate 示例。
要使用 Ant 编译和运行 Unmarshal Validate 示例,在终端窗口中,转到 jaxb-ri-install/samples/unmarshal-validate/
目录,并输入以下内容:
ant
自定义 JAXB 绑定
以下部分描述了几个示例,这些示例是基于基本示例中演示的概念构建的。
本节的目标是演示如何使用自定义绑定声明来自定义 JAXB 绑定,可以通过以下两种方式之一进行:
- 作为内联注释在 XML 模式中
- 作为传递给 JAXB 绑定编译器的外部文件中的语句
与基本 JAXB 示例中的示例不同,该示例侧重于在生成基于模式的 Java 绑定类之前对 XML 模式进行的自定义。
注意: JAXB 绑定自定义目前必须手动完成。JAXB 技术的目标之一是标准化绑定声明的格式,从而可以创建自定义工具,并在 JAXB 实现之间提供标准的交换格式。
本节介绍了可以对 JAXB 绑定和验证方法进行的自定义。更多信息,请参见JAXB 规范。
为什么要自定义?
在大多数情况下,由 JAXB 绑定编译器生成的默认绑定就足够了。然而,有些情况下,您可能希望修改默认绑定。其中一些情况包括:
- 为基于模式的 JAXB 包、类、方法和常量创建 API 文档:通过向您的模式添加自定义 Javadoc 工具注释,您可以解释与您的实现特定的概念、指南和规则。
- 为默认的 XML 名称到 Java 标识符映射无法自动处理的情况提供语义上有意义的自定义名称;例如:
- 为解决名称冲突(如 JAXB 规范 的附录 D.2.1 中所述)。请注意,JAXB 绑定编译器会检测并报告所有名称冲突。
- 为类型安全枚举常量提供名称,这些名称不是有效的 Java 标识符;例如,枚举整数值。
- 为未命名模型组的 Java 表示提供更好的名称,当它们绑定到 Java 属性或类时。
- 提供比默认从目标命名空间 URI 派生的包名称更有意义的名称。
- 覆盖默认绑定;例如:
- 指定模型组必须绑定到类而不是列表。
- 指定一个固定属性可以绑定到一个 Java 常量。
- 覆盖 XML 模式内置数据类型到 Java 数据类型的指定默认绑定。在某些情况下,您可能希望引入一个替代的 Java 类,该类可以表示内置 XML 模式数据类型的其他特征。
自定义概述
本节解释了一些核心的 JAXB 自定义概念:
- 内联和外部自定义
- 范围、继承和优先级
- 自定义语法
- 定制命名空间前缀
内联和外部定制
对默认 JAXB 绑定的定制以传递给 JAXB 绑定编译器的绑定声明的形式进行。这些绑定声明可以通过以下两种方式进行:
- 作为源 XML 模式中的内联注释
- 作为外部绑定定制文件中的声明
对于一些人来说,使用内联定制更容易,因为您可以在应用于的模式的上下文中看到您的定制。相反,使用外部绑定定制文件使您能够定制 JAXB 绑定而无需修改源模式,并且使您能够轻松地将定制应用于多个模式文件。
注意: 您可以结合两种类型的定制。例如,您可以在内联注释中包含对外部绑定定制文件的引用。但是,您不能在同一模式元素上同时声明内联和外部定制。
这些类型的定制在以下各节中有更详细的描述:
内联定制
通过在 XML 模式文件中使用内联绑定声明进行的 JAXB 绑定定制采用了嵌入在模式元素中的
元素的形式(
xsd:
是 XML 模式命名空间前缀,在 W3C XML Schema Part 1: Structures中定义)。内联定制的一般形式如下例所示:
<xs:annotation> <xs:appinfo> <!-- ... binding declarations . ... --> </xs:appinfo> </xs:annotation>
定制是应用在模式中声明的位置。例如,对特定元素级别的声明仅适用于该元素。请注意,必须在和
声明标签中使用 XML 模式命名空间前缀。在前面的例子中,
xs:
被用作命名空间前缀,因此声明被标记为和
。
外部绑定定制文件
通过使用包含绑定声明的外部文件进行的 JAXB 绑定定制,采用了以下示例中显示的一般形式:
<jxb:bindings schemaLocation = "xs:anyURI"> <jxb:bindings node = "xs:string">* <!-- binding declaration --> <jxb:bindings> </jxb:bindings>
schemaLocation
是指向远程模式的 URI 引用。node
是一个 XPath 1.0 表达式,用于标识与给定绑定声明相关联的schemaLocation
中的模式节点。
例如,在 JAXB 绑定声明文件中,第一个schemaLocation
/node
声明指定了模式名称和根模式节点:
<jxb:bindings schemaLocation="po.xsd" node="/xs:schema"> </jxb:bindings>
后续的schemaLocation
/node
声明,例如前一个模式示例中名为ZipCodeType
的simpleType
元素,采用以下形式:
<jxb:bindings node="//xs:simpleType [@name=’ZipCodeType’]">
绑定定制文件格式
绑定定制文件必须是 ASCII 文本。名称或扩展名并不重要;尽管在本章中使用的典型扩展名是.xjb
。
将定制文件传递给 JAXB 绑定编译器
包含绑定声明的定制文件通过以下语法传递给 JAXB 绑定编译器xjc
:
xjc -b file schema
其中file是绑定自定义文件的名称,schema是要传递给绑定编译器的模式的名称。
您可以拥有一个包含多个模式的自定义的单个绑定文件,或者您可以将自定义分成多个绑定文件;例如:
xjc schema1.xsd schema2.xsd schema3.xsd \ -b bindings123.xjb xjc schema1.xsd schema2.xsd schema3.xsd \ -b bindings1.xjb \ -b bindings2.xjb \ -b bindings3.xjb
请注意,命令行上模式文件和绑定文件的顺序无关紧要;尽管每个绑定自定义文件在命令行上必须在其自己的-b
开关之前。
有关xjc
编译器选项的更多信息,请参见 JAXB 编译器选项。
外部绑定自定义的限制
有几条规则适用于在外部绑定自定义文件中进行的绑定声明,而不适用于在源模式中内联进行的类似声明:
- 绑定自定义文件必须以
jxb:bindings version
属性开头,以及 JAXB 和 XMLSchema 命名空间的属性:
<jxb:bindings version="1.0" >
- 绑定声明适用的远程模式必须通过使用
jxb:bindings
声明明确在 XPath 表示法中标识,指定schemaLocation
和node
属性:
schemaLocation
指定远程模式的 URI 引用。node
指定一个 XPath 1.0 表达式,用于标识schemaLocation
中的模式节点,给定的绑定声明与之相关联;在绑定自定义文件中的初始jxb:bindings
声明的情况下,此节点通常为"/xs:schema"
。
同样,必须使用 XPath 表示法指定要应用自定义的模式中的各个节点;例如:
<jxb:bindings node="//xs:complexType [@name=’USAddress’]">
在这种情况下,绑定编译器将自定义应用于节点,就好像声明被嵌入在节点的元素中一样。
总结这些规则,外部绑定元素仅在以下三种情况下被 JAXB 绑定编译器识别并处理:
- 当其父元素是
元素时。
- 当它是另一个
元素的祖先时。
- 当它是文档的根元素时。将
元素作为其根的 XML 文档称为外部绑定声明文件。
范围、继承和优先级
默认的 JAXB 绑定可以在四个不同级别或范围上进行自定义或覆盖。
以下图示了自定义声明的继承和优先级。具体来说,金字塔顶部的声明继承并取代下面的声明。
组件声明继承并取代定义声明;定义声明继承并取代模式声明;模式声明继承并取代全局声明。
图:自定义范围继承和优先级
自定义语法
JAXB 绑定声明的四种类型的语法,XML 到 Java 数据类型绑定声明的语法,以及自定义命名空间前缀的语法在以下部分中描述。
- 全局绑定声明
- 模式绑定声明
- 类绑定声明
- 属性绑定声明
- javaType 绑定声明
- Typesafe 枚举绑定声明
- javadoc 绑定声明
全局绑定声明
全局范围的自定义使用 声明。全局范围自定义的语法如下:
<globalBindings> [ collectionType = "collectionType" ] [ fixedAttributeAsConstantProperty = "true" | "false" | "1" | "0" ] [ generateIsSetMethod = "true" | "false" | "1" | "0" ] [ enableFailFastCheck = "true" | "false" | "1" | "0" ] [ choiceContentProperty = "true" | "false" | "1" | "0" ] [ underscoreBinding = "asWordSeparator" | "asCharInWord" ] [ typesafeEnumBase = "typesafeEnumBase" ] [ typesafeEnumMemberName = "generateName" | "generateError" ] [ enableJavaNamingConventions = "true" | "false" | "1" | "0" ] [ bindingStyle = "elementBinding" | "modelGroupBinding" ] [ <javaType> ... </javaType> ]* </globalBindings>
collectionType
可以是indexed
或实现java.util.List
的任何完全限定类名。fixedAttributeAsConstantProperty
可以是true
,false
,1
, 或0
。默认值为false
。generateIsSetMethod
可以是true
,false
,1
, 或0
。默认值为false
。enableFailFastCheck
可以是true
,false
,1
, 或0
。如果enableFailFastCheck
是true
或1
,并且 JAXB 实现支持此可选检查,那么在设置属性时将执行类型约束检查。默认值为false
。请注意,JAXB 实现不支持快速失败验证。choiceContentProperty
可以是true
,false
,1
, 或0
。默认值为false
。当bindingStyle
是elementBinding
时,choiceContentProperty
不相关。因此,如果指定bindingStyle
为elementBinding
,那么choiceContentProperty
必须导致无效的自定义。underscoreBinding
可以是asWordSeparator
或asCharInWord
。默认值为asWordSeparator
。typesafeEnumBase
可以是一组 QNames,每个都必须解析为简单类型定义。默认值为xs:NCName
。有关将simpleType
定义本地化映射到 Javatypesafe enum
类的信息,请参见 Typesafe 枚举绑定声明。typesafeEnumMemberName
可以是generateError
或generateName
。默认值为generateError
。enableJavaNamingConventions
可以是true
,false
,1
, 或0
。默认值为true
。bindingStyle
可以是elementBinding
或modelGroupBinding
。默认值为elementBinding
。可以是零个或多个 javaType 绑定声明。有关更多信息,请参见 javaType 绑定声明。
声明仅在顶层
schema
元素的 annotation
元素中有效。在任何给定的模式或绑定声明文件中只能有一个 声明的实例。如果一个源模式包含或导入第二个源模式,则
声明必须在第一个源模式中声明。
模式绑定声明
模式范围的自定义使用 声明。模式范围自定义的语法如下:
<schemaBindings> [ <package> package </package> ] [ <nameXmlTransform> ... </nameXmlTransform> ]* </schemaBindings> <package [ name = "packageName" ] [ <javadoc> ... </javadoc> ] </package> <nameXmlTransform> [ <typeName [ suffix="suffix" ] [ prefix="prefix" ] /> ] [ <elementName [ suffix="suffix" ] [ prefix="prefix" ] /> ] [ <modelGroupName [ suffix="suffix" ] [ prefix="prefix" ] /> ] [ <anonymousTypeName [ suffix="suffix" ] [ prefix="prefix" ] /> ] </nameXmlTransform>
如上所示, 声明包括两个子组件:
...
指定了包的名称,如果需要的话,还可以指定模式派生类的 API 文档的位置。...
指定要应用的自定义。
类绑定声明
绑定声明使您能够自定义模式元素与 Java 内容接口或 Java
Element
接口的绑定。 声明可用于自定义:
- 用于模式派生的 Java 接口的名称
- 用于模式派生的 Java 内容接口的实现类
自定义的语法是:
<class [ name = "className"] [ implClass= "implClass" ] > [ <javadoc> ... </javadoc> ] </class>
name
是派生 Java 接口的名称。它必须是有效的 Java 接口名称,不能包含包前缀。包前缀从当前包的值继承。implClass
是 className 的实现类的名称,必须包含完整的包名称。元素为模式派生的 Java 接口指定了 Javadoc 工具注释。在此输入的字符串必须使用
CDATA
或<
来转义嵌入的 HTML 标记。
属性绑定声明
绑定声明使您能够自定义 XML 模式元素与其 Java 表示作为属性的绑定。自定义的范围可以是在定义级别或组件级别,具体取决于
绑定声明的指定位置。
自定义的语法是:
<property [ name = "propertyName"] [ collectionType = "propertyCollectionType" ] [ fixedAttributeAsConstantProperty = "true" | "false" | "1" | "0" ] [ generateIsSetMethod = "true" | "false" | "1" | "0" ] [ enableFailFastCheck ="true" | "false" | "1" | "0" ] [ <baseType> ... </baseType> ] [ <javadoc> ... </javadoc> ] </property> <baseType> <javaType> ... </javaType> </baseType>
name
定义了自定义值propertyName
;它必须是有效的 Java 标识符。collectionType
定义了自定义值propertyCollectionType
,即属性的集合类型propertyCollectionType
。如果指定,属性可以是indexed
或任何实现java.util.List
的完全限定类名。fixedAttributeAsConstantProperty
定义了自定义值fixedAttributeAsConstantProperty
。该值可以是true
、false
、1
或0
。generateIsSetMethod
定义了自定义值generateIsSetMethod
。该值可以是true
、false
、1
或0
。enableFailFastCheck
定义了自定义值enableFailFastCheck
。该值可以是true
、false
、1
或0
。请注意,JAXB 实现不支持快速失败验证。自定义了属性的 getter 方法的 Javadoc 工具注释。
Java 中文官方教程 2022 版(四十九)(3)https://developer.aliyun.com/article/1488535