简体   繁体   中英

How do I separate the <xsd:choice/> sub-elements into individual Collection properties using JAXB?

I have the following XSD fragment that is from a Vendor, I can't change the way it is specified:

<xsd:element name="navmap">
  <xsd:complexType>
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
      <xsd:element ref="navitem"/>
      <xsd:element ref="debug"/>
    </xsd:choice>
    <xsd:attribute name="focus" type="xsd:string" use="optional"/>
  </xsd:complexType>
</xsd:element>

Right now with no customizations it generates the following code

@XmlElements({
        @XmlElement(name = "navitem", type = Navitem.class),
        @XmlElement(name = "debug", type = Debug.class)
    })
    protected List<Object> navitemOrDebug;

I would rather it generate a separate list for each type like below

@XmlElements({
        @XmlElement(name = "navitem", type = Navitem.class)
    })
    protected List<Navitem> navitems;

@XmlElements({
        @XmlElement(name = "debug", type = Debug.class)
    })
    protected List<Debug> debugs;

I have the following in my .xjb file that renames the entire List but I can't figure out how to split them up.

<jxb:bindings node="//xsd:element[@name='navmap']//xsd:complexType//xsd:choice">
  <jxb:property name="contents" />
</jxb:bindings>

How do I specify that I want a separate List or Set for each of the types in an external .xjb binding file?

If I can't do that, How do I add an <jaxb:annotation/> to the .xsd file to specify a separate List or Set for each of the types?

I don't care about ordering, the order is not important in this particular case.

NOTE: I would prefer an external .xjb solution, I don't want to have to diff a custom.xsd against every new version the vendor provides, there are too many of them.

As promised, please meet the Simplify Plugin .

This plugin allows simplifying "complex" properties. Thes properties are often generated from repeatable choices like this one:

<xs:complexType name="typeWithReferencesProperty">
    <xs:choice maxOccurs="unbounded">
        <xs:element name="a" type="someType"/>
        <xs:element name="b" type="someType"/>
    </xs:choice> 
</xs:complexType>

...

<xs:complexType name="typeWithElementsProperty">
    <xs:choice maxOccurs="unbounded">
        <xs:element name="a" type="xs:string"/>
        <xs:element name="b" type="xs:int"/>
    </xs:choice> 
</xs:complexType>

By default, XJC will complex properties modelling several references or elements in one.

@XmlElementRefs({
    @XmlElementRef(name = "a", type = JAXBElement.class),
    @XmlElementRef(name = "b", type = JAXBElement.class)
})
protected List<JAXBElement<SomeType>> aOrB;

...

@XmlElements({
    @XmlElement(name = "a", type = String.class)
    @XmlElement(name = "b", type = Integer.class),
})
protected List<Serializable> aOrB;

These complex properties are required to model complex content of the XML schema adequately, ie to maintain the order of the elements in the repeatable choice. Unfortunately, they are not idiomatic as bean properties. These properties are "heterogeneous" (in a sense that they store different types), which makes it hard to work with them.

However, if the order of the elements is not significant - that is, you can live with the fact that it will change afte re-marshalling, the structures of these properties can be simplified: complex properties can be split into several simple properties.

The Simplify Plugin implements this task. It allows you to simplify your complex properties. The plugin will remove the complex property and insert several simpler properties instead of the original (complex) property. So you can get something like:

@XmlElement(name = "a", type = String.class)
protected List<String> a;
@XmlElement(name = "b", type = Integer.class)
protected List<Integer> b;

Or:

@XmlElement(name = "a")
protected List<SomeType> a;
@XmlElement(name = "b")
protected List<SomeType> b;

Or:

@XmlElementRef(name = "a", type = JAXBElement.class)
protected List<JAXBElement<SomeType>> a;
@XmlElementRef(name = "b", type = JAXBElement.class)
protected List<JAXBElement<SomeType>> b;

Dependin on the customization.

The plugin will be released in JAXB2 Basics 0.6.3, now availavle as a snapshot from this repository .

As far as I know, at the moment you can't (with XJC from JAXB RI). Theoretically it must possible to write a plugin which changes the XJC model.

But you must be aware that two separate homogeneous properties debug and navitem do not equal one heterogeneous property navitemOrDebug . Ie you'll get a different ordering of the elements if you unmarshall and marshall the same object.

However, in many cases this might make sense. Please file an issue here , I'll consider implementing it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM