How generate XMLElementWrapper annotation with xjc and customized binding
Asked Answered
K

2

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

Kamacite answered 15/3, 2010 at 12:40 Comment(0)
C
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)

Converse answered 15/3, 2010 at 13:44 Comment(5)
Thomas, thank you. This link is the first proper content I've seen about this topic.Salted
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 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?Krenn
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.Converse
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 github.com/dmak/jaxb-xew-plugin.Radiance
@Radiance Care to create a proper answer to elaborate a bit on that solution?Converse
R
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;
    }

}
Radiance answered 26/9, 2012 at 13:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.