FUSE Services Framework, 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, FUSE Services Framework maps instances of the head element to
JAXBElement<? extends T>
properties.
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 15.1.
Table 15.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 15.5 shows the object factory method for the substitution group defined in Example 15.2.
Example 15.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); } }
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
Adding Classes to the Runtime Marshaller.
Example 15.7 shows the SEI generated for the interface shown in Example 15.6. The interface uses the substitution group defined in Example 15.2.
Example 15.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 15.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 15.7 lists the object factory in the |
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 15.8 results in the Java class shown in Example 15.9. The complex type uses the substitution group defined in Example 15.2.
Example 15.8. Complex Type Using a Substitution Group
<complexType name="widgetOrderInfo">
<sequence>
<element name="amount" type="xsd:int"/>
<element ref="xsd1:widget"/>
</sequence>
</complexType>
Example 15.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); } }
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 15.10 shows code for setting an instance of a substitution group.
Example 15.10. Setting a Member of a Substitution Group
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);
The code in Example 15.10 does the following:
Instantiates an object factory. | |
Instantiates a | |
Instantiates a | |
Instantiates a | |
Sets the |
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's getName()
method to determine the element's name.
The getName()
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's getDeclaredType()
method to determine the class of the value object.
The getDeclaredType()
method returns the Class
object of
the element's value object.
![]() | Warning |
---|---|
There is a possibility that the |
Example 15.11 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 15.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(); }