20

I'm using JAXB and xjc to compile my XML Schema into Java classes. I do not want to manually edit this generated classes. I have xml schema like that:

<xs:element name="root">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="items">
        <xs:complexType>
          <xs:sequence>
            <xs:element ref="item" />
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>
</xs:element>

The xjc generates a class Items that only contains a list of Item objects. Is there any chance to omit the class Items and have a list of Item objects directly in the Rootclass?

I know that this can be done with @XMLElementWrapper annotation, but I don't know how to tell xjc to create such.

Thanks for any suggestions!

Best regards, Markus

DEAD10CC
  • 910
  • 1
  • 6
  • 20

2 Answers2

12

Bjarne Hansen developed a plugin for xjc that was able to take care of this. Unfortunately, the link to the original implementation is now dead. However, there is a project by Dmitry Katsubo on github, based on Bjarne's original code with some additional improvements.

https://github.com/dmak/jaxb-xew-plugin


(Just for reference: the original link, now dead: http://www.conspicio.dk/blog/bjarne/jaxb-xmlelementwrapper-plugin)

Thomas
  • 17,016
  • 4
  • 46
  • 70
  • Thomas, thank you. This link is the first proper content I've seen about this topic. – mahonya Mar 19 '12 at 14:26
  • I've been trying for a while to use that plugin, but to no avail. Not sure if that's compatible with xjc 2.2.4 (which is what I have at the moment). Also, I don't have the jaxb-xjc.jar (xjc is part of JDK7's tools). Finally I want to call xjc from the command line, and everybody is very mum on how to do it ([Kohsuke Kawaguchi](http://weblogs.java.net/blog/kohsuke/archive/2005/06/writing_a_plugi.html) says "You can also do it from command line, but it's not very pretty.") Why can't we just have a jaxb:annotation to tell xjc to "skip" a level, i.e. just generate an `@XmlElementWrapper`? – Pierre D Mar 22 '12 at 18:38
  • Note that my answer is from two years ago - I used the plugin back then and it worked fine, but it might be outdated by now. – Thomas Mar 23 '12 at 00:40
  • 2
    For those who came across this like I did researching this issue, you can find this plugin in the main Maven repo with groupId com.github.jaxb-xew-plugin and artifactId of jaxb-xew-plugin. The code is maintained at https://github.com/dmak/jaxb-xew-plugin. – davidfmatheson Sep 25 '12 at 14:58
  • @davidfmatheson Care to create a proper answer to elaborate a bit on that solution? – Thomas Sep 25 '12 at 23:49
10

First lets break up your schema so that there are no inner classes generated:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified">
    <xs:element name="root" type="Root" />

    <xs:complexType name="Root">
        <xs:sequence>
            <xs:element name="items" type="Items" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="Items">
        <xs:sequence>
            <xs:element name="item" type="xs:string" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>
</xs:schema>

You'll still get extra classes, just not all in one file. Now you want to add a section to your build to use the jaxb-xew-plugin. I use Maven, so for me this looks like:

<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <version>0.8.2</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <args>
                    <arg>-no-header</arg>
                    <arg>-Xxew</arg>
                    <arg>-Xxew:instantiate lazy</arg>
                    <arg>-Xxew:delete</arg>
                </args>
                <plugins>
                    <plugin>
                        <groupId>com.github.jaxb-xew-plugin</groupId>
                        <artifactId>jaxb-xew-plugin</artifactId>
                        <version>1.0</version>
                    </plugin>
                </plugins>
            </configuration>
        </execution>
    </executions>
</plugin>

If you start using namespaces so that your generated classes have package names, leave off the -Xxew:delete flag, as there's a bug that I recently fixed where it was deleting objects it shouldn't. Alternatively, you could grab the code from github and use it as 1.1-SNAPSHOT.

When I do that I get the code generated that I think you're looking for:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Root", propOrder = {
    "items"
})
public class Root {

    @XmlElementWrapper(name = "items", required = true)
    @XmlElement(name = "item")
    protected List<String> items;

    public List<String> getItems() {
        if (items == null) {
            items = new ArrayList<String>();
        }
        return items;
    }

    public void setItems(List<String> items) {
        this.items = items;
    }

}
davidfmatheson
  • 3,539
  • 19
  • 27