225

I'm trying to generate Java classes from the FpML (Finanial Products Markup Language) version 4.5. A ton of code is generated, but I cannot use it. Trying to serialize a simple document I get this:

javax.xml.bind.MarshalException
  - with linked exception: [com.sun.istack.SAXException2: unable
  to marshal type
  "org.fpml._2008.fpml_4_5.PositionReport"
  as an element because it is missing an
  @XmlRootElement annotation]

In fact no classses have the @XmlRootElement annotation, so what can I be doing wrong?. I'm pointing xjc (JAXB 2.1) to fpml-main-4-5.xsd, which then includes all types.

Peter Rosemann
  • 453
  • 6
  • 16
robinr
  • 4,064
  • 2
  • 18
  • 18

16 Answers16

273

To tie together what others have already stated or hinted at, the rules by which JAXB XJC decides whether or not to put the @XmlRootElement annotation on a generated class are non trivial (see this article).

@XmlRootElement exists because the JAXB runtime requires certain information in order to marshal/unmarshal a given object, specifically the XML element name and namespace. You can't just pass any old object to the Marshaller. @XmlRootElement provides this information.

The annotation is just a convenience, however - JAXB does not require it. The alternative to is to use JAXBElement wrapper objects, which provide the same information as @XmlRootElement, but in the form of an object, rather than an annotation.

However, JAXBElement objects are awkward to construct, since you need to know the XML element name and namespace, which business logic usually doesn't.

Thankfully, when XJC generates a class model, it also generates a class called ObjectFactory. This is partly there for backwards compatibility with JAXB v1, but it's also there as a place for XJC to put generated factory methods which create JAXBElement wrappers around your own objects. It handles the XML name and namespace for you, so you don't need to worry about it. You just need to look through the ObjectFactory methods (and for large schema, there can be hundreds of them) to find the one you need.

hiropon
  • 1,486
  • 2
  • 17
  • 36
skaffman
  • 381,978
  • 94
  • 789
  • 754
  • Great link to the article in first paragraph. – Marcin Górecki Sep 12 '12 at 00:01
  • 17
    **Special case solution: when you can modify the xsd used for class generation:** After reading the link provided in this answer the solution in my case was to modify the xsd file used to generate the classes: I changed the definition of the root element to an inlined definition instead of using the reference to a type defined separetely. These allows JAXB to set this element as @XmlRootElement, which was not possible with the elementType which was used before for the root element. – Arthur Jan 09 '13 at 11:57
  • 2
    changing root element to be of inline type, however, makes all classes to be inner classes of the root type. Also, even if the root element type is defined AFTER the root element itself (apparently allowed by schema), JAXB will still not annotate with @XmlRootElement. – Pawel Veselov Feb 04 '13 at 09:46
  • @PawelVeselov - The following will help you generate top level classes: http://blog.bdoughan.com/2011/07/jaxb-xjc-and-nested-classes.html – bdoughan Feb 28 '13 at 11:01
  • This example helped me to generate the XmlRootElementannotations I needed [Configure Maven to generate classes from XML Schema using JAXB](http://azagorneanu.blogspot.be/2011/09/configure-maven-to-generate-classes.html) – MrSmith42 Mar 22 '13 at 14:40
  • 14
    i.e. `new ObjectFactory().createPositionReport(positionReport)` returns `JAXBElement` – vikingsteve Sep 27 '13 at 11:44
  • 19
    What if the generated ObjectFactory method does not create a method that wraps the argument in a `JXBElement`? In my case, the factory method is 0-arity and just returns a `new` object. (Why are some classes given JAXBElement wrapper helpers and others not?) I guess in that case we must create the wrapper ourselves? – Carl G Nov 04 '14 at 21:04
  • I've noticed this sometimes too @CarlG. Can anyone explain? – Evan LaHurd Dec 10 '15 at 23:08
  • 1
    @CarlG I'm in the same situation - no XmlRootElement nor JAXBElement appears in my classes. Have you found a solution for this case? – Mickael Marrache Dec 30 '15 at 08:53
  • 1
    Using the ObjectFactory helped to solve my problem, thanks :) – MattWeiler Apr 01 '19 at 16:39
