Jaxb implClass specification ignored for rootElement - java

I'm trying to specify a implementation class for an XSD-Type.
Here's a minimal example schema:
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="rd.test"
xmlns:tns="rd.test" elementFormDefault="qualified"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0">
<complexType name="DocumentType">
<annotation>
<appinfo>
<jaxb:class implClass="rd.DocumentEx" />
</appinfo>
</annotation>
<sequence>
<element name="element" type="tns:DocumentType" />
</sequence>
<attribute name="title" type="string" />
</complexType>
<element name="document" type="tns:DocumentType"/>
</schema>
I'm using the standard xjc-tool from the Java JDK (1.7) for now (but I've also tested with maven-jaxb2-plugin, with the same results).
For a short test I used the following XML-document:
<?xml version='1.0' standalone='yes' ?>
<document title="testDocument">
<element title="testElement" />
</document>
When I run the following test program, the results differ for the top-level document element (testDocument) and the contained child element (testElement). The root is of type "DocumentType", i.e. ignoring the specified implClass-directive, whereas the element is of type "DocumentEx", which is the expected result.
In the generated ObjectFactory the appropriate instantiation seems correct, but it seems to be not used for the rootElement:
public DocumentType createDocumentType() {
return new DocumentEx();
}
Here is the test program:
InputStream inp=new FileInputStream(new File("test.xml"));
JAXBContext jaxbContext = JAXBContext.newInstance("test.rd");
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
JAXBElement el = (JAXBElement)unmarshaller.unmarshal(inp);
Object obj = el.getValue();
System.out.println("doc: " + obj);
// result: "doc: test.rd.DocumentType#d1c5bb0"
DocumentType doc = (DocumentType)obj;
Object obj2=doc.getElement();
System.out.println("obj2: " + obj2);
// result: "obj2: rd.DocumentEx#d1c5bb0"
I get the same result, if I specify the implClass for the element instead of for the complexType.
Why is the implClass ignored for the root-element?
Any ideas and hints are appreciated!
Extension to clarify my intention:
I don't want to reference an existing, jaxb-annotated class, but use the auto-generated DocumentType-Class as base class for extionsion with additional attributes and methods. For a later direct marshalling back to XML, I have to keep the relation to the XSD-Type. Therefore the implClass-directive actually is the appropriate (as far as I know) way to instrument the jaxb-generation of the type-classes.
And it's working perfectly for the inner elements (the 'element' with title 'testElement' inside the document-tag)!! Unfortunately the unmarshaller does NOT use the implClass-specified class for instantiating the root-element correctly. See the result-comments in the program excerpt above (doc vs. obj2).

For the behaviour you are looking for I believe you want to specify ref and not impl:
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="rd.test"
xmlns:tns="rd.test" elementFormDefault="qualified"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0">
<complexType name="DocumentType">
<annotation>
<appinfo>
<jaxb:class ref="rd.DocumentEx" />
</appinfo>
</annotation>
<sequence>
<element name="element" type="tns:DocumentType" />
</sequence>
<attribute name="title" type="string" />
</complexType>
<element name="document" type="tns:DocumentType"/>
</schema>
This tells JAXB to use the rd.DocumentEx class for the DocumentType complex type. Now a DocumentType class is not created, and the createDocument method on the ObjectFactory looks like this:
#XmlElementDecl(namespace = "rd.test", name = "document")
public JAXBElement<DocumentEx> createDocument(DocumentEx value) {
return new JAXBElement<DocumentEx>(_Document_QNAME, DocumentEx.class, null, value);
}
From section 7.7.1 of the JAXB 2.2 specification:
• implClass if specified, is the name of the implementation class for
className and must include the complete package name. Note that this
customization only impacts the return value for className’s factory
method. This customization is ignored when new is used to create
instances of a schema-derived Value class.
• ref if specified, is the
name of the value class that is provided outside the schema compiler.
This customization causes a schema compiler to refer to this external
class, as opposed to generate a definition. It must include the
complete package name. This attribute is mutually exclusive with the
className attribute and the implClass attribute.

