此内容没有您所选择的语言版本。
35.2. Substitution Groups in Java
Overview
Apache CXF, as specified in the JAXB specification, supports substitution groups using Java's native class hierarchy in combination with the ability of the
JAXBElement
class' support for wildcard definitions. Because the members of a substitution group must all share a common base type, the classes generated to support the elements' types also share a common base type. In addition, Apache CXF maps instances of the head element to JAXBElement<? extends T>
properties.
Generated object factory methods
The object factory generated to support a package containing a substitution group has methods for each of the elements in the substitution group. For each of the members of the substitution group, except for the head element, the
@XmlElementDecl
annotation decorating the object factory method includes two additional properties, as described in Table 35.1, “Properties for Declaring a JAXB Element is a Member of a Substitution Group”.
Property | Description |
---|---|
substitutionHeadNamespace | Specifies the namespace where the head element is defined. |
substitutionHeadName | Specifies the value of the head element's name attribute. |
The object factory method for the head element of the substitution group's
@XmlElementDecl
contains only the default namespace property and the default name property.
In addition to the element instantiation methods, the object factory contains a method for instantiating an object representing the head element. If the members of the substitution group are all of complex types, the object factory also contains methods for instantiating instances of each complex type used.
Example 35.5, “Object Factory Method for a Substitution Group” shows the object factory method for the substitution group defined in Example 35.2, “Substitution Group with Complex Types”.
Example 35.5. Object Factory Method for a 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); } }
Substitution groups in interfaces
If the head element of a substitution group is used as a message part in one of an operation's messages, the resulting method parameter will be an object of the class generated to support that element. It will not necessarily be an instance of the
JAXBElement<? extends T>
class. The runtime relies on Java's native type hierarchy to support the type substitution, and Java will catch any attempts to use unsupported types.
To ensure that the runtime knows all of the classes needed to support the element substitution, the SEI is decorated with the
@XmlSeeAlso
annotation. This annotation specifies a list of classes required by the runtime for marshalling. Fore more information on using the @XmlSeeAlso
annotation see Section 30.4, “Adding Classes to the Runtime Marshaller”.
Example 35.7, “Generated Interface Using a Substitution Group” shows the SEI generated for the interface shown in Example 35.6, “WSDL Interface Using a Substitution Group”. The interface uses the substitution group defined in Example 35.2, “Substitution Group with Complex Types”.
Example 35.6. WSDL Interface Using a Substitution Group
<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>
Example 35.7. Generated Interface Using a 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
);
}
Tip
The SEI shown in Example 35.7, “Generated Interface Using a Substitution Group” lists the object factory in the
@XmlSeeAlso
annotation. Listing the object factory for a namespace provides access to all of the generated classes for that namespace.
Substitution groups in complex types
When the head element of a substitution group is used as an element in a complex type, the code generator maps the element to a
JAXBElement<? extends T>
property. It does not map it to a property containing an instance of the generated class generated to support the substitution group.
For example, the complex type defined in Example 35.8, “Complex Type Using a Substitution Group” results in the Java class shown in Example 35.9, “Java Class for a Complex Type Using a Substitution Group”. The complex type uses the substitution group defined in Example 35.2, “Substitution Group with Complex Types”.
Example 35.8. Complex Type Using a Substitution Group
<complexType name="widgetOrderInfo">
<sequence>
<element name="amount" type="xsd:int"/>
<element ref="xsd1:widget"/>
</sequence>
</complexType>
Example 35.9. Java Class for a Complex Type Using a Substitution Group
@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); } }
Setting a substitution group property
How you work with a substitution group depends on whether the code generator mapped the group to a straight Java class or to a
JAXBElement<? extends T>
class. When the element is simply mapped to an object of the generated value class, you work with the object the same way you work with other Java objects that are part of a type hierarchy. You can substitute any of the subclasses for the parent class. You can inspect the object to determine its exact class, and cast it appropriately.
Tip
The JAXB specification recommends that you use the object factory methods for instantiating objects of the generated classes.
When the code generators create a
JAXBElement<? extends T>
object to hold instances of a substitution group, you must wrap the element's value in a JAXBElement<? extends T>
object. The best method to do this is to use the element creation methods provided by the object factory. They provide an easy means for creating an element based on its value.
Example 35.10, “Setting a Member of a Substitution Group” shows code for setting an instance of a substitution group.
Example 35.10. Setting a Member of a Substitution Group
ObjectFactory of = new ObjectFactory(); 1 PlasticWidgetType pWidget = of.createPlasticWidgetType(); 2 pWidget.setShape = "round'; pWidget.setColor = "green"; pWidget.setMoldProcess = "injection"; JAXBElement<PlasticWidgetType> widget = of.createPlasticWidget(pWidget); 3 WidgetOrderInfo order = of.createWidgetOrderInfo(); 4 order.setWidget(widget); 5
The code in Example 35.10, “Setting a Member of a Substitution Group” does the following:
- 1
- Instantiates an object factory.
- 2
- Instantiates a
PlasticWidgetType
object. - 3
- Instantiates a
JAXBElement<PlasticWidgetType>
object to hold a plastic widget element. - 4
- Instantiates a
WidgetOrderInfo
object. - 5
- Sets the
WidgetOrderInfo
object's widget to theJAXBElement
object holding the plastic widget element.
Getting the value of a substitution group property
The object factory methods do not help when extracting the element's value from a
JAXBElement<? extends T>
object. You must to use the JAXBElement<? extends T>
object's getValue()
method. The following options determine the type of object returned by the getValue()
method:
- Use the
isInstance()
method of all the possible classes to determine the class of the element's value object. - Use the
JAXBElement<? extends T>
object'sgetName()
method to determine the element's name.ThegetName()
method returns a QName. Using the local name of the element, you can determine the proper class for the value object. - Use the
JAXBElement<? extends T>
object'sgetDeclaredType()
method to determine the class of the value object.ThegetDeclaredType()
method returns theClass
object of the element's value object.WarningThere is a possibility that thegetDeclaredType()
method will return the base class for the head element regardless of the actual class of the value object.
Example 35.11, “Getting the Value of a Member of the Substitution Group” shows code retrieving the value from a substitution group. To determine the proper class of the element's value object the example uses the element's
getName()
method.
Example 35.11. Getting the Value of a Member of the Substitution Group
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(); }