71

This is mentioned at the bottom of the blog post already linked above but this works like a treat for me:

Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(new JAXBElement<MyClass>(new QName("uri","local"), MyClass.class, myClassInstance), System.out);
Gurnard
  • 1,693
  • 20
  • 35
55

As hinted at in one of the above answers, you won't get an XMLRootElement on your root element if in the XSD its type is defined as a named type, since that named type could be used elsewhere in your XSD. Try mking it an anonymous type, i.e. instead of:

<xsd:element name="myRootElement" type="MyRootElementType" />

<xsd:complexType name="MyRootElementType">
...
</xsd:complexType>

you would have:

<xsd:element name="myRootElement">
    <xsd:complexType>
    ...
    <xsd:complexType>
</xsd:element>
Matthew Wise
  • 2,330
  • 23
  • 23
  • 1
    That's not true for me. My type is anonymous (embedded inside my root element) and no XmlRootElement annotation is generated. Any idea? – Mickael Marrache Feb 23 '16 at 19:41
39

@XmlRootElement is not needed for unmarshalling - if one uses the 2 parameter form of Unmarshaller#unmarshall.

So, if instead of doing:

UserType user = (UserType) unmarshaller.unmarshal(new StringReader(responseString));

one should do:

JAXBElement<UserType> userElement = unmarshaller.unmarshal(someSource, UserType.class);
UserType user = userElement.getValue();

The latter code will not require @XmlRootElement annotation at UserType class level.

Eric
  • 1,276
  • 2
  • 11
  • 27
Sayantam
  • 794
  • 7
  • 5
  • 2
    Do you know of an equally elegant way to marshal an object that doesn't have XmlRootElement - without wrapping it in a JAXBElement as mentioned by skaffman, Gurnard et al? – Chris Jun 13 '12 at 13:14
  • 5
    +1 Works perfectly! One edit for more clarity... In your solution 'someSource' is very vague term. To elaborate : JAXBElement root = unmarshaller.unmarshal(new StreamSource(new File("some.xml")),TargetClazz.class); – supernova Aug 23 '13 at 03:31
  • 4
    Further elaboration of 'someSource':```String pathname = "file.xml"; InputStream stream = new FileInputStream(pathname); JAXBContext jaxbContext = JAXBContext.newInstance(UserType.class); Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); XMLInputFactory factory = XMLInputFactory.newInstance(); XMLEventReader someSource = factory.createXMLEventReader(stream); JAXBElement userElement = jaxbUnmarshaller.unmarshal(someSource, UserType.class); UserType user = userElement.getValue();``` – Steve Pitchers Apr 26 '17 at 13:15
21

Joe's answer (Joe Jun 26 '09 at 17:26) does it for me. The simple answer is that absence of an @XmlRootElement annotation is no problem if you marshal a JAXBElement. The thing that confused me is the generated ObjectFactory has 2 createMyRootElement methods - the first takes no parameters and gives the unwrapped object, the second takes the unwrapped object and returns it wrapped in a JAXBElement, and marshalling that JAXBElement works fine. Here's the basic code I used (I'm new to this, so apologies if the code's not formatted correctly in this reply), largely cribbed from link text:

ObjectFactory objFactory = new ObjectFactory();
MyRootElement root = objFactory.createMyRootElement();
...
// Set root properties
...
if (!writeDocument(objFactory.createMyRootElement(root), output)) {
    System.err.println("Failed to marshal XML document");
}
...

private boolean writeDocument(JAXBElement document, OutputStream output) {

  Class<?> clazz = document.getValue().getClass();
  try {
    JAXBContext context =
        JAXBContext.newInstance(clazz.getPackage().getName());
    Marshaller m = context.createMarshaller();
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
    m.marshal(document, output);
    return true;

  } catch (JAXBException e) {
    e.printStackTrace(System.err);
    return false;
  }
}
Yaqoob
  • 311
  • 2
  • 2
