37.2. Java 中的替换组

概述

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

生成的对象工厂方法

为支持包含替换组群的软件包生成的对象工厂有方法用于替换组中的每个元素。对于每个替换组的成员,除了 head 元素外,@XmlElementDecl 注解会包括两个额外的属性,如 表 37.1 “Declaring a JAXB Element 的属性是子组的成员” 所述。

表 37.1. Declaring a JAXB Element 的属性是子组的成员

属性描述

substitutionHeadNamespace

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

substitutionHeadName

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

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

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

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

例 37.5. 用于子组的对象因素方法

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> 类。运行时依赖于 Java 的原生类型层次结构来支持类型替换,Java 将捕获任何使用不支持的类型的尝试。

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

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

例 37.6. 使用 Substitution 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. 使用替换组生成的接口

@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<? 扩展 T> 属性。它没有映射到包含生成的类实例的属性,以支持替换组。

例如: 例 37.8 “使用 Substitution Group 的复杂类型” 中定义的复杂类型会导致 例 37.9 “使用子组进行复杂类型的 Java 类” 中显示的 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. 使用子组进行复杂类型的 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 > 对象来存放替换组的实例,您必须将元素的值嵌套在 JAXBElement<? 扩展 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; 对象以容纳 platformstic widget 元素。

实例化 小部件OrderInfo 对象。

将 widget OrderInfo 对象的 widget 设置为含有 plastic widget 元素的 JAXBElement 对象。

获取替换组属性值

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

  • 使用所有可能类的 isInstance() 方法来确定元素的值对象的类。
  • 使用 JAXBElement<? 扩展 T > 对象的 getName() 方法,以确定元素的名称。

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

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

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

    警告

    对于 head 元素,无论值对象的实际类如何,getDeclaredType() 方法会返回基础类。

例 37.11 “获取子组成员组成员” 显示从替换组中检索值的代码。要确定元素的值对象的正确类,示例中使用了该元素的 getName() 方法。

例 37.11. 获取子组成员组成员

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