JAXB Marshalling - extending an existing class - jaxb

I am in need of creating a series of Java objects via XML using JAXB that all extend a common base class that is already created (not using JAXB). For example, let's say I have following JAXB classes that I am trying to generate:
Penguin.xml -> Penguin.java
Robin.xml -> Robin.java
Cardinal.xml -> Cardinal.java
I already have an existing base class called Bird.java that I wish the three classes above to extend.
What is the best way to do this?
Thanks for your help!

That is very simple: you need to to create a JAXB binding file with following contents:
<jaxb:bindings version="1.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
>
<jaxb:globalBindings>
<!-- All beans should extend this base class: -->
<xjc:superClass name="org.mycompany.common.Bird" />
</jaxb:globalBindings>
</jaxb:bindings>
More information on this option (and other sweet things) you can find here.

Related

Generating jaxb classes with naming conflicts

I have created a new JAXB project and imported an xsd which I am trying to generate JAXB classes off of. When I select "Generate->JAXB Classes" I get a number of similar errors all which relate to naming conflicts:
A class/interface with the same name "generated.Document" is already in use. Use a class customization to resolve this conflict.
The above error is thrown from the following piece of the .xsd file
<xs:complexType name="Document">
<xs:sequence>
<xs:element ref="Document"/>
</xs:sequence>
</xs:complexType>
<xs:element name="Document">
...
Changing the .xsd file is not an option for me so I have to find another way. I have been reading about the possibility of creating a bindings file. I can't seem to find good documentation on how to do that for my particular problem. My three main questions are:
Should I create a new bindings .xjb file and add it to eclipse to solve this issue?
How should this bindings file look in order to resolve the "Document" naming conflicts?
How do I get eclipse to recognize the bindings file when I run "Generate -> JAXB Classes
Should I create a new bindings .xjb file and add it to eclipse to solve this issue?
yes, you can with an xjb file
How should this bindings file look in order to resolve the "Document" naming conflicts?
(e.g. I don't know your entire xsd, this is only an example)
<bindings version="2.0" xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:annox="http://annox.dev.java.net">
<bindings node="xs:complexType[#name='Document']">
<class name="Item"/>
</bindings>
</bindings>
How do I get eclipse to recognize the bindings file when I run "Generate -> JAXB Classes
Eclipse allows you to attach an XJB file (Binding files:)
I hope I've given you all the answers about your question.

XSD having metadata at each field level

i have XML structure as below (just part of large XML)
<Person>
<firstName>
<lastName>
<Partner>
<firstName>
...
</Person>
i need to keep additional metadata with each field for example to indicate if its updatable or not
i c two approaches
1) add the metadata at each FIELD level. i feel this overly complicates the XSD as each element is now an OBJECT
<Person>
<firstName updatable="true" ... />
...
</Person>
2) separate out the metadata as below
BUt how do i link the metadata to the data? via a uniquie name? can someone consuming the XML easily link it?
Is there a better way? Thanks!
<data>
<Person>one
<firstName>
<lastName>
<Partner>
<firstName>
...
</Person>
<Person>two
<firstName>
<lastName>
<Partner>
<firstName>
...
</Person>
</data>
<metadata>
<field name="firstName" updateble="false"/>
....
</metadata>
i think this is similar to
Add metadata to an XSD definition
but it does not have any answer
My (maybe rhetoric) question would be why would someone want to see this metadata with each XML if it is static in relationship to the model?
I'll show you a UBL XSD snippet (XML namespaces elided as irrelevant):
<xsd:element ref="cbc:UBLVersionID" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>
<ccts:Component>
<ccts:ComponentType>BBIE</ccts:ComponentType>
<ccts:DictionaryEntryName>Application Response. UBL Version Identifier. Identifier</ccts:DictionaryEntryName>
<ccts:Definition>The earliest version of the UBL 2 schema for this document type that defines all of the elements that might be encountered in the current instance.</ccts:Definition>
<ccts:Cardinality>0..1</ccts:Cardinality>
<ccts:ObjectClass>Application Response</ccts:ObjectClass>
<ccts:PropertyTerm>UBL Version Identifier</ccts:PropertyTerm>
<ccts:RepresentationTerm>Identifier</ccts:RepresentationTerm>
<ccts:DataType>Identifier. Type</ccts:DataType>
<ccts:Examples>2.0.5</ccts:Examples>
</ccts:Component>
</xsd:documentation>
</xsd:annotation>
</xsd:element>
You could see here that there's a lot of structured data which could easily pass as something related to your question. Fundamentally though, this is a mechanism that uses the XSD annotations mechanism, to achieve things in relationship to the XSD. Another one is that used by JAXB custom binding mechanism:
<xsd:simpleType name="ZipCodeType">
<xsd:annotation>
<xsd:appinfo>
<jxb:javaType name="int" parseMethod="javax.xml.bind.DatatypeConverter.parseInt" printMethod="javax.xml.bind.DatatypeConverter.printInt"/>
</xsd:appinfo>
</xsd:annotation>
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="10000"/>
<xsd:maxInclusive value="99999"/>
</xsd:restriction>
</xsd:simpleType>
While this is different than the UBL example, (documentation vs. appinfo), both are using the XSD annotation mechanism.
JAXB's custom bindings also supports a model where the custom bindings are separate from the XSD (in their own separate XML file). The correlation between the custom binding file (the metadata in your case) and the XSD (the XML in your case) is done through XPath matches.
This brings about another clarification: what is the processing model you have in mind? Dynamic (i.e. the metamodel is static, but can be applied to arbitrary XSDs)? Platform? Below is a solution that could work for what you need, in a dynamic fashion, if it happens to match your platform.
.NET:
Build an XSD the way I've referred to above (i.e. annotations of some sort).
At runtime, validate your XML against this XSD. Each node will then have the SchemaInfo property filled in. Using classes in System.Xml.Schema you could easily process the SchemaElement or SchemaAttribute in your SchemaInfo property as an XmlSchemaAnnotated class, which is what both are.
The above is basically PSVI applied to your XML. The same exists for Java (on this Xerces page search for How do I retrieve PSVI from the DOM?)...
I could picture solutions for XSLT as well, or not involving XSD at all... the above though should be sufficient to get you started.