20

You can fix this issue using the binding from How to generate @XmlRootElement Classes for Base Types in XSD?.

Here is an example with Maven

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>jaxb2-maven-plugin</artifactId>
            <version>1.3.1</version>
            <executions>
                <execution>
                    <id>xjc</id>
                    <goals>
                        <goal>xjc</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <schemaDirectory>src/main/resources/xsd</schemaDirectory>
                <packageName>com.mycompany.schemas</packageName>
                <bindingFiles>bindings.xjb</bindingFiles>
                <extension>true</extension>
            </configuration>
        </plugin>

Here is the binding.xjb file content

<?xml version="1.0"?>
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
              xmlns:xjc= "http://java.sun.com/xml/ns/jaxb/xjc"
              jxb:extensionBindingPrefixes="xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <jxb:bindings schemaLocation="path/to/myschema.xsd" node="/xs:schema">
        <jxb:globalBindings>
            <xjc:simple/>
        </jxb:globalBindings>
    </jxb:bindings>
</jxb:bindings>
Community
  • 1
  • 1
Olivier.Roger
  • 4,131
  • 5
  • 35
  • 63
  • 4
    Indeed, using in the binding.xjb file did the trick. Awesome solution if you don't want to change your marshaling code or your WSDL. Note that xjc:simple generates different method names (plural) for collection getters (getOrders instead of getOrder for example) – dvtoever Oct 22 '14 at 09:28
11

As you know the answer is to use the ObjectFactory(). Here is a sample of the code that worked for me :)

ObjectFactory myRootFactory = new ObjectFactory();

MyRootType myRootType = myRootFactory.createMyRootType();

try {

        File file = new File("./file.xml");
        JAXBContext jaxbContext = JAXBContext.newInstance(MyRoot.class);
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

        //output pretty printed
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        JABXElement<MyRootType> myRootElement = myRootFactory.createMyRoot(myRootType);

        jaxbMarshaller.marshal(myRootElement, file);
        jaxbMarshaller.marshal(myRootElement, System.out);

    } catch (JAXBException e) {
        e.printStackTrace();
    }
jdklett
  • 33
  • 6
Shehaaz
  • 735
  • 1
  • 7
  • 12
  • to your point... how do I use JAXBElement> create...() methods from ObjectFactory for nested elements? i.e. : I get: "unable to marshal type "UsernameTokenType" as an element because it is missing an @XmlRootElement annotation" – Angelina Apr 03 '19 at 19:59
8

After sruggling for two days I found the solution for the problem.You can use the ObjectFactory class to workaround for the classes which doesn't have the @XmlRootElement. ObjectFactory has overloaded methods to wrap it around the JAXBElement.

Method:1 does the simple creation of the object.

Method:2 will wrap the object with @JAXBElement.

Always use Method:2 to avoid javax.xml.bind.MarshalException - with linked exception missing an @XmlRootElement annotation.

Please find the sample code below

Method:1 does the simple creation of the object

public GetCountry createGetCountry() {
        return new GetCountry();
    }

Method:2 will wrap the object with @JAXBElement.

 @XmlElementDecl(namespace = "my/name/space", name = "getCountry")
 public JAXBElement<GetCountry> createGetCountry(GetCountry value) {
        return new JAXBElement<GetCountry>(_GetCountry_QNAME, GetCountry.class, null, value);
    }

Working code sample:

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
WebServiceTemplate springWSTemplate = context.getBean(WebServiceTemplate.class);

GetCountry request = new GetCountry();
request.setGuid("test_guid");

JAXBElement<GetCountryResponse> jaxbResponse = (JAXBElement<GetCountryResponse>)springWSTemplate .marshalSendAndReceive(new ObjectFactory().createGetCountry(request));

