jaxb java class to multiple xml mappings - java

I have a couple of java classes that I want to convert to xml using jaxb. (I have no need to generate the classes based on the schema) I need to be able to map the class to different xml formats so I do not want to use annotations. From what I've seen my best option seems to be to use external xml bindings. So I wanted to know:
1) I am using eclipse. I am new to JAXB and I would like to know how to integrate external bindings using eclipse?
2) What other options other than external xml bindings are available?

I think you best option is to use MOXy XML bindings:
http://www.eclipse.org/eclipselink/documentation/2.6/moxy/runtime003.htm
This allows you to define XML<->Java mappings in form of XML files instead of annotations:
<?xml version="1.0" encoding="US-ASCII"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="example">
<java-types>
<java-type name="Customer">
<xml-root-element name="customer-info" />
<java-attributes>
<xml-attribute java-attribute="custId" name="customer-id" />
<xml-element java-attribute="picture" name="picture-hex">
<xml-schema-type name="hexBinary" />
<xml-java-type-adapter
value="example.adapters.MyHexConverter" />
</xml-element>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
You can use this file via JAXBContextProperties.OXM_METADATA_SOURCE property:
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, iStream);
JAXBContext ctx = JAXBContext.newInstance(new Class[] { Customer.class }, properties);
So if you want several different mappings for the same class, just write several XML bindings and create your JAXBContext with corresponding files. I think this is the best options right now, with MOXy
With pure JAXB RI you can write an own annotations reader. I did this once with Annox:
http://confluence.highsource.org/display/ANX/JAXB+User+Guide
Another option was JBoss JAXBIntroductions, also based on a custom annotations reader:
https://developer.jboss.org/wiki/JAXBIntroductions
But I'm not sure this is live anymore.
Since you want multiple mappings, you'll have to write them (all but one) manually. You can generate one set of mappings as annotations, but further mappings will have to be written manually. Or, let's say, I'm not aware of a plugin or tool which would generate, for instance, MOXy XML bindings. Wouldn't be a big problem to write one though.
You may also take a completely different approach. Instead of mapping one central model with different mappings/format, you can have map a separate package of DTOs onto these formats. And then convert between your DTOs and the central model. Something like
XML(1) <-> DTO(1)|<-\
XML(2) <-> DTO(2)|<--*->Model
XML(3) <-> DTO(3)|<-/
Thus you'll have clean DTOs per exchange format (which you can generate out of schemas) and a single central business model (to rule them all). You'll have to convert between DTOs and the Model, this can be handled with a tool like Dozer.
If this is a better approach or not depends on how complex your formats are and how different they are fron one another.
Concerning your questions:
1) There's nothing special about Eclipse, just add MOXy as dependency and follow the docs.
2) I've described a few options above.

See "Passing Customization Files to the JAXB Binding Compiler" here:
https://docs.oracle.com/javase/tutorial/jaxb/intro/custom.html
You could write a script to integrate into Eclipse. Or you could use a Maven or Ant task.
Your only options are annotations or XML bindings.

Related

MOXy DynamicEntity with JSON?

I'm trying to use DynamicEntity to unmarshal some simple JSON, and it's totally bombing on me. Docs are rather sparse, is it even possible to do this? I'm basically doing this;
JAXBContext jaxbContext = JAXBContext.newInstance(DynamicEntity.class);
DynamicEntity entity = (DynamicEntity) jaxbContext.createUnmarshaller().unmarshal(entityStream);
This is straight from the XML docs here: https://wiki.eclipse.org/EclipseLink/Examples/MOXy/Dynamic/XmlToDynamicEntity
And I get;
Caused by:
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
org.eclipse.persistence.dynamic.DynamicEntity is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at org.eclipse.persistence.dynamic.DynamicEntity
Has anyone managed to get this to work? I'm basically trying to avoid building POJOs since my backend store doesnt care about them anyway, I just want to deserialize to a generic object and pass it along. In .NET I'd just use dynamic but I'm pretty stumped on how to do this with Moxy.
In order to get DynamicEntity, it is neccessary to use DynamicJAXBContext. It can be configured using the following in jaxb.properties file:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory
or you can use DynamicJAXBContextFactory directly.
Although Dynamic MOXY does not require any java classes for the bindings (the POJOs), you need to provide binding metadata when creating the context. It can be XSD or binding.xml that describes the mapping. So instead of creating the context using JAXBContext.newInstance(DynamicEntity.class), you would need to use alternative methods - see links below.
See example here (using XSD):
https://wiki.eclipse.org/EclipseLink/Examples/MOXy/Dynamic/JAXBContextFromXMLSchema
or more complex example using binding.xml and also JSON:
https://wiki.eclipse.org/EclipseLink/Examples/MOXy/Dynamic/Flickr

