26

I am having some issues with generating Java Classes with appropriate JAXB annotations from an XSD using XJC.

I have a relatively simple XSD file defining my XML schema. The complex types within the XSD take advantage of inheritance using the <xs:extension> tags. The problem I having is that I need all complex types to generate Java Classes with the @XmlRootElement.

Unfortunately, the way in which XJC generates the classes means that only derived class gets the @XmlRootElement (not the base class). I am using the simple global binding directive to ensure that it solves many of the other issues that I have faced with XJC.

Here is an example snippet of the XSD:

<xs:schema version="1.0" targetNamespace="http://www.knowledgemill.com/kmcs"
  xmlns:kmcs="http://www.knowledgemill.com/kmcs"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
  jaxb:version="2.0"
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
  jaxb:extensionBindingPrefixes="xjc"
  elementFormDefault="qualified">
    <xs:annotation>
        <xs:appinfo>
            <jaxb:globalBindings>
                <xjc:simple />
            </jaxb:globalBindings>
        </xs:appinfo>
    </xs:annotation>

    <xs:element name="Artifact" type="kmcs:Artifact"/>
    <xs:element name="EmailArtifact" type="kmcs:EmailArtifact"/>

    <xs:complexType name="Artifact">
        <xs:sequence>
            <xs:element name="artifactId" type="xs:string" minOccurs="0"/>
            <xs:element name="artifactType" type="xs:string" minOccurs="0"/>
            <xs:element name="contentHash" type="xs:string" minOccurs="0"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="EmailArtifact">
        <xs:complexContent>
            <xs:extension base="kmcs:Artifact">
                <xs:sequence>
                    <xs:element name="subject" type="xs:string" minOccurs="0"/>
                    <xs:element name="threadSubject" type="xs:string" minOccurs="0"/>
                    <xs:element name="from" type="xs:string" minOccurs="0"/>
                    <xs:element name="to" type="xs:string" minOccurs="0"/>
                    <xs:element name="cc" type="xs:string" minOccurs="0"/>
                    <xs:element name="bcc" type="xs:string" minOccurs="0"/>
                    <xs:element name="messageId" type="xs:string" minOccurs="0"/>
                    <xs:element name="date" type="xs:date" minOccurs="0"/>
                    <xs:element name="size" type="xs:long" minOccurs="0"/>
                    <xs:element name="hasAttachment" type="xs:boolean" minOccurs="0"/>
                    <xs:element name="sensitivity" type="xs:string" minOccurs="0"/>
                    <xs:element name="headerHash" type="xs:string" minOccurs="0"/>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>


</xs:schema>

As we can see from the above snippet, EmailArtifact extends Artifact.

The java class code for EmailArtifact contains the following:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "EmailArtifact", propOrder = {
    "subject",
    "threadSubject",
    "from",
    "to",
    "cc",
    "bcc",
    "messageId",
    "date",
    "size",
    "hasAttachment",
    "sensitivity",
    "headerHash"
})
@XmlSeeAlso({
    ExtendedEmail.class
})
@XmlRootElement(name = "EmailArtifact")
public class EmailArtifact
    extends Artifact
{

    protected String subject;
    protected String threadSubject;
    protected String from;
    protected String to;
    protected String cc;
    protected String bcc;
    protected String messageId;
    @XmlSchemaType(name = "date")
    protected XMLGregorianCalendar date;
    protected Long size;
    protected Boolean hasAttachment;
    protected String sensitivity;
    protected String headerHash;

The java class code for Artifact contains the following:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Artifact", propOrder = {
    "artifactId",
    "artifactType",
    "contentHash"
})
@XmlSeeAlso({
    ManagedDocArtifact.class,
    EmailArtifact.class
})
public class Artifact {

    protected String artifactId;
    protected String artifactType;
    protected String contentHash;

In the EmailArtifact we can see that it contains the @XmlRootElement but the base type Artifact does not contain @XmlRootElement.

How can you force XJC to generate @XmlRootElement for all classes including the base types.

k0ner
  • 986
  • 6
  • 20
jallch
  • 767
  • 3
  • 8
  • 12
  • Simple binding mode should do that. Are you sure you're specifying it properly? – skaffman Oct 05 '09 at 11:55
  • Yep pretty confident I am - here is the top of my XSD with the relevant globalBindings... – jallch Oct 05 '09 at 12:11
  • Yeah, that should work, I think, although I've always used external binding customizations rather the inline ones – skaffman Oct 05 '09 at 20:12
  • Thanks for the response. Also tried using an external binding file. Again... no luck. Frustrating one. Perhaps it is part of a standard that I am missing that base types should never be an XmlRootElement. Seems a strange practice though... Oh well. At the moment I am having to resort to manually adding them back in after generation - not nice :-( Kind of defeats the point of keeping the XSD as the source of truth. – jallch Oct 06 '09 at 09:07
  • Try the mailing list on http://jaxb.dev.java.net , you might get a more focussed answer. – skaffman Oct 07 '09 at 08:56

2 Answers2

31

Just bind using xjb-file:

<?xml version="1.0"?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jxb:extensionBindingPrefixes="xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <jxb:bindings schemaLocation="path/to/myschema.xsd" node="/xs:schema">
    <jxb:globalBindings>
      <xjc:simple />
    </jxb:globalBindings>
  </jxb:bindings>
</jxb:bindings>

And don't forget to define element of the same type:

<xs:complexType name="Artifact" />
<xs:element name="artifact" type="Artifact">
Betlista
  • 9,561
  • 10
  • 62
  • 99
Azee
  • 1,729
  • 15
  • 22
  • 2
    Thanks! It is the best solution. This don't need to change xsd schema and don't need to change generated root class. – Dmytro Boichenko Nov 08 '12 at 16:07
  • Could you explain the second part about needing to define and element of the same type? Where is that defined? I was hoping not to change the XSD or generated classes. – jacobq Feb 06 '15 at 14:55
  • 2
    This worked for me as well. Both properties in jxb:bindings are not necessary. Additionaly I had to supply the xjc compiler with the extension=true command line param (within an Ant-Script). – Heri Nov 11 '15 at 08:46
  • 2
    Note, that the java 9 versions of jaxb (at least the `jaxb2-maven-plugin:2.4`) have a bug, that ignores such statements in xjb files (at the time of writing). See https://github.com/highsource/maven-jaxb2-plugin/issues/120 – slartidan Feb 21 '19 at 16:01
3

This question references a blog post by Kohsuke Kawaguchi, formerly worked on the JAX-B or JAX-WS RI, that talks about the RI's decision making process and lack of clarity on this issue in the spec.

The blog post mentions that the simple binding feature is part of the RI. Are you using the RI to generate your code?

Community
  • 1
  • 1
DavidValeri
  • 2,330
  • 15
  • 11