user310340
user310340

Reputation: 51

Missing @XmlRootElement when creating a client from a wsdl

I have a question in regards to consuming a web service based on a third party wsdl file.

I've taken the given wsdl and generated the 120+ java files required. This process was done by using xjc. Within the Sping environment, I was able to successfully create a couple of JUnit tests by calling a couple of the exposed services.

But, in order to successfully test those services I had to add the @XmlRootElement annotation to the generated java files. Otherwise, I would encounter an error stating

"com.sun.istack.SAXException2: unable to marshal type "com.beam.services.client.UserGetRequestData" as an element because it is missing an @XmlRootElement annotation"

.

I've exhausted my search… I have no control as to how the wsdl file is created/structured. How can I go about generating the java files to ensure that the @XmlRootElement annotation is included or go about writing the client side code in way to avoid the error above?

Thank you.

Upvotes: 5

Views: 15281

Answers (3)

Tom Vahlman
Tom Vahlman

Reputation: 1

Regarding problems in tests of a RestController using RestAssured and SpringBootTest. I was using a class Document, from an external source, which lacked the @XMLRootElement annotation.

I extended a class annotated with @XMLRootElement annotation from the Document missing the annotation. Then used the new class, i.e. JAXBDocument, in my SpringBootTest to call my RestController.

The @RequestBody annotation maps the whole client request to a model class, using the model class's getter and setters. This mapping failed before since a @XMLRootElement was missing.

@XmlRootElement(name = "JAXBDocument")
public class JAXBDocument extends Document{
    public JAXBDocument(Document document) {
        super.setCstmrCdtTrfInitn(document.getCstmrCdtTrfInitn());
    }

    public JAXBDocument() {}
}

Upvotes: 0

Drunix
Drunix

Reputation: 3343

If you really need the @XmlRootElement you could use simple binding mode if your type is used for only one element. The reason why JAXB does not include the annotation by default and how to use simple binding is explained here: https://web.archive.org/web/20170504081258/https://community.oracle.com/blogs/kohsuke/2006/03/03/why-does-jaxb-put-xmlrootelement-sometimes-not-always :

your schema might be used by other schemas that XJC isn't compiling right now

and

Such notion isn't defined in the spec, but as an experiment we have such aggressive optimization mode in XJC, tentatively called "simple-minded binding mode".

The sample seems to got lost when they moved the blog, but it looked like this:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="1.0" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionbindingprefixes="xjc">
  <xs:annotation>
    <xs:appinfo>
      <jaxb:globalbindings>
        <xjc:simple/>
      </jaxb:globalbindings>
    </xs:appinfo>
  </xs:annotation>      
  <xs:element name="foo" type="bar"/>
  <xs:complextype name="bar"/>
</xs:schema>

The other possibilty is to wrap it in a JAXBElement. The ObjectFactory should include a method for creating these wrapped objects.

Upvotes: 2

user3548196
user3548196

Reputation: 375

If you are using mavem then check this link it worked for me.

Create Maven project. Below you can see the POM:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.zmeu</groupId>
    <artifactId>zmeu-blog-maven-jaxb</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>ZMEU Blog Maven JAXB</name>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.8.0</version>
                <configuration>
                    <schemaDirectory>src/main/resources/schema</schemaDirectory>
                    <bindingDirectory>src/main/resources/schema</bindingDirectory>
                    <generatePackage>org.zmeu.blog.jaxb</generatePackage>
                    <strict>false</strict>
                    <extension>true</extension>
                    <plugins>
                        <plugin>
                            <groupId>org.jvnet.jaxb2_commons</groupId>
                            <artifactId>jaxb2-basics</artifactId>
                            <version>0.6.2</version>
                        </plugin>
                        <plugin>
                            <groupId>org.jvnet.jaxb2_commons</groupId>
                            <artifactId>jaxb2-basics-annotate</artifactId>
                            <version>0.6.2</version>
                        </plugin>
                    </plugins>
                    <args>
                        <arg>-Xannotate</arg>
                        <arg>-XtoString</arg>
                    </args>
                </configuration>
                <executions>
                    <execution>
                        <id>generate</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.jvnet.jaxb2_commons</groupId>
            <artifactId>jaxb2-basics-runtime</artifactId>
            <version>0.6.2</version>
        </dependency>
    </dependencies>
</project>

Write XML Schema (schema.xsd):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <xs:element name="user" type="user" />
    <xs:element name="userList" type="userList" />

    <xs:complexType name="user">
        <xs:all>
            <xs:element name="id" type="xs:long" minOccurs="0" />
            <xs:element name="name" type="xs:string" />
            <xs:element name="registrationDate" type="xs:dateTime" />
        </xs:all>
    </xs:complexType>

    <xs:complexType name="userList">
        <xs:sequence>
            <xs:element name="user" type="user" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>

</xs:schema>

Customize JAXB Bindings (binding.xjb):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:annox="http://annox.dev.java.net"
    xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
    version="2.1">
    <jaxb:globalBindings>
        <!-- Use java.util.Calendar instead of javax.xml.datatype.XMLGregorianCalendar for xs:dateTime -->
        <jaxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
                parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
                printMethod="javax.xml.bind.DatatypeConverter.printDateTime" />

        <!-- Force all classes implements Serializable -->
        <xjc:serializable uid="1" />
    </jaxb:globalBindings>

    <!-- Annotate the following classes with XmlRootElement -->
    <jaxb:bindings schemaLocation="schema.xsd" node="/xs:schema">
        <jaxb:bindings node="xs:complexType[@name='user']">
            <annox:annotate>
                <annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="user" />
            </annox:annotate>
        </jaxb:bindings>
        <jaxb:bindings node="xs:complexType[@name='userList']">
            <annox:annotate>
                <annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement" name="userList" />
            </annox:annotate>
        </jaxb:bindings>
    </jaxb:bindings>
</jaxb:bindings>

Run the build using mvn clean install command. Build must be successful. Generated classes will be located in target/generated-sources/xjc directory. Below is a snippet from generated User class:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "user", propOrder = {})
@XmlRootElement(name = "user")
public class User implements Serializable, ToString {
    private final static long serialVersionUID = 1L;

    protected Long id;

    @XmlElement(required = true)
    protected String name;

    @XmlElement(required = true, type = String.class)
    @XmlJavaTypeAdapter(Adapter1 .class)
    @XmlSchemaType(name = "dateTime")
    protected Calendar registrationDate;

}

You are done!

Upvotes: 1

Related Questions