How to manage several xml format with jaxb/moxy

I need to perform some calls to a backend not managed by me. The point is that they use different xml format to trasport the data. Even for the same call request and response are different: same data but different root tags.
At first I tried to map them with different beans using annotations (moxy jaxb), but the I had to manage to many of them and rhe cost of change was too high. Then I switched to xml file mapping: it seems better then previous choice, but still I have to manage lots of xml files (douzen).
Have you got any proposal in order to keep the project light and scalable?
Thanks in advance for the help.
One of the reasons we added the external mapping document in EclipseLink JAXB (MOXy) is to allow you to apply additional XML representations to your object model:
http://blog.bdoughan.com/2011/09/mapping-objects-to-multiple-xml-schemas.html
One thing to pay attention to is the xml-mapping-metadata-complete attribute on the root xml-bindings element. When this is set to true the XML document replaces all other mappings, and when it is false or not present it amends the metadata.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="blog.weather"
xml-mapping-metadata-complete="true">
Using the amend the metadata approach you can pass in multiple binding files to create the Context where subsequent mapping files can be used to progressively tweak the metadata.
Map<String, Object> properties = new HashMap<String, Object>(1);
List<String> bindingFiles = new ArrayList<String>(2);
bindingFiles.add("version2.xml");
bindingFiles.add("version3.xml");
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, bindingFiles);
JAXBContext jc = JAXBContext.newInstance(new Class[] {WeatherReport.class}, properties);

Serialize one object into several different xml

i have one question. What is the best way to serialize in java 1 object to few xml with different schema? For example we have this java bean:
class User {
String name;
String gender;
String age;
}
And i want to serialize it to first
<user>
<name>bobby</name>
<gender>male</gender>
<age>40</age>
</user>
second
<info>
<employer>
<data>
<name>bobby</name>
</data>
<meta>
<gender>male</gender>
<age>40</age>
</meta>
</employer>
</info>
and maybe another one xml. What you think?
You could refer to this answer. The JAXB lib generate the serialization xml file based on a .xsd file. And of course you can customize the .xsd file for your own purpose.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
Metadata Representation
Generally object-to-XML providers offer different ways of specifying metadata. Annotations is one way of specifying metadata and in all instances of seen annotations correspond to only one representation. So you need to look for a provider that offers an alternate approach such as an XML mapping document or programmatic metadata.
Path Based Mapping
Generally object-to-XML providers offer mapping through a 1-to-1 relationship between objects/properties and levels of nesting. To map to your second representation you need a provider that is able to do path based mapping.
MOXy offers both items that you are looking for. Below is a link to an example where a single object model is mapped to both the Google and Yahoo weather APIs:
http://blog.bdoughan.com/2011/09/mapping-objects-to-multiple-xml-schemas.html

Spring JAXB - Unmarshalling an XML document with schema validation

