37.2. Substitution Groups in Java
Overview
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
@XmlElementDecl
annotation decorating the object factory method includes two additional properties, as described in Table 37.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. |
@XmlElementDecl
contains only the default namespace property and the default name property.
Example 37.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
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.
@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 32.4, “Adding Classes to the Runtime Marshaller”.
Example 37.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 37.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
);
}
@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
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.
Example 37.8. Complex Type Using a Substitution Group
<complexType name="widgetOrderInfo">
<sequence>
<element name="amount" type="xsd:int"/>
<element ref="xsd1:widget"/>
</sequence>
</complexType>
Example 37.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
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.
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 37.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
- 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
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.
getName()
method.
Example 37.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(); }