18

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?

TL Stillman
  • 305
  • 1
  • 3
  • 10
  • See http://stackoverflow.com/questions/3639313/xsd-formatting-elementcomplextype-vs-complextype-element/3639375#3639375 for an explanation – skaffman Sep 07 '10 at 11:56
  • @skaffman: Eh? I don't see how your answer relates to whether xjc chooses `JAXBElement` over `Foo`. – C. K. Young Sep 07 '10 at 12:03
  • 1
    @Chris: Because it is determined in part by the choice of anonymous types or names types in the source schema. – skaffman Sep 07 '10 at 12:14

2 Answers2

11

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:

bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • Thanks, substitution groups are indeed where this is happening. So is it then a bug that in `afterUnmarshal(Unmarshaller u, Object parent)` these substitutable classes are being passed their own JAXBElement as their `parent`? Especially since there doesn't seem to be a way to get the real parent element from the JAXBElement. – TL Stillman Sep 07 '10 at 16:05
  • This appears to be a bug in Metro JAXB (the reference implementation, included in Java SE 6). In the MOXy JAXB implementation (http://www.eclipse.org/eclipselink/moxy.php) the correct parent object is passed to the afterUnmarshal method. – bdoughan Sep 07 '10 at 18:07
0

To avoid mapping to JAXBElement? I have done this things it work for me :

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
           xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
           jaxb:extensionBindingPrefixes="xjc"
           jaxb:version="2.0">

    <xs:annotation>
       <xs:appinfo>
          <jaxb:globalBindings generateValueClass="false">
           <xjc:simple />
          </jaxb:globalBindings>
       </xs:appinfo>
    </xs:annotation>

</xs:schema>

Save this file in the xml file and supply as binding files.

Reference Link

Generate JAXB classes using eclipse dont forget to give binding files created with above xml and check "Allow Vendor extensions" as below:

enter image description here

With changes i am able Get rid of JAXBElement in classes generated xjc for convert xsd to JAXB generated classes.

Gautam
  • 3,707
  • 5
  • 36
  • 57