GetCountryResponse response = jaxbResponse.getValue();
prasadg
  • 539
  • 6
  • 10
  • Thanks for giving the code reference with spring webservice template as was struggling to figure it out for quite some time! – RRR_J May 06 '20 at 05:37
7

In case my experience of this problem gives someone a Eureka! moment.. I'll add the following:

I was also getting this problem, when using an xsd file that I had generated using IntelliJ's "Generate xsd from Instance document" menu option.

When I accepted all the defaults of this tool, it generated an xsd file that when used with jaxb, generated java files with no @XmlRootElement. At runtime when I tried to marshal I got the same exception as discussed in this question.

I went back to the IntellJ tool, and saw the default option in the "Desgin Type" drop down (which of course I didn't understand.. and still don't if I'm honest) was:

Desgin Type:

"local elements/Global complex types"

I changed this to

"local elements/types"

, now it generated a (substantially) different xsd, that produced the @XmlRootElement when used with jaxb. Can't say I understand the in's and out's of it, but it worked for me.

johnm
  • 7,316
  • 1
  • 20
  • 33
6

It's not working for us either. But we did find a widely-quoted article that adds SOME background... I'll link to it here for the sake of the next person: http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html

mcherm
  • 20,782
  • 10
  • 41
  • 50
  • This worked well for me, thank you. I also found that I was marshaling the wrong JAXB object (not the root like I thought) in the process of going through this. I forgot to create a JAXBElement and was trying to marshal just the returned object from the ObjectFactory class I had obtained from binding. This basically took care of the issue altogether (in case anyone else runs up against the same problem). – Joe Bane Jun 26 '09 at 17:26
  • 1
    404 : "We're sorry the java.net site has closed. Most Open Source projects previously hosted on java.net have been relocated." – Tristan Mar 02 '18 at 12:53
  • 1
    https://web.archive.org/web/20070812073809/http://weblogs.java.net/blog/kohsuke/archive/2006/03/why_does_jaxb_p.html – D-Klotz Nov 15 '18 at 14:41
6

With a Maven build, you can add the @XmlRootElement annotation

with the "jaxb2-basics-annotate" plug-in.

See more information : see

Configure Maven to generate classes from XML Schema using JAXB

and JAXB XJC code generation

Community
  • 1
  • 1
metatechbe
  • 607
  • 9
  • 7
6

JAXBElement wrappers works for cases where no @XmlRootElement is generated by JAXB. These wrappers are available in ObjectFactory class generated by maven-jaxb2-plugin. For eg:

     public class HelloWorldEndpoint {
        @PayloadRoot(namespace = NAMESPACE_URI, localPart = "person")
        @ResponsePayload
        public JAXBElement<Greeting> sayHello(@RequestPayload JAXBElement<Person> request) {

        Person person = request.getValue();

        String greeting = "Hello " + person.getFirstName() + " " + person.getLastName() + "!";

        Greeting greet = new Greeting();
        greet.setGreeting(greeting);

        ObjectFactory factory = new ObjectFactory();
        JAXBElement<Greeting> response = factory.createGreeting(greet);
        return response;
      }
 }
zer0Id0l
  • 1,264
  • 2
  • 19
  • 34
3

Did you try to change your xsd like this?

<!-- create-logical-system -->
<xs:element name="methodCall">
  <xs:complexType>
    ...
  </xs:complexType>
</xs:element>
Tony
  • 31
  • 2
  • This worked for me with JDK 1.7u71. A top level element gets assigned the @XmlRootElement by xjc. Initially I had a top level complex type only. Having to wrap in a JAXBElement is plain ugly. – Serge Merzliakov Jan 28 '15 at 06:47
2

The topic is quite old but still relevant in enterprise business contexts. I tried to avoid to touch the xsds in order to easily update them in the future. Here are my solutions..

1. Mostly xjc:simple is sufficient

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    jxb:extensionBindingPrefixes="xjc">

    <jxb:globalBindings>
        <xjc:simple/> <!-- adds @XmlRootElement annotations -->
    </jxb:globalBindings>

</jxb:bindings>

It will mostly create XmlRootElements for importing xsd definitions.

2. Divide your jaxb2-maven-plugin executions

I have encountered that it makes a huge difference if you try to generate classes from multiple xsd definitions instead of a execution definition per xsd.

So if you have a definition with multiple <source>'s, than just try to split them:

          <execution>
            <id>xjc-schema-1</id>
            <goals>
              <goal>xjc</goal>
            </goals>
            <configuration>
              <xjbSources>
                <xjbSource>src/main/resources/xsd/binding.xjb</xjbSource>
              </xjbSources>
              <sources>
                <source>src/main/resources/xsd/definition1/</source>
              </sources>
              <clearOutputDir>false</clearOutputDir>
            </configuration>
          </execution>

          <execution>
            <id>xjc-schema-2</id>
            <goals>
              <goal>xjc</goal>
            </goals>
            <configuration>
              <xjbSources>
                <xjbSource>src/main/resources/xsd/binding.xjb</xjbSource>
              </xjbSources>
              <sources>
                <source>src/main/resources/xsd/definition2/</source>
              </sources>
              <clearOutputDir>false</clearOutputDir>
            </configuration>
          </execution>

The generator will not catch the fact that one class might be sufficient and therefore create custom classes per execution. And thats exactly what I need ;).

