Search code examples
javajaxbxsdxjc

specify type for IDREF in XML schema


I am generating Java objects from an XML schema using xjc. I would like to reference the same element multiple times within the document using IDREF. I would also like to constrain the objects referenced by IDREF to a specific type. I'd like to do this for the purposes of schema validation, but also so that in the Java code, the referenced object is returned as a specific type instead of type Object. For example, say I want a schema to describe the following:

<teams>
  <team id="team1">
    <coach>coachz</coach>
    <player>homestar</player>
    <player>marzipan</player>
    <player>strongsad</player>
    <player>strongbad</player>
  </team>

  <team id="team2">
    <coach>bubs</coach>
    <player>homesar</player>
    <player>thecheat</player>
    <player>poopsmith</player>
    <player>bubs</player>
  </team>

  <team id="allstars">
    <coach>poopsmith</coach>
    <player>coachz</player>
    <player>bubs</player>
    <player>kingoftown</player>
    <player>strongbad</player>
  </team>
</teams>

<people>
 <person id="coachz">Coach Z</person>
 <person id="homesar">Homesar</person>
 <person id="homestar">Homestar</person>
 <person id="strongbad">Strong Bad</person>
 <person id="strongsad">Strong Sad</person>
 <person id="marzipan">Marzipan</person>
 <person id="bubs">Bubs</person>
 <person id="kingoftown">King of Town</person>
 <person id="poopsmith">The Poopsmith</person>
 <person id="thecheat">The Cheat</person>
</people>

I can define player like this:

<xs:element name="player" type="xs:IDREF" maxOccurs="unbounded"/>

but then in the Java code, when I try to retrieve a player it will come back as type object, and I have to cast it to a person. At that point, if someone has mistakenly referenced a Team object, I have errors to deal with that could have been caught at validation. I want to specify something like this:

<xs:element name="player" type="xs:IDREF"reftype="person"maxOccurs="unbounded" />

But as far as I can tell, there is no way to specify a type as I have done here with the contrived attribute 'reftype'. Can this be done, using IDREF? If not, is there another method?


Solution

  • You can simply apply baseType binding to your player element. Something like:

    <jaxb:bindings node="xsd:element[@name='player']">
        <jaxb:property>
            <jaxb:baseType name="....Person"/>
        </jaxb:property>
    </jaxb:bindings>
    

    You may need to figure out the correct binding location for your schema.

    Example from my code:

    Schema:

    <xsd:complexType name="HJIII-53-A">
        <xsd:sequence>
            <xsd:element name="b" type="xsd:IDREF"/>
            <xsd:element name="b1" type="test:HJIII-53-B"/>
            <xsd:element name="c" type="xsd:IDREFS"/>
            <xsd:element name="c1" type="test:HJIII-53-C" minOccurs="0" maxOccurs="unbounded"/>
        </xsd:sequence>
    </xsd:complexType>
    

    Bindings:

    <jaxb:bindings schemaLocation="schema.xsd" node="/xsd:schema">
        <jaxb:globalBindings localScoping="toplevel">
            <jaxb:serializable/>
        </jaxb:globalBindings>
        <jaxb:bindings node="xsd:complexType[@name='HJIII-53-A']//xsd:element[@name='b']">
            <jaxb:property>
                <jaxb:baseType name="org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53B"/>
            </jaxb:property>
        </jaxb:bindings>
        <jaxb:bindings node="xsd:complexType[@name='HJIII-53-A']//xsd:element[@name='c']">
            <jaxb:property>
                <jaxb:baseType name="org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53C"/>
            </jaxb:property>
        </jaxb:bindings>
    </jaxb:bindings>
    

    Generated code:

    @XmlElement(required = true, type = Object.class)
    @XmlIDREF
    @XmlSchemaType(name = "IDREF")
    protected org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53B b;
    @XmlElement(required = true)
    protected org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53B b1;
    @XmlList
    @XmlElement(required = true, type = Object.class)
    @XmlIDREF
    protected List<org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53C> c;
    protected List<org.jvnet.hyperjaxb3.ejb.tests.issuesjpa2.HJIII53C> c1;
    

    See: https://svn.java.net/svn/hj3~svn/trunk/ejb/tests/issues-jpa2/src/main/resources/