37.2. 在 Java 中替换组

概述

Apache CXF (如 JAXB 规范中指定的)支持使用 Java 的原生类层次结构替换组,并结合 JAXBElement 类对通配符定义的支持。由于替换组的成员必须全部共享一个共同的基础类型,因此生成的类以支持元素的类型也共享一个通用基本类型。另外,Apache CXF 将 head 元素的实例映射到 JAXBElement<?扩展了 T> 属性。

生成的对象工厂方法

对象工厂生成来支持包含替换组的软件包有方法,对于替换组中的每个元素都有方法。对于替换组的每个成员,除 head 元素外,@XmlElementDecl 注解会减少对象工厂方法包含两个额外属性,如 表 37.1 “Declaring a JAXB Elements 的属性是 Substitution Group 的成员” 所述。

表 37.1. Declaring a JAXB Elements 的属性是 Substitution Group 的成员

属性描述

substitutionHeadNamespace

指定定义 head 元素的命名空间。

substitutionHeadName

指定 head 元素的 name 属性的值。

替换组的 @XmlElementDecl 的 head 元素的对象工厂方法仅包含 default 命名空间 属性和默认 name 属性。

除了元素实例化方法外,对象工厂还包含一个代表头元素的对象实例化的方法。如果替换组的成员是所有复杂的类型,则对象工厂还包含用于实例化各种复杂类型的实例的方法。

例 37.5 “Substitution Group 的对象因素方法” 显示 例 37.2 “使用复杂类型替换组” 中定义的替换组的对象工厂方法。

例 37.5. Substitution Group 的对象因素方法

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 元素用作操作消息之一中的消息部分,则生成的方法参数将是生成的类的对象,以支持该元素。它不一定是 JAXBElement< 扩展 T& gt; 类的实例。运行时依赖于 Java 的原生类型层次结构来支持类型替换,Java 将捕获任何尝试使用不受支持的类型。

为确保运行时知道需要支持元素替换的所有类,SEI 被解码为 @XmlSeeAlso 注释。此注解指定运行时为 marshalling 所需的类列表。有关使用 @XmlSeeAlso 注释的更多信息,请参阅 第 32.4 节 “在 Runtime Marshaller 中添加类”

例 37.7 “使用 Substitution Group 生成的接口” 显示为 例 37.6 “使用 Substution Group 的 WSDL 接口” 中显示的接口生成的 SEI。接口使用 例 37.2 “使用复杂类型替换组” 中定义的替换组。

例 37.6. 使用 Substution Group 的 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. 使用 Substitution Group 生成的接口

@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 “使用 Substitution Group 生成的接口” 中显示的 SEI 列出 @XmlSeeAlso 注解中的对象工厂。列出命名空间的对象工厂提供对该命名空间生成的所有类的访问。

用复杂类型替换组

当替换组的 head 元素用作复杂类型中的元素时,代码生成器将元素映射到 JAXBElement<?扩展了 T> 属性。它不会将它映射到包含所生成的类实例的属性,以支持替换组。

例如: 例 37.8 “使用 Substitution Group 的复杂类型” 中定义的复杂类型会导致 Java 类在 例 37.9 “使用 Substitution Group 进行复杂类型的 Java 类” 中显示。复杂类型使用 例 37.2 “使用复杂类型替换组” 中定义的替换组。

例 37.8. 使用 Substitution Group 的复杂类型

<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< 中的代码生成器?扩展了 T > 类。当元素映射到生成值类的对象时,您可以使用对象的方式与作为类型层次结构一部分的其他 Java 对象搭配使用。您可以替换父类的任何子类。您可以检查对象,以确定其准确的类,并适当地广播对象。

JAXB 规格建议您使用对象工厂方法实例化所生成的类的对象。

当代码生成器创建 JAXBElement< 扩展了 T& gt; 对象来保存替换组的实例时,您必须将元素的值嵌套在 JAXBElement< 中?扩展了 T> 对象。执行此操作的最佳方式是使用对象工厂提供的元素创建方法。它们提供了一种基于其值创建元素的简单方法。

例 37.10 “设置 Substitution 组的成员” 显示设置替换组实例的代码。

例 37.10. 设置 Substitution 组的成员

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 “设置 Substitution 组的成员” 中的代码执行以下操作:

实例化对象工厂。

实例化 PlasticWidgetType 对象。

实例化 JAXBElement<PlasticWidgetType& gt; 对象来容纳 plastic widget 元素。

实例化 WidgetOrderInfo 对象。

WidgetOrderInfo 对象的小部件设置为含有 plastic widget 元素的 JAXBElement 对象。

获取替换组属性的值

在从 JAXBElement< 中提取元素的值<中扩展了 T > 对象时,对象工厂方法没有帮助。您必须使用 JAXBElement<?扩展了 T&gt; 对象的 getValue () 方法。以下选项决定了 getValue () 方法返回的对象类型:

  • 使用 all possible 类的 isInstance () 方法来确定元素的值对象的类。
  • 使用 JAXBElement<? 扩展 T > 对象的 getName () 方法来确定元素的名称。

    getName () 方法返回 QName。使用元素的本地名称,您可以为 value 对象确定正确的类。

  • 使用 JAXBElement<? 扩展 T > 对象的 getDeclaredType () 方法来确定值对象的类。

    getDeclaredType () 方法返回元素的值对象的 Class 对象。

    警告

    无论 value 对象的实际类是什么,getDeclaredType () 方法可能会返回 head 元素的基础类。

例 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();
}