I have the following schema:
<xsd:schema xmlns:bar="http://www.foo.org/bar"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:annox="http://annox.dev.java.net"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
targetNamespace="http://www.foo.org/bar"
jaxb:extensionBindingPrefixes="annox" jaxb:version="2.1" elementFormDefault="qualified">
<xsd:element name="unit" type="bar:unit" />
<xsd:complexType name="unit">
<xsd:annotation>
<xsd:appinfo>
<annox:annotate>@javax.xml.bind.annotation.XmlRootElement(name="unit")</annox:annotate>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
<xsd:any processContents="skip" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
When I unmarshall this XML
<unit xmlns="http://www.foo.org/bar">
<text>Name</text>
</unit>
the returned object is javax.xml.bind.JAXBElement<Unit>
, however I would like to get org.foo.bar.Unit
back. I need this because unmarshalling in my case happens implicitly by JAX-RS provider or SpringWeb.
Observations:
<xsd:any processContents="skip" />
declaration, JAXB starts to return org.foo.bar.Unit
.<xsd:element name="unit" type="bar:unit" />
declaration, JAXB starts to return org.foo.bar.Unit
(although one need to disable validation during unmarshalling).Thus I would say that given XSD is the smallest XSD that demonstrates the problem.
Questions: Why JAXB wraps org.foo.bar.Unit
into JAXBElement
for above combination? From what I see, there is no way the XSD type unit
can have tag name different from unit
, so why JAXB needs this factory method?
@XmlElementDecl(namespace = "http://www.foo.org/bar", name = "unit")
public JAXBElement<Unit> createUnit(Unit value) { ... }
The project demonstrating the problem for JAXB 2.2.7 is here. When run it outputs the following:
Running org.foo.bar.UnitTest
>>> Class is: javax.xml.bind.JAXBElement
>>> XML is: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><unit xmlns="http://www.foo.org/bar"><text>Name</text></unit>
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.318 sec <<< FAILURE!
To unmarshal an xml string into a JAXB object, you will need to create an Unmarshaller from the JAXBContext, then call the unmarshal() method with a source/reader and the expected root object.
JAXB definitionsMarshalling is the process of transforming Java objects into XML documents. Unmarshalling is the process of reading XML documents into Java objects. The JAXBContext class provides the client's entry point to the JAXB API. It provides API for marshalling, unmarshalling and validating.
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.
Annotation Type XmlElementRef. @Retention(value=RUNTIME) @Target(value={FIELD,METHOD}) public @interface XmlElementRef. Maps a JavaBean property to a XML element derived from property's type. Usage. @XmlElementRef annotation can be used with a JavaBean property or from within XmlElementRefs.
Adding to Ian's answer,
Any complex
element that is named by root
element will have factory method annotated with @XmlElementDecl()
.
You can resolve this, by moving the complex
type declaration inline like below.
<xsd:schema xmlns= "http://www.foo.org/bar" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:annox="http://annox.dev.java.net" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
targetNamespace="http://www.foo.org/bar" jaxb:extensionBindingPrefixes="annox"
jaxb:version="2.1" elementFormDefault="qualified">
<xsd:element name="unit">
<xsd:complexType>
<xsd:annotation>
<xsd:appinfo>
<annox:annotate>@javax.xml.bind.annotation.XmlRootElement(name="unit")
</annox:annotate>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
<xsd:any processContents="skip" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
ObjectFactory.class (no JAXBElement
factory method generated here)
@XmlRegistry
public class ObjectFactory {
/**
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.foo.bar
*
*/
public ObjectFactory() {
}
/**
* Create an instance of {@link Unit }
*
*/
public Unit createUnit() {
return new Unit();
}
}
Test class:
@Test
public void testUnmarshalling() throws JAXBException, SAXException {
JAXBContext context = JAXBContext.newInstance(Unit.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setSchema(SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
.newSchema(new StreamSource(getClass().getClassLoader().getResourceAsStream("common.xsd"))));
Object unit = unmarshaller.unmarshal(getClass().getResourceAsStream("unit.xml"));
System.out.println(">>> Class is: " + unit.getClass().getName());
StringWriter writer = new StringWriter();
context.createMarshaller().marshal(unit, writer);
System.out.println(">>> XML is: " + writer.toString());
//assertTrue(unit instanceof Unit);
}
Test xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<unit xmlns="http://www.foo.org/bar">
<text>Name</text>
</unit>
output :
>>> Class is: org.foo.bar.Unit
>>> XML is: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><unit xmlns="http://www.foo.org/bar"><text>Name</text></unit>
From what I see, there is no way the XSD type unit can have tag name different from unit, so why JAXB needs this factory method?
On the contrary - you will always get a JAXBElement
when your schema uses a named complex type by reference. With a named complex type there's always the possibility that the type might be used for a different element (maybe in another importing schema) or that the element may use a subtype of the named type rather than the top type itself.
Unwrapped root elements are used when the global xsd:element
declaration has a nested anonymous complexType
, as in that scenario the unmarshaller knows that those kinds of substitutions can't happen.
If you are doing something like this:
JAXBContext jaxbContext = JAXBContext.newInstance(Unit.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
JAXBElement<Unit> root = jaxbUnmarshaller.unmarshal(new StreamSource(
file), Unit.class);
Unit unit = root.getValue();
Try maybe:
Unit unit = JAXBIntrospector.getValue(jaxbUnmarshaller.unmarshal(new StreamSource(
file), Unit.class);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With