Data representation is a core component of communication between enterprise applications. There are a number of formats for data exchange - XML, CSV, JSON, proprietary to name a few. XML is a common format when working with web services and is also fundamental to SOA. Working with XML in Java applications often requires transformation between Java objects and XML documents. There are many
open source tools (JAXB, XMLBeans, Xstreme, JiBX, Zeus, etc.) to achieve this transformation . This post explores JAXB. JAXB API is part of J2SE 1.6,
Convert XML Document into Java Objects (Unmarshal)Converting a XML document into Java objects is a common use case. XML document that is being transformed to Java objects is required to have a XML Schema to produce bindings. Following steps will achieve the transformation . As you go through these steps you will notice use of auto generated classes to get XML data, you do not have to write XML parsing code using DOM or SAX. In some cases your application may already have predefined domain classes which closely match the XML schema representation or somewhat match XML representation and you may not not like using of auto generated classes, for these cases there are ways to minimize use of auto generated classes, using some mapping libraries or using JAXB Customizations.
- Step 1: At compile time, use XML Schema associated with XML document and JAXB tool auto generate Java classes, this is called binding (Tool lets you specify a package name and generates java Interface and Implementation source file and an ObjectFactory class which provides methods to create generated types.
Use following command..(for generating code using Maven scroll down)
jdk\bin\xjc.exe -p com.mypkgname appscheama.xsd
INPUT Schema
I have used following XML Schema to model NFL scores
xml version="1.0" encoding="UTF-8"?>
xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/SportsSchema"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:nfl="http://www.example.org/SportsSchema"
elementFormDefault="qualified">
<xs:complexType name="TeamType">
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="location" type="xs:string" />
<!--xs:complexType>
<xs:complexType name="FootballScoreType">
<xs:sequence>
<xs:element name="firstTeam" type="nfl:TeamType" />
<xs:element name="secondTeam" type="nfl:TeamType" />
<xs:element name="firstTeamPoints" type="xs:int" />
<xs:element name="secondTeamPoints" type="xs:int" />
<!--xs:sequence
<!--xs:complexType>
<xs:element name="scores">
<xs:complexType>
<xs:sequence>
<xs:element name="score" type="nfl:FootballScoreType" maxOccurs="unbounded" />
<!--xs:sequence>
<!--xs:complexType>
<!--xs:element>
</schema>
AUTO GENERATED CODE
Upon running the xjc tool, various Java classes representing XML schema are generated. Following is an example of generated for one of the element in schema. Notice the annotations on Java classes, this what make the binding work. Generated code also a ObjectFactory which is used to create instances of various auto generated types.
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.0.2-b01-fcs
// See xml/jaxb">http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2010.01.08 at 02:37:52 PM EST
//
package com.spag.dataxchange.generated;
import java.math.BigInteger;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;import javax.xml.bind.annotation.XmlType;
/**
*
Java class for FootballScoreType complex type. *
* <p>The following schema fragment specifies the expected content contained within this class.
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "FootballScoreType", propOrder = { "firstTeam", "secondTeam", "firstTeamPoints", "secondTeamPoints"})
public class FootballScoreType {
@XmlElement(required = true)
protected TeamType firstTeam;
@XmlElement(required = true)
protected TeamType secondTeam;
@XmlElement(required = true)
protected BigInteger firstTeamPoints;
@XmlElement(required = true)
protected BigInteger secondTeamPoints;
public TeamType getFirstTeam() {return firstTeam;}
public void setFirstTeam(TeamType value) {this.firstTeam = value;}
public TeamType getSecondTeam() {return secondTeam;}
public void setSecondTeam(TeamType value) {this.secondTeam = value;}
public BigInteger getFirstTeamPoints() { return firstTeamPoints; }
public void setFirstTeamPoints(BigInteger value) {this.firstTeamPoints = value;}
public BigInteger getSecondTeamPoints() {return secondTeamPoints;}
public void setSecondTeamPoints(BigInteger value) {this.secondTeamPoints = value;}
}
Step 2: Now that we jave java XML bindings in place. We can use these classes to convert XML document into Java objects, aka unmarshaling. Unmarshaling is performed using JAXB API and auto generated classes from step 1. Following is sample code.
package com.spag.dataxchange;
import java.io.File;
import java.util.Iterator;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.Validator;
import com.spag.dataxchange.generated.*;
public class ScoreReader {
public static void main(String [] args) {
try {
JAXBContext jaxbCtx = JAXBContext.newInstance("com.spag.dataxchange.generated") ;
Unmarshaller reader = jaxbCtx.createUnmarshaller();
Scores obj = (Scores)reader.unmarshal(new File("src/main/resources/data/scores.xml"));
List list = obj.getScore();
Iterator iter = list.iterator();
int i = 0;
while(iter.hasNext()) {
i++;
FootballScoreType score = iter.next();
System.out.println("Game " + i );
System.out.println( score.getFirstTeam().getLocation() + " - " + score.getFirstTeam().getName() + ": " + score.getFirstTeamPoints());
System.out.println( score.getSecondTeam().getLocation() + " - " + score.getSecondTeam().getName() + ": " + score.getSecondTeamPoints());
}
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Consider the scenario where we already have domain classes defined, the challenge here is to either map the auto generated to classes to domain classes or to eliminate use of auto generated classes and go straight to domain classes. One way to eliminate/reduce use of auto generated classes is to use JAXB Customization. JAXB Customization tags lets you map XML schema to classes of your liking. Customizations can be specified inline with XML Schema code, however in most cases you won't be entitled to modifying the schema of XML document that being published by other application, that too referencing domain classes specific to your application. Thanks goodness customizations can be specified in external binding file (binding.xjb).
bindings.xjb allows you to map existing classes to domain classes, when invoking the xjc comipler specify the binding file that is being used. Binding customizations can be done at various xml schema element to class mapping,
<jxb:bindings version="2.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="GolfSchema.xsd" node="/xs:schema" >
<jxb:bindings node="//xs:complexType[@name='golfRound']">
<jxb:class ref="com.spag.dataxchange.golf.GolfRound"/>
<!--jxb:bindings>
<jxb:bindings node="//xs:complexType[@name='golfer']">
<jxb:class ref="com.spag.dataxchange.golf.Golfer"/>
<!--jxb:bindings>
<!--jxb:bindings>
<!--jxb:bindings>
Binding file could get unwieldy, there are other options to map auto generated class objects to domain class objects. Dozer is such a library that provides mapping from one JavaBean to other. This library could be utilized to convert between auto generated JAXB classes and your domain model.
Maven configuration for working with JAXB, including use of mapping files.
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2</version>
</dependency>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>1</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources</outputDirectory>
src/main/resources/schema/nfl
<schemaFiles>SportsSchema.xsd</schemaFiles>
<packageName>com.spag.dataxchange.generated</packageName> <!-- The name of your generated source package -->
</configuration>
</execution>
<execution>
<id>2</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<clearOutputDir>false</clearOutputDir>
<outputDirectory>${project.build.directory}/generated-sources</outputDirectory>
src/main/resources/schema/golf
<schemaFiles>GolfSchema.xsd</schemaFiles>
<packageName>com.spag.dataxchange.golf</packageName> <!-- The name of your generated source package -->
src/main/resources/schema/golf
<bindingFiles>bindings.xjb</bindingFiles>
</configuration>
</execution>
</executions>
</plugin>
Convert Java Objects into XML document (Marshal)
To convert Java object into XML document, JAXB has schemagen tool which lets you create a Schema from your domain classes. Using Objects instances, generated XML schema and JAXB API you could generate the XML document easily. Here are some code snippets and maven configurations to ease your development.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<goals>
<goal>schemagen</goal>
</goals>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.directory}/generated-schema</outputDirectory>
<includes>
<include>com/spag/dataxchange/golf/*.java</include>
</includes> <!-- The name of your generated source package -->
</configuration>
</plugin>
Further PonderingJAXB is primarily used in webservices developed using existing Java classes.
What happens when the the schema changes / domain model changes ?
Explore of JAXB annotations.
Java to XML(WSDL)nges ?
Ref: https://jaxb.dev.java.net/tutorial/
http://blogs.sun.com/CoreJavaTechTips/entry/exchanging_data_with_xml_and1