JavaTM Architecture for XML Binding

Implications of Type Substitution for Subclassing

Specification Version: 1.0
Reference Implementation (RI) Version: 1.0.2

You can enable type substitution support in your bindings by adding a customization to your schema and using the -extension switch when you recompile. This may have implications for your application if, in addition, your bindings support application-specific subclasses incorporated by way of the implClass customization.

To support type substitution, a schema-derived element impl class no longer extends its type's impl class. Instead, the element impl class has a reference to an instance of that type or any type that extends the element's schema defined type.

For example, given this schema,

<element name="foo" type="Base"/>
<complexType name="Base"> ...
<complexType name="Derived">... <xs:extension base="Base">

The generated impl class for element foo used to be:

impl/Foo.java
class Foo extends impl.Base {}

To support type substitution that allows instances of "Derived" to be associated with element foo, the following code is generated by JAXB 1.0.2 xjc with extension mode on:

impl/Foo.java
class Foo implements Base {
   Base getValueObject();
   /** val can be of type "Base" or "Derived"
   void setValueObject(Base val);

   // all methods on Base can be called.
}

If your subclass contains the method methodInSubclass, let's say, and you created your bindings without type substitution support, you can access methodInSubclass simply by casting the returned Element instance down to your subclass:

((subclass)FooElementInstance).methodInSubclass

However, if you regenerate your bindings with type substitution support, this technique now results in a ClassCastException at runtime. The fix is to cast the object returned by the unmarshalled object's getValueObject() method down to your subclass.

For example, let's say you have a MyUSAddress class that extends the schema-derived class primer.address.USAddress. That is, your schema contains:

<xsd:annotation>
  <xsd:appinfo>
    <jxb:schemaBindings>
      <jxb:package name="primer.address"/>
    </jxb:schemaBindings>
  </xsd:appinfo>
</xsd:annotation>

<xsd:complexType name="USAddress">
  <xsd:annotation>
    <xsd:appinfo>
      <jxb:class implClass="primer.MyUSAddress"/>
    </xsd:appinfo>
  </xsd:annotation>
.
.
.

If your schema's not customized for type substitution, then the following application code would work with the resulting bindings:

primer.MyUSAddress myAddr = 
    (primer.MyUSAddress)u.unmarshal(new FileInputStream("address.xml"));
where address.xml contains:
<Address country="US">
    <name>Alice Smith</name>
    <street>123 Maple Street</street>
    <city>Cambridge</city>
    <state>MA</state>
    <zip>12345</zip>
</Address>
That is, it would be okay to cast the unmarshalled object down to your primer.MyUSAddress.

However if, for some reason, you were to add an typeSubstitution customization to your schema and recompile, your application would fail with a ClassCastException. The fix is to cast the object returned by the getValueObject() method that the schema-derived class now contains down to MyUSAddress:

Address addr = (Address)u.unmarshal(new FileInputStream("address.xml"));
primer.MyUSAddress myAddr=(primer.MyUSAddress)addr.getValueObject();

Type substitution support is experimental at present. JAXB 2.0 will specify the standard binding for type substitution.


$Revision: 1.3 $
$Date: 2003/09/26 18:48:14 $