I am trying to work out how to unmarshall and XML document to a Java document.
The top of the xml document looks like this
<xs:myData xmlns:xs="http://www.example.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com example.xsd ">
There is a schema file whose top section looks like this:
<schema targetNamespace="http://www.example.com"
elementFormDefault="qualified"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xs="http://www.example.com">
I would like to unmarshall the xml document using Spring/JaxB and eventually convert it to a JPA object. I am not sure how to go about so i looked for examples on google and came up with this http://thoughtforge.net/610/marshalling-xml-with-spring-ws-and-jaxb/
I understand most of it except how or where the schema is used.
I have seen other examples where the schema is explicitly specified, i.e.
SchemaFactory schemaFac = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema sysConfigSchema = schemaFac.newSchema(
new File("example.xsd"));
unmarshaller.setSchema(sysConfigSchema);
RootElement root = (RootElement)unmarshaller.unmarshal(
new File("example1.xml"));
How is the schema shown in the first link used to validate the xml document?
Are there any disadvantages to using Spring's jaxb2Marshaller as opposed to direct use of JAXB?
What is the effect of having the namespace next to the XmlElement annotation? (See the Person class)
I would appreciate any more examples showing Spring/REST with unmarshalling with schema validation.
Thanks
As far as I know JAXB does not parse xsi attribute to dereference XSD, load it and use for validation. Perhaps that was done to disable automatic validation, otherwise it would be problematic to switch it off :)
Spring Jaxb2Marshaller was obviously added to implement the same interface org.springframework.oxm.Marshaller (which is implemented also by CastorMarshaller, JibxMarshaller, ...). It is very powerful and allows you to tune JAXBContext in very flexible way (I can't imagine the scenario when provided API is not enough). From pattern point of new Jaxb2Marshaller is a builder, so it does not add anything to core JAXB functionality. But there are some evident advantages. For example, schema loading is very simple. In the article the Spring context refers the person.xsd (<property name="schema" value="classpath:schema/person.xsd"/>) which one need to put into resources explicitly. Then JAXB marshaller/unmarshaller will use this schema to validate XML when XML is generated/loaded.
#XmlElement(..., namepsace="xxx") will automatically generate this XML element with a specified namespace. It's rare case if somebody does not use namespaces. I would say writing XSD without namespaces is not normal, as you want to avoid the element name collision.
Using JAXB with RestTemplate is very simple. You need to be sure that JAXB runtime is in your classpath (JDK 6 already has it) and your bean is annotated with #XmlRootElement. Then just use Person person = restTemplate.getForObject(restServiceUrl, Person.class),

Use Jakarta Digester or JAXB?

Given a scenario:
I have my own system's object structure. Now there are more than one XML sources I have to map to my java classes. And there is no need to convert Java object back into XML.
What's your suggestion for me to use Digester or JAXB? Currently I lean to use Digester, because I can specify XML path for each XML source to the same object method call, and Digester seems to be easier to maintain. Although JAXB has good design to marshal/unmarshal java and XML, but I think it is too complicated, xml schema is needed for each xml-java mapping, right?
I think both Digester or JAXB has their mission to fit different usage scenario, so need your advice to help me decide one of them. Thanks a lot.
I think you may have a skewed view of JAXB. It can be complicated, if you choose to make it so, but it can also be extremely simple. For example, you can bind an entire XML document onto an object graph with only a single annotation.
Also, the schema thing is a red herring. JAXB can generate java code from an XML Schema, but that's just a convenience for cases where you have a schema. If you don't, then ignore that part. You can annotate your class model by hand, it's very easy.
Digester, on the other hand, is harder to maintain (in my opinion), since you have to muck about with path expressions ion addition to your class model.
An advantage of JAXB is that it is a spec (JSR-222) with multiple implementations: Metro, EclipseLink MOXy, JaxMe. This avoids the problem of vendor lock in.
XPath Based Mapping
The EclipseLink JAXB (MOXy) has an extension to support XPath based mapping (I'm the tech lead).
package blog.geocode;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="kml")
#XmlType(propOrder={"country", "state", "city", "street", "postalCode"})
public class Address {
#XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:Thoroughfare/ns:ThoroughfareName/text()")
private String street;
#XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:LocalityName/text()")
private String city;
#XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:AdministrativeAreaName/text()")
private String state;
#XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:CountryNameCode/text()")
private String country;
#XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:PostalCode/ns:PostalCodeNumber/text()")
private String postalCode;
}
Multiple XML Sources
To apply multiple XML representations to an object model you can leverage MOXy's XML metadata. This is another extension to the JAXB standard. An example file looks like:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="blog.bindingfile">
<xml-schema
namespace="http://www.example.com/customer"
element-form-default="QUALIFIED"/>
<java-types>
<java-type name="Customer">
<xml-root-element/>
<xml-type prop-order="firstName lastName address phoneNumbers"/>
<java-attributes>
<xml-element java-attribute="firstName" name="first-name"/>
<xml-element java-attribute="lastName" name="last-name"/>
<xml-element java-attribute="phoneNumbers" name="phone-number"/>
</java-attributes>
</java-type>
<java-type name="PhoneNumber">
<java-attributes>
<xml-attribute java-attribute="type"/>
<xml-value java-attribute="number"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
For more information:
http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
http://bdoughan.blogspot.com/2010/12/extending-jaxb-representing-annotations.html
Maybe off topic: I've abandonded digester in favor of xstream. Maybe have a look

Categories

Resources