9

I am trying to unmarshall the following XML using JAXB:

<Works>
    <Work>
        <Composers>
            <Composer>
                <Name>A name</Name>
            </Composer>
            <Composer>
                <Name>A name 2</Name>
            </Composer>
        </Composers>
    </Work>
</Works>

I have generated all of the classes using XJC. If I want to access the Composers collection, I have to do this:

 List<Composer> composers = work.getComposers().getComposer();

Is there any way I can do the following instead?

 List<Composer> composers = work.getComposers();

I appreciate the need for a Composers object as it derived from the XML, but when dealing in Java, having an intermediate POJO that stores the collections seems a bit redundant.

My XSD is:

<xsd:complexType name="Works">
    <xsd:sequence>
        <xsd:element name="Work" type="Work" maxOccurs="unbounded" minOccurs="0"></xsd:element>
    </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="Work">
    <xsd:sequence>
        <xsd:element name="Composers" type="Composers"></xsd:element>
    </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="Composers">
    <xsd:sequence>
        <xsd:element name="Composer" type="Composer" maxOccurs="unbounded" minOccurs="0"></xsd:element>
    </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="Composer">
    <xsd:sequence>
        <xsd:element name="Name" type="xsd:string"></xsd:element>
    </xsd:sequence>
</xsd:complexType>

seedhead
  • 3,655
  • 4
  • 32
  • 38
  • Do you have a schema that you used to generate the POJOs? – Bala R Sep 07 '11 at 17:52
  • List composers = work.getComposers().getComposer(); this does not look right. It should return you only one composer not a list of composers . Whereas List composers = work.getComposers(); this looks correct . – Anubis05 Sep 07 '11 at 18:20
  • 1
    @ganguly.sarthak: Although the `work.getComposers().getComposer()` call doesn't *look* right, it is indeed necessary if you're using the generated JAXB classes. I've posted an answer with a link to an XJC plugin that manipulates the generated classes to correct this annoying JAXB quirk. – William Brendel Sep 07 '11 at 20:55

2 Answers2

6

The @XmlElementWrapper plugin does exactly what you want.

William Brendel
  • 31,712
  • 14
  • 72
  • 77
  • 1
    Thanks William! Unfortunately this plugin doesn't support JAXB 2.1, only 2.0. Is the only option here to downgrade to 2.0? – seedhead Sep 08 '11 at 12:11
  • I'm using it in a project with JAXB 2.2.3 without any problems. Can you tell me what error you're seeing? – William Brendel Sep 08 '11 at 14:50
  • No error but the generated classes from XJC don't contain the expected @XmlElementWrapper annotations. I am using Java 6 and JAXB 2.1, are you using Java 6 too? – seedhead Sep 08 '11 at 14:59
  • 1
    You're adding xew.jar to the classpath and specifying the "-Xxew" command line option? I just did a quick test with JAXB 2.1 and the XEW plugin, and it generated the @XmlElementWrapper annotations properly. I can write up a step-by-step tutorial if you think it would be helpful. – William Brendel Sep 09 '11 at 16:55
  • William, that would be great! – seedhead Sep 12 '11 at 09:20
  • Did the step-by-step tutorial every eventuate? It would be really helpful. – Kevin Nov 19 '12 at 02:02
  • Sorry, I forgot to write the tutorial. I'll put it back on my todo list :-) – William Brendel Nov 19 '12 at 18:16
3

For anybody who can not or does not want to use the plugin: If you can live with a different XML structure, it's possible to avoid generating the extra wrapper classes by simply using maxoccurs="unbounded" and leaving out the containing element. Using the original example:

<xsd:element name="Work" type="Work" maxOccurs="unbounded" minOccurs="0"/>

<xsd:complexType name="Work">
    <xsd:sequence>
        <xsd:element name="Composer" type="Composer" maxOccurs="unbounded" minOccurs="0"/>
    </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="Composer">
    <xsd:sequence>
        <xsd:element name="Name" type="xsd:string"></xsd:element>
    </xsd:sequence>
</xsd:complexType>

will produce a structure like this:

<Work>
    <Composer>
        <Name>A name</Name>
    </Composer>
    <Composer>
        <Name>A name 2</Name>
    </Composer>
</Work>

This will put a method on the Work type that returns a List<Composer> object. Unfortunately the method is called getComposer instead of getComposers, but you can use annotations or custom bindings to fix that problem.

Community
  • 1
  • 1
undefined
  • 6,208
  • 3
  • 49
  • 59