Inheritence

The Java programming language support class inheritence, including multiple interface interitence. XML does support a similar concept using a veriety of tools - type substitution, substitution groups, union and choice.

Substitution Groups allows to substitute an XML element with another XML element with a derived type. We write another XML element instead of the original one (with a different name). Substitution groups works only for XML elements (XML attributes are not supported) and allows to introduce new substitutions without changing the original XML Schema. This feature is the most similar one in XML to Java inheritence. However, it is a complicated feature that a lot of developer avoid. J2XB makes the use of Substitution groups seemless.

Type Substitution offers a similar mechanism to Substitution Groups. At this time, J2XB does not support Type Substitution.

Union allows to create simple XML types that are multi-valued - a type that is both a String and a Date, or a type that can be represented as a Integer, a Float or a Date. Union types can be used as any other simple XML type, in XML elements, XML attributes and XML lists (XML style list). J2XB Supports Union types for Atomic inheritence.

Some developers like to map Bean inheritence as a choice property that allows to select between the supported derived types. By defining an XML element with a choice content model. However, such mapping includes a specific list of supported derived types and cannot be extended without changing the XML Schema or the annotation on the class defining the XML Schema. At this time, J2XB does not support this inheritence pattern.

Bean Inheritence and Substitution Groups

By default (as per XML Schema definition), any XML element can be substituted by any other global XML element with a derived type. This requirement, when transfered to the language of J2XB, means that the parent bean must have a global XML type and the child beans must be defined as global XML elements. J2XB also adds the restriction that the child bean must also be mapped with a global XML type because they may also be parent beans of other child beans introduced later (multi-level inheritence).

Those restricutions translate to that J2XB requires all the Beans involved in a polymorphic property to be mapped using @MOPersistentBean and @MOXmlGlobalType annotations (the @MOPersistentDependentBean annotation is not allowed).

Note that conformance to those requirements is all that is required for a set of Java classes to support Substitution Groups.

For example, assume we have a Drawing class with a list of Shape instances (the Shape class is abstract). We have two derived classes of Shape - the Square and Circle classes.

The code for the classes can be seen here: Circle , Square , Drawing and Shape .

The Shape class is mapped using

@MOPersistentBean(xmlName = "Shape")
@MOXmlGlobalType("ShapeType")
@MOXmlNamespace(value = "http://example.abra.com/inheritence/shapes", preferedPrefix = "ex14")
public abstract class Shape {...}

and the Square class (as an example) using

@MOPersistentBean(xmlName = "Square")
@MOXmlGlobalType("SquareType")
@MOXmlNamespace(value = "http://example.abra.com/inheritence/shapes", preferedPrefix = "ex14")
public class Square extends Shape {...}

The collection at the Drawing class is defined as

@MOProperty
public List<Shape> getShapes() {...}

Now, the XML Schema created for this set of classes is

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:ex14="http://example.abra.com/inheritence/shapes"
    targetNamespace="http://example.abra.com/inheritence/shapes"
    elementFormDefault="qualified" attributeFormDefault="unqualified">

  <xs:element name="Drawing" type ="ex14:DrawingType"/>
  <xs:complexType name="DrawingType">
    <xs:sequence>
      <xs:element name="shapes" type="ex14:ShapeType" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:element name="Shape" type ="ex14:ShapeType" abstract="true"/>
  <xs:complexType name="ShapeType">
    <xs:sequence>
      <xs:element name="size" type="xs:int"/>
    </xs:sequence>
  </xs:complexType>

  <xs:element name="Square" type ="ex14:SquareType" substitutionGroup="ex14:Shape"/>
  <xs:complexType name="SquareType">
    <xs:complexContent>
      <xs:extension base="ex14:ShapeType">
        <xs:sequence>
          <xs:element name="height" type="xs:int"/>
          <xs:element name="width" type="xs:int"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:element name="Circle" type ="ex14:CircleType" substitutionGroup="ex14:Shape"/>
  <xs:complexType name="CircleType">
    <xs:complexContent>
      <xs:extension base="ex14:ShapeType">
        <xs:sequence>
          <xs:element name="radius" type="xs:int"/>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

