42
votes

What's the difference between annotating a class with @XMLRootElement and @XMLType. I've been annotating classes with @XMLType when the structure will be used more than once within an XML schema and with @XMLRootElement when it will be used only once - is this the best approach?

A different but related question which I'll include here. The @XMLType annotation has an propOrder attribute to specify in which order its elements appear - is there an equivalent for @XMLRootElement?

I'm using these annotations in conjunction with JAX-WS annotations to create web services if that makes any difference.

2

2 Answers

23
votes

The difference between XmlRootElement and XmlType is a matter of scoping. Remember this annotation is merely dictating the creation of the schema used to generate your XML. The XmlRootElement denotes a global element (with an anonymous or schema type):

<xs:element name=foo type="bar"> </xs:element> <-- schema type

while the XmlType is used to denote a local element (with an anonymous or complex type):

<xs:complexType name=bar> </xs:complexType> <-- complex type

The main differences in local/global here are in the hierarchy of the schema your object will appear in and whether you are declaring a schema type or complex type. The documentation for both of these annotations is well written and includes examples:

XmlRootElement

XmlType

EDIT: Addressing the propOrder question: you can use it on a global element if you are also declaring a local type:

@XmlRootElement (name="PersonElement")
@XmlType (propOrder={"firstname", "lastname"})
public class People{
    @XmlElement
    public String firstname;
    public String lastname;
}

This will yield something like:

<xs:element name="PersonElement" type="People"/>
<xs:complexType name="People">
    <xs:sequence>
        <xs:element name="firstname" type="xs:string"/>
        <xs:element name="lastname" type="xs:string"/>
    </xs:sequence>
</xs:complexType>
17
votes

I've been annotating classes with @XMLType when the structure will be used more than once within an XML schema and with @XMLRootElement when it will be used only once - is this the best approach?

One thing to know is that neither the @XmlRootElement or @XmlType annotation is required. They aren't the equivalent of @Entity from JPA. You can use a JAXB (JSR-222) implementation without any annotations what so ever:

Below I'll explain what @XmlRootElement and @XmlType do.


@XmlRootElement

There are times when your JAXB implementation needs to instantiate an object based only on the XML element that is being processed. The @XmlRootElement annotation is the primary means of specifying this association. Note if a class corresponds to more than one XML element then the @XmlElementDecl annotation should be used insteat,

ROLE #1 - Specifying the Root Object

@XmlRootElement is primarily used to specify the root object. This is so when your JAXB implementation begins unmarshalling an XML document it knows what object to instantiate. Almost all subsequent annotations will be based on information gathered from the parent class.

Foo

@XmlRootElement(name="root")
public class Foo {

    private String name;

}

Bar

public class Bar {

    private String name;

}

XML

<root>
    <name>Jane Doe</name>
</root>

Demo

Foo foo = (Foo) unmarshaller.unmarshal(xml);
Bar bar = unmarshaller.unmarshal(xml, Bar.class).getValue();

ROLE #2 - Substitution Groups

The @XmlElementRef annotation delegates the type of object instantiated to the name/uri of the element. This enables the mapping to the concept of substitution groups for representing inheritance.

ROLE #3 - Any Content

@XmlAnyElement allows you to map a wild card section of your XML document. If you specify @XmlAnyElement(lax=true) then elements associated with domain objects will be converted to the corresponding domain object.


@XmlType

ROLE #1 - Schema Gen

By default a named complex type is generated for each Java class known to the JAXB context. You can control the name of this type using the @XmlType annotation, or specify that an anonymous complex type should be generated by specifying the name as "".

ROLE #2 - Inheritance and xsi:type

By default JAXB leverages the xsi:type attribute as the inheritance indicator. The value on this attribute corresponds to the name and namespace you have specified on the @XmlType annotation, or is defaulted based on the class.

ROLE #3 - Prop Order

As you mention you can use the @XmlType to specify the property order.

ROLE #4 - Factory Methods

@XmlType allows you to specify a factory class and/or method that can be used to instantiate the domain object instead of the default constructor.


A different but related question which I'll include here. The @XMLType annotation has an propOrder attribute to specify in which order it's elements appear - is there an equivalent for @XMLRootElement?

No, the propOrder aspect belongs to the @XmlType annotation. This makes sense since complex types are responsible for specifying an (or lack of) order. You can of course use these annotations at the same time.

@XmlRootElement
@XmlType(propOrder={"foo", "bar"}
public class Root {
    ...
}