Related

How to refactor XSD so that unmarshalling does not return JAXBElement

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:
If I remove/replace <xsd:any processContents="skip" /> declaration, JAXB starts to return org.foo.bar.Unit.
If I remove <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!
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);
Use this method to work with, either a javax.xml.bind.JAXBElement instance or an instance of #XmlRootElement annotated Java class:
public <T> T unmarshal(Source queryResults, String modelPackages) {
T resultObject = null;
try {
JAXBContext jc = JAXBContext.newInstance(modelPackages);
Unmarshaller u = jc.createUnmarshaller();
resultObject = (T) JAXBIntrospector.getValue(u.unmarshal(queryResults));
} catch (JAXBException e) {
LOG.error(e.getMessage(), e);
} catch (ClassCastException e) {
LOG.error(e.getMessage(), e);
}
return resultObject;
}
Edit:
You have reason, I putted this code because is a code I did for a project and that I think that is more reusable.
So for you question:
Why JAXB wraps org.foo.bar.Unit into JAXBElement for above combination?
because you are telling it to do it with <xsd:any processContents="skip" /> :)
Well, when you put this in your XSD you acts like if you use the annotation:
#XmlAnyElement(lax=false)
With that tag / annotation you are saying to JAXB: 'here comes something, a bunch of nodes, (#XmlAnyElement) that you should not parse never; let it as DOM object, please (lax=false)' try with:
processContents=lax
This way it should try to parse your xml to domain object and will return Unit if it can find it or JAXBElement otherway or:
processContents=strict
Which will try to parse it to your domain object
After some googling I have found an answer, which is basically given by Kohsuke Kawaguchi in Why does JAXB put #XmlRootElement sometimes but not always. It turned out that the decision to add #XmlRootElement annotation is antagonist to generation of helper factory method. One should enable <xjc:simple /> optimization and JAXB will assume that all elements are root elements:
<xsd:schema xmlns:bar="http://www.foo.org/bar"
xmlns:xsd="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"
targetNamespace="http://www.foo.org/bar"
jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.1" elementFormDefault="qualified">
<xsd:annotation>
<xsd:appinfo>
<jaxb:globalBindings>
<xjc:simple />
</jaxb:globalBindings>
</xsd:appinfo>
</xsd:annotation>
<xsd:element name="unit" type="bar:unit" />
<xsd:complexType name="unit">
<xsd:sequence>
<xsd:any processContents="skip" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

Jaxb: Generate constant value for fixed-value attribute

I'm currently working on a xsd which uses the following contruct:
<xs:attribute name="listVersionID" type="xs:normalizedString" use="required" fixed="1.0">
While not problematic per se, it is rather annoying to work with, since the fixed-value of this definition increases between releases of the xsd spec, and we need to modify the values in a seperate constants-class to keep them valid, although little if anything of interest in the xsd has changed. The xsd is maintained elsewhere, so just changing it is no option.
Thus I was asking myself wether there is a jaxb-plugin or similar to turn fixed-value attributes into constants ala
#XmlAttribute(name = "listVersionID")
#XmlJavaTypeAdapter(NormalizedStringAdapter.class)
#XmlSchemaType(name = "normalizedString")
protected final String listVersionID = "1.0";
instead of just
#XmlAttribute(name = "listVersionID")
#XmlJavaTypeAdapter(NormalizedStringAdapter.class)
#XmlSchemaType(name = "normalizedString")
protected String listVersionID;
which must be populated manually.
Does anyone know of such?
If you don't want to modify your schema, another option is to use an external binding file:
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jaxb:bindings schemaLocation="yourschema.xsd" node="/xs:schema">
<jaxb:globalBindings fixedAttributeAsConstantProperty="true" />
</jaxb:bindings>
</jaxb:bindings>
It is equivalent to what proposes #jmattheis in his answer.
Yes it is possible through custom jaxb bindings, which can be added as file at the codegen.
In the jaxb bindings, there is the fixedAttributeAsConstantProperty-attribute. Setting this to true, instructs the code generator to generate attributes with the fixed attribute as java-constants.
There are 2 options for this:
1. Through global bindings:
which then make all attributes with fixed values to constants
<schema targetNamespace="http://stackoverflow.com/example"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0">
<annotation>
<appinfo>
<jaxb:globalBindings fixedAttributeAsConstantProperty="true" />
</appinfo>
</annotation>
...
</schema>
2. Through local mappings:
Which only defines the fixedAttributeAsConstantProperty property on a specific attribute.
<schema targetNamespace="http://stackoverflow.com/example"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:version="2.0">
<complexType name="example">
<attribute name="someconstant" type="xsd:int" fixed="42">
<annotation>
<appinfo>
<jaxb:property fixedAttributeAsConstantProperty="true" />
</appinfo>
</annotation>
</attribute>
</complexType>
...
</schema>
Both examples should result in:
#XmlRootElement(name = "example")
public class Example {
#XmlAttribute
public final static int SOMECONSTANT = 42;
}

