Optimal JAXB XJC code generation and optimal XML schema with inheritance

code-generation, inheritance, jaxb, xjc, xsd

Solution

I would suggest using something similar to your first option as I have never seen a cleaner solution to this problem.

XSD

<xs:element name="Publications" minOccurs="0">
  <xs:complexType>
    <xs:sequence>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Magazine" type="magazine"/>
        <xs:element name="Book" type="book"/>
      </xs:choice>
    </xs:sequence>
  </xs:complexType>
</xs:element>

 <xs:complexType name="magazine">
  <xs:complexContent>
   <xs:extension base="publication">
    <xs:sequence>
      <xs:element name="issueName" type="xs:string" minOccurs="0"/>
    </xs:sequence>
  </xs:extension>
 </xs:complexContent>
</xs:complexType>

<xs:complexType name="publication">
  <xs:sequence>
    <xs:element name="name" type="xs:string" minOccurs="0"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="book">
  <xs:complexContent>
    <xs:extension base="publication">
      <xs:sequence>
        <xs:element name="title" type="xs:string" minOccurs="0"/>
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>

JAVA This is the Java code I used to generate the above XSD.

@XmlElements({
  @XmlElement(name="Magazine", type=Magazine.class),
  @XmlElement(name="Book", type=Book.class)
})
@XmlElementWrapper(name="Publications")
public List<Publication> publications;

Problem

There have been a lot of similar questions which focus on one aspect to optimize but each solution had an ugly downside. Suppose I want to develop an XML schema (XSD) which allows the following documents and want to generate classes using XJC: ``` <Catalogue> <Book>...</Book> <Journal>...</Journal> <Book>...</Book> ... </Catalogue> ``` The schema should model the type hierarchy (`Book` and `Journal` are subclasses of `Publication`). Naturally, this should also be the case for the generated Java classes. I tried the following approches which all have a major issue: 1.) modeling Catalogue to contain a `xsd:choice` of all possible subtypes. ``` <xsd:complexType name="Catalogue"> <xsd:choice maxOccurs="unbounded"> <xsd:element ref="Book" /> <xsd:element ref="Magazine" /> </xsd:choice> </xsd:complexType> <xsd:element name="Publication" abstract="true" type="Publication" /> <xsd:element name="Book" type="Book"/> <xsd:element name="Magazine" type="Magazine"/> <xsd:complexType name="Publication"> <xsd:sequence></xsd:sequence> </xsd:complexType> <xsd:complexType name="Book"> <xsd:complexContent> <xsd:extension base="Publication"> </xsd:extension> </xsd:complexContent> </xsd:complexType> ... ``` The problem here is that I have to mention all possible subtypes in the `choice` element which could be a lot in a real application. A minor issue is that, although the `Catalogue` attribute has the correct type `List<Publication>` it has an ugly name `bookAndMagazine`. Because of the redundant schema definition, not an option! 2.) modeling Catalogue to contain a `xsd:sequence` of the parent class ``` <xsd:complexType name="Catalogue"> <xsd:choice maxOccurs="unbounded"> <xsd:element ref="Publication" maxOccurs="unbounded"/> </xsd:choice> </xsd:complexType> ``` This does only work if the XML documents are formulated like `<Publication xsi:type="Book"...>` . Thus, not an option! 3.) Use substitutionGroup like mentioned here http://www.xfront.com/ElementHierarchy.html ``` <xsd:complexType name="Catalogue"> <xsd:choice maxOccurs="unbounded"> <xsd:element ref="Publication" maxOccurs="unbounded"/> </xsd:choice> </xsd:complexType> <xsd:element name="Publication" abstract="true" type="Publication" /> <xsd:element name="Book" type="Book" substitutionGroup="Publication"/> <xsd:element name="Magazine" type="Magazine" substitutionGroup="Publication"/> <xsd:complexType name="Publication"> <xsd:sequence></xsd:sequence> </xsd:complexType> <xsd:complexType name="Book"> <xsd:complexContent> <xsd:extension base="Publication"> </xsd:extension> </xsd:complexContent> </xsd:complexType> ... ``` Here, the code generation is the issue because the inner element of `Catalogue` is mapped to `List<JaxbElement<? extends Publication>>` rather than `List<Publication>` . Hence, also this isn't an option. How to bring all my objectives together?: - canonical, non-redundant schema which models inheritance (such as in 2.) or 3.)) - simple and clean Java classes generated from this schema and which models inheritance (like in 2.) and partly in 1.) ) - clean XML documents (not like in 2.) ) - usage of standard JAXB and preferable not much binding metadata And if there is no solution which matches all these objectives, which one would you prefer?

Original source