Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does JAXB sometimes map to JAXBElement?

Tags:

java

jaxb

jaxb2

There is a placeholder answer over at the unofficial guide with a link to an article which (to me) seems quite unrelated.

I use XJC to generate my JAXB classes and while most of them map to each other as expected, some elements get mapped to JAXBElement<Foo>. This is most annoying for graphs with cycles, where sometimes the parent node of a Foo element will be the JAXBElement<Foo>, which doesn't itself have a parent property, breaking the cycle.

I can think of various workarounds, but it would be much nicer if someone could explain this behaviour to me. Why does JAXB sometimes map a <Foo> element to JAXBElement<Foo> instead of Foo?

like image 703
TL Stillman Avatar asked Sep 07 '10 11:09

TL Stillman


People also ask

Why JAXBElement?

JAXBElement is used to preserve the element name/namespace in use cases where enough information is not present in the object model. It's often used with substitution groups. Without any JAXB metada the result will be wrapped in a JAXBElement.

What is JAXBElement?

public class JAXBElement<T> extends Object implements Serializable. JAXB representation of an Xml Element. This class represents information about an Xml Element from both the element declaration within a schema and the element instance value within an xml document with the following properties. element's xml tag name.

How do I get JAXBElement value?

If getProject() returns the type JAXBElement<String> then getName() returns the name of the XML tag. To get the value of that element you need to call getValue() .

What is the use of ObjectFactory in JAXB?

jaxb package. An ObjectFactory allows you to programatically construct new instances of the Java representation for XML content. The Java representation of XML content can consist of schema derived interfaces and classes representing the binding of schema type definitions, element declarations and model groups.


1 Answers

JAXBElement is used to preserve the element name/namespace in use cases where enough information is not present in the object model. The most common occurence is with substitution groups:

With Substitution Group:

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

    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="anElement"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="anElement" type="xs:string"/>

    <xs:element name="aSubstituteElement" type="xs:string" substitutionGroup="anElement"/>

</xs:schema>

Will generate:

package org.example;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "anElement"
})
@XmlRootElement(name = "root")
public class Root {

    @XmlElementRef(name = "anElement", namespace = "http://www.example.org", type = JAXBElement.class)
    protected JAXBElement<String> anElement;

    public JAXBElement<String> getAnElement() {
        return anElement;
    }

    public void setAnElement(JAXBElement<String> value) {
        this.anElement = ((JAXBElement<String> ) value);
    }

}

Without Substitution Group:

If you remove the substitution group:

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

    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="anElement"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="anElement" type="xs:string"/>

</xs:schema>

The following class will be generated:

package org.example;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "anElement"
})
@XmlRootElement(name = "root")
public class Root {

    @XmlElement(required = true)
    protected String anElement;

    public String getAnElement() {
        return anElement;
    }

    public void setAnElement(String value) {
        this.anElement = value;
    }

}

You may also get a JAXBElement when you unmarshal, compare the following examples:

  • Without any JAXB metada the result will be wrapped in a JAXBElement
  • Using @XmlRootElement eliminates the root level JAXBElement
like image 66
bdoughan Avatar answered Sep 21 '22 04:09

bdoughan