JAXB always marshalls extension - unable to get elements of a super type only

I'm stuck on a problem with JAXB / Spring Web Services. Below is the detailed description. I appreciate any suggestion that could help me to solve it. I can provide more if details if needed.
I am writing a web service that returns list of some entities. Spring WS is contract-first framework, so I started with the XSD similar to:
<element name="GetEntitiesRequest" type="Something"/>
<element name="GetEntitiesResponse" type="Entities"/>
<complexType name="Entities">
<sequence>
<element name="Entity" type="Entity" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<complexType name="Entity">
<sequence>
(...)
</sequence>
</complexType>
It was working well. However, the "Entity" type begin to grow (there a lot of elements) which caused performance issues (there are many Entities in the response). So I decided to split "Entity" into two parts
Some general information that will be returned within the group response - Entity
More detailed information that will be returned in an another web service operation, specific for the entity - EntityDetails
So after the change the schema is as follows (EntityDetails inherits from Entity):
<element name="GetEntitiesRequest" type="Something"/>
<element name="GetEntitiesResponse" type="Entities"/>
<complexType name="Entities">
<sequence>
<element name="Entity" type="Entity" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<complexType name="Entity">
<sequence>
(...)
</sequence>
</complexType>
<element name="GetEntityDetailsRequest" type="SomethingMore"/>
<element name="GetEntityDetailsResponse" type="EntityDetails"/>
<complexType name="EntityDetails">
<complexContent>
<extension base="Entity">
<sequence>
(...)
</sequence>
</extension>
</complexContent>
</complexType>
JAXB (precisely: hyperjaxb3) generates classes for Entity (inheritance strategy = JOINED), EntityDetails, and Entities. Also, it creates the ObjectFactory with "createGetEntitiesResponse" method. I am using this method to marshall List retrieved through Hibernate from the Entity table.
Theoretically, I should get list of "Entity" when sending "GetEntitiesRequest". However, I get list of "EntityDetails" instead.
If you read this form the beginning, you can imagine, that this what I wanted to avoid.
If you need more details, persistence.xml is as follows:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence (...)>
<persistence-unit name="org.package">
<class>org.package.Entity</class>
<class>org.package.EntityDetails</class>
<class>org.package.Entities</class>
</persistence-unit>
</persistence>
I use Gradle for the build automation, and its jaxb plugin for the class generation:
jaxb
{
xsdDir = "src/main/webapp/schemas/messages"
bindingsDir = "src/main/webapp/schemas/bindings"
bindings = ["bindings.xjb"]
xjc
{
extension = true
taskClassname = "com.sun.tools.xjc.XJC2Task"
generatePackage = "org.package"
args = ["-Xannotate", "-Xhyperjaxb3-jpa2", "-Xequals", "-XhashCode", "-XtoString"]
}
}
currently, the bindings.xjb, beyond header, contains only:
<jaxb:globalBindings localScoping="toplevel">
<xjc:serializable/>
</jaxb:globalBindings>
First of all, make sure that you get instances Entity from the database, NOT EntityDetails.
Try to create an isolated scenario, without the database. Just instantiate your Entity, fill it with something create the response and marshal it. See what happens.
You'll isolate the problem - either you're getting wrong instances from the database or the marshalling does not work as expected. Both is a bit hard to diagnose without seeing your code. Try to reduce your problem to one of the two I mentioned above.
Diclaimer: I'm the author of Hyperjaxb3.