judomu
  • 428
  • 3
  • 13
1

To soluction it you should configure a xml binding before to compile with wsimport, setting generateElementProperty as false.

     <jaxws:bindings wsdlLocation="LOCATION_OF_WSDL"
      xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
      xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
      xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
         <jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle>
    <jaxws:bindings  node="wsdl:definitions/wsdl:types/xs:schema[@targetNamespace='NAMESPACE_OF_WSDL']">
      <jxb:globalBindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema">
            <xjc:generateElementProperty>false</xjc:generateElementProperty> 
      </jxb:globalBindings>
  </jaxws:bindings>
</jaxws:bindings>
leandruol
  • 11
  • 1
0

I just was struggling for a while with the same problem and just want to post my final result which works fine for me. So the base problems have been:

  • I have to generate xml strings from JAXB class instances with have no XmlRootElement annotations
  • The classes need additional classes to be bound for the marshalling process

The following class works fine for this problem:

public class Object2XmlConverter {

    public static <T> String convertToString(final T jaxbInstance, final Class<?>... additionalClasses)
            throws JAXBException {
        final Class<T> clazz = (Class<T>) jaxbInstance.getClass();

        final JAXBContext jaxbContext;
        if (additionalClasses.length > 0) {
            // this path is only necessary if you need additional classes to be bound
            jaxbContext = JAXBContext.newInstance(addClassesToBeBound(clazz, additionalClasses));
        } else {
            jaxbContext = JAXBContext.newInstance(clazz);
        }

        final QName qname = new QName("", jaxbInstance.getClass().getSimpleName());
        final JAXBElement<T> jaxbElement = new JAXBElement<T>(qname, clazz, null, jaxbInstance);

        final Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        final StringWriter stringWriter = new StringWriter();
        jaxbMarshaller.marshal(jaxbElement, stringWriter);
        return stringWriter.toString();
    }

    private static <T> Class<?>[] addClassesToBeBound(final Class<T> clazz, final Class<?>[] additionalClasses) {
        final Class<?>[] classArray = new Class<?>[additionalClasses.length + 1];
        for (int i = 0; i < additionalClasses.length; i++) {
            classArray[i] = additionalClasses[i];
        }
        classArray[classArray.length - 1] = clazz;
        return classArray;
    }

    public static void main(final String[] args) throws Exception {
        final Ns1TargetHeaderTyp dataTyp = ...;
        System.out.println(convertToString(dataTyp));
    }
}