68

I need to validate Class object against my schema in which I have provided regular expression to validate fields for auto generated JAXB classes. When I try to validate my class object I get below error:

unable to marshal type "xyz" as an element because it is missing an @XmlRootElement annotation

Here is the code that I use to validate my autogenerated class object:

jc = JAXBContext.newInstance(obj.getClass());
source = new JAXBSource(jc, obj);
Schema schema = schemaInjector.getSchema();
Validator validator = schema.newValidator();
validator.validate(source);

Is there any other way I can solve this?

xlm
  • 6,854
  • 14
  • 53
  • 55
user656213
  • 993
  • 2
  • 8
  • 10

4 Answers4

94

If your class does not have an @XmlRootElement annotation then you can wrap it in an instance of JAXBElement. If you generated your classes from an XML Schema then the generated ObjectFactory may have a convenience method for you.

I have written more about this use case on my blog:

xlm
  • 6,854
  • 14
  • 53
  • 55
bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • 1
    Thanks for the help. I have modified my code as per solution on your blog but I am still getting the same error. modified code is: `QName qName = new QName("http://www.w3.org/2001/XMLSchema", obj.toString());` `JAXBElement e = createJAXBElement(qName, obj.getClass(), obj);` `jc = JAXBContext.newInstance(e.getValue().getClass());` `Marshaller m = jc.createMarshaller();` `source = new JAXBSource(jc, m.getClass());` `Schema schema = schemaInjector.getSchema();` `Validator validator = schema.newValidator();` `validator.validate(source);` _Please advice_ – user656213 Jul 03 '14 at 04:05
  • 5
    I found this answer helpful: http://stackoverflow.com/a/2172942/58363 It gives alternate wording to @Blaise-doughan 's answer. – Daniel Bower Jan 18 '17 at 21:08
23

I solved this problem by using the ObjectFactory class as shown in the example below:

PostTransaction transactionRequest = new PostTransaction();
//Some code here

JAXBElement<PostTransaction> jAXBElement = new ObjectFactory().createPostTransaction(transactionRequest);
 try {
JAXBElement<PostTransactionResponse> aXBElementResponse = (JAXBElement<PostTransactionResponse>) webServiceTemplate.marshalSendAndReceive("wsdlUrl", jAXBElement, new SoapActionCallback("soapMethodName"));
baitmbarek
  • 2,440
  • 4
  • 18
  • 26
tinbee00
  • 330
  • 2
  • 7
  • 1
    Easiest solution – JJCV Feb 20 '20 at 06:47
  • 3
    In my case, the analog ".createPostTransaction () " has no parameters(( – Ilya Y Feb 18 '21 at 09:40
  • 1
    Best answer..and clean. if anyone wondering how to create the ObjectFactory().createXyZ you can build the jaxbObjects using jaxb maven plugin – Jeryl Cook Jan 04 '22 at 01:39
  • From where is the PostTransaction? I don't have that – pemko Jan 26 '23 at 08:25
  • I am still getting same error `com.sun.istack.SAXException2: unable to marshal type "com.example.camel.client.stub.Generic" as an element because it is missing an @XmlRootElement annotation`. Can you please help? I have a question posted in detail here: https://stackoverflow.com/questions/76178871/unable-to-marshal-type-classname-as-an-element-because-it-is-missing-an-xmlro?noredirect=1#comment134343257_76178871 – jarvo69 May 07 '23 at 06:52
14

I suggest you to use Maven plugin maven-jaxb2-plugin to generate classes from a .xsd file. Use a binding file e.g. .xjb to add annotations @XmlRootElement. Example:

Binding file:

<bindings version="2.0" xmlns="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:annox="http://annox.dev.java.net">

  <globalBindings>
        <xjc:serializable uid="12343" />
        <xjc:simple/>
  </globalBindings>
  
</bindings>

POM (Maven plugin config):

 <plugin>
        <groupId>org.jvnet.jaxb2.maven2</groupId>
        <artifactId>maven-jaxb2-plugin</artifactId>
        <version>0.8.1</version>
        <executions>
            <execution>
                <phase>generate-sources</phase>
                <goals>
                    <goal>generate</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <args>
                <arg>-Xannotate</arg>
                <arg>-nv</arg>
            </args>
            <extension>true</extension>
            <forceRegenerate>true</forceRegenerate>
            <bindingDirectory>${basedir}/src/main/resources/schema/xjb</bindingDirectory>
            <bindingIncludes>
                <include>*.xjb</include>
            </bindingIncludes>
            <schemas>
                <schema>
                    <fileset>
                        <directory>${basedir}/src/main/resources/schema/</directory>
                        <includes>
                            <include>*.xsd</include>
                        </includes>
                    </fileset>
                </schema>
            </schemas>
            <debug>true</debug>
            <verbose>true</verbose>
            <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>
                <plugin>
                    <groupId>org.jvnet.jaxb2_commons</groupId>
                    <artifactId>jaxb2-namespace-prefix</artifactId>
                    <version>1.1</version>
                </plugin>
            </plugins>
        </configuration>
    </plugin>
        

See Maven JAXB2 Plugin User Guide

xlm
  • 6,854
  • 14
  • 53
  • 55
Xstian
  • 8,184
  • 10
  • 42
  • 72
  • 5
    Note that `` is the relevant piece here which will add the `@XmlRootElement` annotation. This is a vendor customization in the JAXB RI, see here: https://jaxb.java.net/nonav/2.2.1/docs/vendorCustomizations.html. It does more than just add this annotation. If you only want the `@XmlRootElement`, you can use the jaxb2-basics-annotate extension. – Michael Paesold Feb 06 '15 at 08:09
2

I faced same issue due to legacy wsdl that doesn't have xsd schema inside wsdl definition. I solved this issue by having two maven plugins to generate operations from wsdl as well DTD from xsd file as below and for marshalling new ObjectFactory().createHandShake(new HandShake());

  public boolean handShake() {
        JAXBElement<HandShake> request = new ObjectFactory().createHandShake(new HandShake());
        logger.info(String.format("request: {0}", "handshake request"));
        logger.debug("sending request");
        HandShakeResponse handShakeResponse = ((JAXBElement<HandShakeResponse>) getWebServiceTemplate()
                .marshalSendAndReceive(request, new SoapActionCallback(
                        "urn:handShake"))).getValue();
        logger.debug("receive response");
        return handShakeResponse.isReturn();
    }

<plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.14.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <schemaLanguage>WSDL</schemaLanguage>
                    <generatePackage>${contextPathWSDL}</generatePackage>
                    <schemas>
                        <schema>
                            <url>${merchant.WSDL}</url>
                        </schema>
                    </schemas>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.14.0</version>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <schemaDirectory>${basedir}/src/main/resources/xsds</schemaDirectory>
                    <schemaIncludes>
                        <include>*.xsd</include>
                    </schemaIncludes>
                    <generatePackage>${contextPathXSD}</generatePackage>
                    <generateDirectory>${basedir}/target/generated-sources/DTD</generateDirectory>
                </configuration>
            </plugin>
piet.t
  • 11,718
  • 21
  • 43
  • 52
Mohamed.Abdo
  • 2,054
  • 1
  • 19
  • 12