Class reuse with JAXB bindings don't honour SimpleTypes

I'm trying to reuse classes that are already compiled and available. This looks to be achievable by declaring bindings to the pre-existing classes as per example bindings extract below:-
<jaxb:bindings schemaLocation="MyExample.xsd">
<jaxb:bindings node="//xs:simpleType[#name='MySimpleType']">
<jaxb:class ref="com.example.MySimpleType" />
</jaxb:bindings>
<jaxb:bindings node="//xs:complexType[#name='MyComplexType']">
<jaxb:class ref="com.example.MyComplexType" />
</jaxb:bindings>
</jaxb:bindings>
The problem is that whilst complex types work just fine, the simple types are ignored and still generated....
I've tried a variety of different notations (e.g. scd) with no success on the Simple Types.
Any ideas or help very welcome....
If the generated class you are trying to reference is an enumeration (i.e. it implements javax.xml.bind.annotation.XmlEnum), then you need to use:
jaxb:typesafeEnumClass
instead of
jaxb:class
in the bindings.

generating JAXB objects from XML

I have a problem, I have an XSD file which I am trying to validate with an XML:
The XSD starts with:
<xs:schema id="Notes"
targetNamespace="http://mynotes.com/Notes"
elementFormDefault="qualified"
xmlns="http://mynotes.com/Notes"
xmlns:mstns="http://mynotes.com/Notes"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
Then I have the following XML:
<?xml version="1.0" encoding="utf-8"?>
<notes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="noNamespaceSchemaLocation" xmlns="http://mynotes.com/Notes">
In that case I can validate, but when I use JAXB to create an objects, the objects don't get populated and all their members are null.
But, If I modify the XML to the following:
<?xml version="1.0" encoding="utf-8"?>
<notes>...
In this case the JAXB objects are created successfully, but the validation fails...
I guess I am missing something with the namespace declaration, your help will be highly appreciated.
Thanks.
You can use the package level #XmlSchema annotation to specify the default namespace qualification for your JAXB model. Below is an example, you will need to adjust the package to be the same as your domain classes.
com/example/package-info.java
#XmlSchema(
namespace = "http://mynotes.com/Notes",
elementFormDefault = XmlNsForm.QUALIFIED)
package com.example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

JAXB - Creating modules for reuse

Does JAXB support modular code generation?
Most of my background is with JibX for XML marshalling, but for legacy reasons our firm is using JAXB.
One feature that was available for JIBX was modular code generation. Say I have a main schema but I have several different envelopes for that schema. With JibX I could create a jar file out of the JibX'ed core schema, and then in separate projects I could JibX my envelope schemas and simply point to the shared jar instead of having to duplicate the code generation of the core schemas for each envelope.
I don't yet see a way for JAXB to handle this - has anyone been successful doing something like this?
Thanks in advance,
Roy
For the JAXB RI, that's handled with "episode" files (these are really just customization files). Process the core schema first, making sure to have xjc use the -episode <file> arg. Package the results of that processing into a JAR file with the episode file in META-INF/sun-jaxb.episode. Then, pass that JAR file as an arg to xjc when processing the other schemas.
Using a JAXB 2.1 implementation (Metro, EclipseLink MOXy, Apache JaxMe, etc), you can specify that schema types correspond to existing classes in order to prevent them from being generated.
For example:
root.xsd
<?xml version="1.0"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.com/root">
<xsd:import schemaLocation="imported.xsd" namespace="http://www.example.com/imported"/>
<xsd:complexType name="root">
<xsd:attribute name="root-prop" type="xsd:string"/>
</xsd:complexType>
</xsd:schema>
imported.xsd
<?xml version="1.0"?>
<xsd:schema
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.example.com/imported"
targetNamespace="http://www.example.com/imported">
<xsd:complexType name="imported">
<xsd:attribute name="imported-prop" type="xsd:string"/>
</xsd:complexType>
</xsd:schema>
Problem Statement
If you use the XJC tool to generate java classes from the XML schema:
xjc -d out root.xsd
You the following is generated:
com\example\imported\Imported.java
com\example\imported\ObjectFactory.java
com\example\imported\package-info.java
com\example\root\ObjectFactory.java
com\example\root\Root.java
com\example\root\package-info.java
imported-bindings.xml
You can use a JAXB bindings file to specify that types from imported.xsd point to existing classes:
<jxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jxb:bindings schemaLocation="imported.xsd">
<jxb:bindings node="//xs:complexType[#name='imported']">
<jxb:class ref="com.example.imported.Imported"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
Running the XJC
Now if we run XJC with out bindings file:
xjc -d out -b imported-bindings.xml root.xsd
None of the files specified in the bindings file will be generated:
com\example\root\ObjectFactory.java
com\example\root\Root.java
com\example\root\package-info.java
Alternative Approach
The code generated from the imported schema directly (xjc imported.xsd) and indirectly (xjc root.xsd) is the same. You can simply drop the code generated indirectly and point at the project containing the code that was generated directly.

Resources