</xs:schema>

Notes: * When using Bean Inheritence, the child bean classes must be added separatly to the xmlBindingModel because they cannot be discovered automatically (in our example, the Square and Circle classes. * We can change the DrawingType to reference the global Shape XML element instead of defining one itself by adding the annotation @MOXmlGlobalBeanRef on the property. It will result in the DrawingType to be defined as

<xs:complexType name="DrawingType">
  <xs:sequence>
    <xs:element ref="ex14:Shape" minOccurs="0" maxOccurs="unbounded"/>
  </xs:sequence>
</xs:complexType>

Atomic Inheritence and XML Union

The XML Union schema element allows to create simple XML types that thier value space is a union of simple XML types value spaces. Examples can be a union of an int with a Date, allowing the XML type to accept both numbers and dates.

The J2XB @MOPolymorphicAtomProperty annotation uses XML Union schema elements to map Java atomic properties and atomic collections who can contain more then one class of instances. Such properties can have signature of Object and Number (but not restricted to those classes - any class mapped to a simple XML type can be used).

For example, a property with an Object signature that can accept values of integers or strings will be mapped using

@MOProperty()
@MOPolymorphicAtomProperty({
        @MOPolymorphicAtomType(Integer.class),
        @MOPolymorphicAtomType(String.class)})
public Object getStringOrInt1() {...}

The resulting XML Schema fragment is then

<xs:element name="stringOrInt1">
  <xs:simpleType>
    <xs:union>
      <xs:simpleType>
        <xs:restriction base="xs:int">
        </xs:restriction>
      </xs:simpleType>
      <xs:simpleType>
        <xs:restriction base="xs:string">
        </xs:restriction>
      </xs:simpleType>
    </xs:union>
  </xs:simpleType>
</xs:element>

The XML Schema for the Union element can also be defined as a global XML type using the @MOXmlGlobalType annotation and it can include validations (Facets) for the specific types. For instance, the following property defines a type that is an int or a string with length <=3.

@MOProperty()
@MOXmlGlobalType("intOrStringRestricted")
@MOXmlNamespaceRef(PolymorphicAtomProperty.class)
@MOPolymorphicAtomProperty({
  @MOPolymorphicAtomType(Integer.class),
  @MOPolymorphicAtomType(value = String.class, validationString = @MOValidationString(minLength = 3))})
public Object getStringOrInt2() {...}

and the corresponding XML schema is

<xs:element name="stringOrInt2" type="poly:intOrStringRestricted"/>
...
<xs:simpleType name="intOrStringRestricted">
  <xs:union>
    <xs:simpleType>
      <xs:restriction base="xs:int">
      </xs:restriction>
    </xs:simpleType>
    <xs:simpleType>
      <xs:restriction base="xs:string">
        <xs:minLength value="3"/>
      </xs:restriction>
    </xs:simpleType>
  </xs:union>
</xs:simpleType>

Another more complex example:

@MOProperty()
@MOXmlListStyle()
@MOPolymorphicAtomProperty({
  @MOPolymorphicAtomType(value = Integer.class, xmlDerivedType = @MOXmlDerivedType(MoXmlBaseSimpleType.xmlUnsignedShort)),
  @MOPolymorphicAtomType(value = String.class, validationString = @MOValidationString(minLength = 3))})
public List<Object> getPolymorphicListAsListStyle() {...}

with the corresponding XML Schema

<xs:element name="polymorphicListAsListStyle">
  <xs:simpleType>
    <xs:list>
      <xs:simpleType>
        <xs:union>
          <xs:simpleType>
            <xs:restriction base="xs:unsignedShort">
            </xs:restriction>
          </xs:simpleType>
          <xs:simpleType>
            <xs:restriction base="xs:string">
              <xs:minLength value="3"/>
            </xs:restriction>
          </xs:simpleType>
        </xs:union>
      </xs:simpleType>
    </xs:list>
  </xs:simpleType>
</xs:element>