37.2. 在 Java 中替换组
概述
根据 JAXB 规范中指定的 Apache CXF,支持使用 Java 的原生类层次结构替换组,以及 JAXBElement
类对通配符定义的支持的功能。由于替换组的成员必须全部共享一个通用基本类型,因此为支持元素的类型而生成的类也共享一个通用的基本类型。此外,Apache CXF 将 head 元素的实例映射到 JAXBElement<? 扩展 T>
属性。
生成的对象工厂方法
生成对象工厂来支持包含替换组的软件包有替换组中的每个元素的方法。对于替换组的每个成员,但 head 元素除外,@XmlElementDecl
注解会减少对象工厂方法包括两个额外的属性,如 表 37.1 “Declaring a JAXB Element 的属性是 Substitution 组成员” 所述。
属性 | 描述 |
---|---|
| 指定定义 head 元素的命名空间。 |
|
指定 head 元素的 |
替换组的 @XmlElementDecl
的 head 元素的对象工厂方法仅包含 default namespace
属性和默认 name
属性。
除了元素实例化方法外,对象工厂还包含一个代表 head 元素的实例化对象的方法。如果替换组的成员都是复杂的类型,对象工厂还包含使用每种复杂类型的实例化实例的方法。
例 37.5 “Substitution 组的对象工厂方法” 显示 例 37.2 “使用复杂类型替换组” 中定义的替换组的对象工厂方法。
例 37.5. Substitution 组的对象工厂方法
public class ObjectFactory { private final static QName _Widget_QNAME = new QName(...); private final static QName _PlasticWidget_QNAME = new QName(...); private final static QName _WoodWidget_QNAME = new QName(...); public ObjectFactory() { } public WidgetType createWidgetType() { return new WidgetType(); } public PlasticWidgetType createPlasticWidgetType() { return new PlasticWidgetType(); } public WoodWidgetType createWoodWidgetType() { return new WoodWidgetType(); } @XmlElementDecl(namespace="...", name = "widget") public JAXBElement<WidgetType> createWidget(WidgetType value) { return new JAXBElement<WidgetType>(_Widget_QNAME, WidgetType.class, null, value); } @XmlElementDecl(namespace = "...", name = "plasticWidget", substitutionHeadNamespace = "...", substitutionHeadName = "widget") public JAXBElement<PlasticWidgetType> createPlasticWidget(PlasticWidgetType value) { return new JAXBElement<PlasticWidgetType>(_PlasticWidget_QNAME, PlasticWidgetType.class, null, value); } @XmlElementDecl(namespace = "...", name = "woodWidget", substitutionHeadNamespace = "...", substitutionHeadName = "widget") public JAXBElement<WoodWidgetType> createWoodWidget(WoodWidgetType value) { return new JAXBElement<WoodWidgetType>(_WoodWidget_QNAME, WoodWidgetType.class, null, value); } }
在接口中替换组
如果将替换组的 head 元素用作操作消息中的一个消息部分,则生成的 method 参数将是为支持该元素生成的类对象。它不一定是 JAXBElement<? extends T&
gt; 类的实例。运行时依赖于 Java 的原生类型层次结构来支持类型替换,Java 将捕获任何尝试使用不支持的类型。
为确保运行时知道支持元素替换所需的所有类,而 SEI 被认为是 @XmlSeeAlso
注释。此注解指定运行时为 marshalling 所需的类列表。有关使用 @XmlSeeAlso
注释的更多信息,请参阅 第 32.4 节 “将类添加到 Runtime Marshaller”。
例 37.7 “使用替换组生成接口” 显示为 例 37.6 “使用替换组的 WSDL 接口” 中显示的接口生成的 SEI。接口使用 例 37.2 “使用复杂类型替换组” 中定义的替换组。
例 37.6. 使用替换组的 WSDL 接口
<message name="widgetMessage"> <part name="widgetPart" element="xsd1:widget" /> </message> <message name="numWidgets"> <part name="numInventory" type="xsd:int" /> </message> <message name="badSize"> <part name="numInventory" type="xsd:int" /> </message> <portType name="orderWidgets"> <operation name="placeWidgetOrder"> <input message="tns:widgetOrder" name="order" /> <output message="tns:widgetOrderBill" name="bill" /> <fault message="tns:badSize" name="sizeFault" /> </operation> <operation name="checkWidgets"> <input message="tns:widgetMessage" name="request" /> <output message="tns:numWidgets" name="response" /> </operation> </portType>
例 37.7. 使用替换组生成接口
@WebService(targetNamespace = "...", name = "orderWidgets")
@XmlSeeAlso({com.widgetvendor.types.widgettypes.ObjectFactory.class})
public interface OrderWidgets {
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@WebResult(name = "numInventory", targetNamespace = "", partName = "numInventory")
@WebMethod
public int checkWidgets(
@WebParam(partName = "widgetPart", name = "widget", targetNamespace = "...")
com.widgetvendor.types.widgettypes.WidgetType widgetPart
);
}
例 37.7 “使用替换组生成接口” 中显示的 SEI 列出了 @XmlSeeAlso
注释中的对象工厂。列出命名空间的对象工厂可以访问该命名空间的所有生成的类。
在复杂类型中替换组
当替换组的 head 元素用作复杂类型中的一个元素时,代码生成器会将元素映射到 JAXBElement<? extends T>
属性。它不会将它映射到包含生成的类实例的属性,以支持替换组。
例如: 例 37.8 “使用替换组进行复杂类型” 中定义的复杂类型会导致 Java 类在 例 37.9 “使用 Substitution Group 的复杂类型的 Java 类” 中显示。复杂类型使用 例 37.2 “使用复杂类型替换组” 中定义的替换组。
例 37.8. 使用替换组进行复杂类型
<complexType name="widgetOrderInfo">
<sequence>
<element name="amount" type="xsd:int"/>
<element ref="xsd1:widget"/>
</sequence>
</complexType>
例 37.9. 使用 Substitution Group 的复杂类型的 Java 类
@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "widgetOrderInfo", propOrder = {"amount","widget",}) public class WidgetOrderInfo { protected int amount; @XmlElementRef(name = "widget", namespace = "...", type = JAXBElement.class) protected JAXBElement<? extends WidgetType> widget; public int getAmount() { return amount; } public void setAmount(int value) { this.amount = value; } public JAXBElement<? extends WidgetType> getWidget() { return widget; } public void setWidget(JAXBElement<? extends WidgetType> value) { this.widget = ((JAXBElement<? extends WidgetType> ) value); } }
设置替换组属性
您如何使用替换组,这取决于将组映射到直接 Java 类还是一个 JAXBElement<? extends T>
; 类的代码生成器。当元素直接映射到生成的值类的对象时,您可以像使用属于类型层次结构的其他 Java 对象一样使用对象。您可以将任何子类替换为父类。您可以检查对象以确定其确切的类,并相应地广播它。
JAXB 规格建议您使用对象工厂方法来实例化所生成类的对象。
当代码生成器创建 JAXBElement<? 扩展 T
> 对象来保存替换组的实例时,您必须将元素的值嵌套在 JAXBElement<? extends T>
对象中。执行此操作的最佳方法是使用对象工厂提供的元素创建方法。它们提供了一种简单的方法,可以基于其值创建元素。
例 37.10 “设置替换组成员” 显示设置替换组实例的代码。
例 37.10. 设置替换组成员
ObjectFactory of = new ObjectFactory(); PlasticWidgetType pWidget = of.createPlasticWidgetType(); pWidget.setShape = "round'; pWidget.setColor = "green"; pWidget.setMoldProcess = "injection"; JAXBElement<PlasticWidgetType> widget = of.createPlasticWidget(pWidget); WidgetOrderInfo order = of.createWidgetOrderInfo(); order.setWidget(widget);
例 37.10 “设置替换组成员” 中的代码执行以下操作:
实例化对象工厂。
实例化 PlasticWidgetType
对象。
实例化 JAXBElement<PlasticWidgetType&
gt; 对象来容纳 plastic widget 元素。
实例化 WidgetOrderInfo
对象。
将 WidgetOrderInfo
对象的小部件设置为含有 plastic widget
元素的 JAXBElement
对象。
获取替换组属性的值
从 JAXBElement<? extends T
> 对象提取元素值时,对象工厂方法无法帮助。您必须使用 JAXBElement<? 扩展 T>
; 对象的 getValue ()
方法。以下选项决定了 getValue ()
方法返回的对象类型:
-
使用所有可能类的
isInstance ()
方法来确定元素的值对象的类。 使用
JAXBElement<? extends T
> 对象的getName ()
方法来确定元素的名称。getName ()
方法返回一个 QName。使用元素的本地名称,您可以为 value 对象确定正确的类。使用
JAXBElement<? extends T
> 对象的getDeclaredType ()
方法来确定 value 对象的类。getDeclaredType ()
方法返回元素值对象的Class
对象。警告getDeclaredType ()
方法有可能返回 head 元素的基本类,而不考虑 value 对象的实际类。
例 37.11 “获取 Substitution 组成员的值” 显示从替换组检索值的代码。要确定元素值对象的正确类,示例使用元素的 getName ()
方法。
例 37.11. 获取 Substitution 组成员的值
String elementName = order.getWidget().getName().getLocalPart(); if (elementName.equals("woodWidget") { WoodWidgetType widget=order.getWidget().getValue(); } else if (elementName.equals("plasticWidget") { PlasticWidgetType widget=order.getWidget().getValue(); } else { WidgetType widget=order.getWidget().getValue(); }