XSD: constrain attribute value of element to a substring of parent attribute

Consider this piece of XML
<Parent id="MyParent1">
<Child id="MyParent1.MyChild1"/>
</Parent>
<Parent id="MyParent2">
<Child id="MyParent2.MyChild1"/>
<Child id="MySillyIncorrectPrefix.MyChild2"/>
</Parent>
How can I validate (possibly with XSD) Child elements whose id contains the Parent element id as a prefix, so that:
<Child id="MyParent2.MyChild1"/> <!-- is valid -->
<Child id="MySillyIncorrectPrefix.MyChild2"/> <!-- is not valid -->
I'm not bound to XSD version 1.0, so I could try with XSD 1.1 (and features like assertions), but I would like to know:
how to express the above constraint with an xs:assertion or more suitable XSD 1.1
feature.
if it's possible to build a validator in Java leveraging on
that xsd? "Xerces-J" is a feasible solution ?
In my limited knowledge of XSD 1.1 I came up with this attempt:
<xs:element name="Child">
<xs:complexType>
<xs:attribute name="type" type="xs:String" />
<xs:assert test="starts-with(#type,../#type)"/>
</xs:complexType>
</xs:element>
Is this correct? Is there a tool where I could test it?
Being more general: is there a tool to assist the build&test of such XSD 1.1 featured schemas? (afaik Eclipse supports only XSD 1.0)
What you describe is not feasible in XSD 1.0.
In XSD 1.1 you can use assertions on the type of the parent to require each child's id attribute to begin with the value of the parent's id attribute.
This schema should validate the example (use an xsd 1.1 assertion)
<?xml version="1.1" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/stackoverflow" xmlns:tns="http://www.example.org/stackoverflow" elementFormDefault="qualified">
<complexType name="ParentType">
<sequence>
<element name="Child" type="tns:ChildType"
maxOccurs="unbounded" minOccurs="0">
</element>
</sequence>
<attribute name="id" type="string"></attribute>
</complexType>
<element name="Parent" type="tns:ParentType"></element>
<complexType name="ChildType">
<attribute name="id" type="string"></attribute>
<assert test="starts-with(#id,../#id)"/>
</complexType>
</schema>

XMLBeans nested complex element instantiation failure

I'm using XMLBeans to generate java objects from a XSD schema.
The Schema is in the following structure :
<schema targetNamespace="" xmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<element name="Father">
<complexType>
<all>
<element name="Son">
<complexType>
<all>
<element name="Target" type="string" />
</all>
</complexType>
</element>
</all>
</complexType>
</element>
</schema>
The schema is compiled allright and I'm able to instantiate the Father by:
Father father = Father.Factory.newInstance();
But when I try to perform :
father.getSon().setTarget("Some String");
I get a null pointer exception. When debugging it, I saw that Son is null (hence the exception).
All I need is to set the "Target" value, but I couldn't figure a way to do it....
Is there a way to auto-build all the XSD structure? Alternatively, can I instantiate the "Son" manually and then access its "Target"?
Thanks a lot!
O.J
getSon() method allows you to get the existing child called Son. If you're trying to generate a new xml, you have to start with an empty document. Then you should add your elements as you wish before accessing them.
Try this code:
FatherDocument fatherDocument = FatherDocument.Factory.newInstance();
Father father = fatherDocument.addNewFather();
Son son = father.addNewSon();
son.setTarget("Some string");
StringWriter writer = new StringWriter();
fatherDocument.save(writer);
System.out.println(writer.toString());
I've generated this xml:
<Father><Son><Target>Some string</Target></Son></Father>

Categories