In this article, we will learn and implement JAXB (Java Architecture for XML Binding) which converts XML to Java objects and vice-versa i.e.; Java objects to XML on the fly. The specific terms used for the above conversion is
- Un-marshalling (XML –> Java objects)
- Marshalling (Java objects –> XML)
Previously, developers has to implement parsing techniques like SAX, DOM, etc to accomplish above task. But with the introduction of JAXB, developers task is one cut-off and they can allocate more time on business implementation
Nowadays, JAXB are most widely used in the implementation of Web Services as data exchanged here are in the form XML which needs to be converted into objects at the server end (and vice-versa)
Let us see few definitions and later we will implement a basic example to illustrate JAXB marshalling & un-marshalling
Technology Used
- Java 1.7
- Eclipse Luna IDE
- Apache Maven 3.2.1
JAXB
- JAXB stands for Java Architecture for XML Binding
- It’s a JSR 222 specification see here
- JAXB provides rich API to convert XML to Java objects & vice-versa
- The main advantage of using JAXB API for reading/processing XML documents is that, we don’t need to aware of any parsing techniques. (unlike SAX, DOM)
XML Schema (XSD)
- XSD stands for XML Schema Definition
- XSD describes the structure of XML document
- Basically XSD describes the syntax/rules for XML document
- XSD’s aren’t mandatory to have with respect to JAXB. But, if we have it will be useful for XML validation before marshalling/un-marshalling
Maven-zing JAXB
- It is always preferred to mavenize your JEE or Java framework projects
- It helps in resolving your dependencies & creates a deployable jar/war/ear
- If you are using JDK 1.7, then there is no need to add any extra libraries as dependency in pom.xml as JAXB 2.0 comes shipped with JDK 7.0
- But, with maven you can add your desired plugins/dependencies
- Note: if you are using JDK version less than 6, then you can download jaxb-impl.jar and include library into project classpath
- Or else, you can add these dependencies in your pom.xml as below
<dependencies> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>${jaxb.impl.version}</version> </dependency> </dependencies>
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | < project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" < modelVersion >4.0.0</ modelVersion > < groupId >in.bench.resources</ groupId > < artifactId >JAXB</ artifactId > < packaging >jar</ packaging > < version >1.0-SNAPSHOT</ version > < name >JAXB Maven jar</ name > < properties > < jaxb.impl.version >2.2.7-b53</ jaxb.impl.version > < compileSource >1.7</ compileSource > < project.build.sourceEncoding >UTF-8</ project.build.sourceEncoding > < maven.compiler.target >1.7</ maven.compiler.target > < maven.compiler.source >1.7</ maven.compiler.source > </ properties > < build > < finalName >JAXB</ finalName > < plugins > <!-- plugin - maven compiler plugin --> < plugin > < groupId >org.apache.maven.plugins</ groupId > < artifactId >maven-compiler-plugin</ artifactId > < configuration > < source >1.7</ source > < target >1.7</ target > </ configuration > </ plugin > <!-- plugin - maven jaxb goal - generate java objects from XSD --> < plugin > < groupId >org.codehaus.mojo</ groupId > < artifactId >jaxb2-maven-plugin</ artifactId > < version >1.5</ version > < executions > < execution > < goals > < goal >xjc</ goal > </ goals > < configuration > <!-- <packageName>my.jaxb.data</packageName> --> < outputDirectory >${basedir}/generated/java/source</ outputDirectory > < schemaDirectory >${basedir}/src/main/resources/entities</ schemaDirectory > < schemaFiles >*.xsd</ schemaFiles > < schemaLanguage >XMLSCHEMA</ schemaLanguage > < extension >true</ extension > < args > < arg >-XtoString</ arg > </ args > < plugins > < plugin > < groupId >org.jvnet.jaxb2_commons</ groupId > < artifactId >jaxb2-basics</ artifactId > < version >0.6.4</ version > </ plugin > </ plugins > </ configuration > </ execution > </ executions > </ plugin > </ plugins > </ build > <!-- <dependencies> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>${jaxb.impl.version}</version> </dependency> </dependencies> --> </ project > |
Generating POJO’s from XSD using maven plugins
JAXB – Generating java source files from XSD
Steps to generate java-sources from XML Schema Definition (XSD)
- configure JAXB Maven plugin in pom.xml
- write well-defined XSD for your service
- use maven command “mvn generate-sources” to generate java source files
Note: Its not a mandate, well if one wish to write supporting POJOs with JAXB annotation. Also, be careful while designing XSD
Configure JAXB Maven plugin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <!-- plugin - maven jaxb goal - generate java objects from XSD --> < plugin > < groupId >org.codehaus.mojo</ groupId > < artifactId >jaxb2-maven-plugin</ artifactId > < version >1.5</ version > < executions > < execution > < goals > < goal >xjc</ goal > </ goals > < configuration > <!-- <packageName>my.jaxb.data</packageName> --> < outputDirectory >${basedir}/generated/java/source</ outputDirectory > < schemaDirectory >${basedir}/src/main/resources/entities</ schemaDirectory > < schemaFiles >*.xsd</ schemaFiles > < schemaLanguage >XMLSCHEMA</ schemaLanguage > < extension >true</ extension > < args > < arg >-XtoString</ arg > </ args > < plugins > < plugin > < groupId >org.jvnet.jaxb2_commons</ groupId > < artifactId >jaxb2-basics</ artifactId > < version >0.6.4</ version > </ plugin > </ plugins > </ configuration > </ execution > </ executions > </ plugin > |
Music.xsd
Below XSD contains two elements with name “Movies” and “Music”
- Movies element has four attributes namely movieName, year, director, comments
- Music elements has three attributes with two simple type & one complex type which refers above declared movies element using ref attribute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <? xml version = "1.0" encoding = "UTF-8" ?> targetNamespace = "http://benchresources.in/entities/music" xmlns:tns = "http://benchresources.in/entities/music" elementFormDefault = "qualified" > < xsd:element name = "music" > < xsd:complexType > < xsd:sequence > < xsd:element name = "composer" type = "xsd:string" /> < xsd:element name = "languages" type = "xsd:string" /> < xsd:element ref = "tns:movies" /> </ xsd:sequence > </ xsd:complexType > </ xsd:element > < xsd:element name = "movies" > < xsd:complexType > < xsd:sequence > < xsd:element name = "movie" maxOccurs = "unbounded" > < xsd:complexType > < xsd:sequence > < xsd:element name = "movieName" type = "xsd:string" /> < xsd:element name = "year" type = "xsd:string" /> < xsd:element name = "director" type = "xsd:string" /> < xsd:element name = "comments" type = "xsd:string" /> </ xsd:sequence > </ xsd:complexType > </ xsd:element > </ xsd:sequence > </ xsd:complexType > </ xsd:element > </ xsd:schema > |
Run mvn generate-sources
Look at the generated java source files in the generated folder and also view console statements while JAXB generating classes using source XSD
Music.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | package in.benchresources.entities.music; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; @XmlAccessorType (XmlAccessType.FIELD) @XmlType (name = "" , propOrder = { "composer" , "languages" , "movies" }) @XmlRootElement (name = "music" ) public class Music { @XmlElement (required = true ) protected String composer; @XmlElement (required = true ) protected String languages; @XmlElement (required = true ) protected Movies movies; public String getComposer() { return composer; } public void setComposer(String value) { this .composer = value; } public String getLanguages() { return languages; } public void setLanguages(String value) { this .languages = value; } public Movies getMovies() { return movies; } public void setMovies(Movies value) { this .movies = value; } } |
Movies.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | package in.benchresources.entities.music; import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; @XmlAccessorType (XmlAccessType.FIELD) @XmlType (name = "" , propOrder = { "movie" }) @XmlRootElement (name = "movies" ) public class Movies { @XmlElement (required = true ) protected List<Movies.Movie> movie; public List<Movies.Movie> getMovie() { if (movie == null ) { movie = new ArrayList<Movies.Movie>(); } return this .movie; } @XmlAccessorType (XmlAccessType.FIELD) @XmlType (name = "" , propOrder = { "movieName" , "year" , "director" , "comments" }) public static class Movie { @XmlElement (required = true ) protected String movieName; @XmlElement (required = true ) protected String year; @XmlElement (required = true ) protected String director; @XmlElement (required = true ) protected String comments; public String getMovieName() { return movieName; } public void setMovieName(String value) { this .movieName = value; } public String getYear() { return year; } public void setYear(String value) { this .year = value; } public String getDirector() { return director; } public void setDirector(String value) { this .director = value; } public String getComments() { return comments; } public void setComments(String value) { this .comments = value; } } } |
Directory Structure
Before moving on, let us understand the directory/package structure once you create project in Eclipse IDE
Maven has to follow certain directory structure
- src/test/java –> test related files, mostly JUnit test cases
- src/main/java –> create java source files under this folder
- src/main/resources –> all configuration files placed here
- generated/java/source –> generated java source files are placed here
- Maven Dependencies or Referenced Libraries –> includes jars in the classpath
- WEB-INF under webapp –> stores web.xml & other configuration files related to web application
Project Structure (Package Explorer view in Eclipse)
Let’s see coding in action
Marshalling & Un-marshalling
Un-marshalling: Converts XML documents to corresponding Java objects
Marshalling: Converts Java objects to XML
Un-marshalling program
This class generates Java objects from input file “Music.xml”. Also, sets XSD to validate the input XML before un-marshalling. There are other validation mechanism to do same like using javax.xml.validation.Validator class
Note: programs has some commented lines, which can be used as alternative approach to get values from input xml
JAXBUnMarshaller.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | package in.mycompany.entities.music; import in.benchresources.entities.music.Movies; import in.benchresources.entities.music.Movies.Movie; import in.benchresources.entities.music.Music; import java.io.File; import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; public class JAXBUnMarshaller { public static void main(String[] args) { createJavaObject(); } public static void createJavaObject(){ JAXBContext jaxbContext = null ; Unmarshaller unmarshaller = null ; File file = new File( "src\\main\\resources\\sourcexml\\Music.xml" ); try { // validation SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = schemaFactory.newSchema( new File( "src\\main\\resources\\entities\\Music.xsd" )); // create JAXB context jaxbContext = JAXBContext.newInstance(Music. class ); //"in.mycompany.entities.music" // initializing unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); // validate here against XSD unmarshaller.setSchema(schema); // creates Java Objects from XML file /*JAXBElement<?> muzix = (JAXBElement<?>) unmarshaller.unmarshal(file); MusicType musicType = (MusicType) muzix.getValue();*/ Music musicType = (Music) unmarshaller.unmarshal(file); System.out.println( " Composer :- " + musicType.getComposer()); System.out.println( " Languages :- " + musicType.getLanguages()); Movies movies = musicType.getMovies(); for (Movie movie : movies.getMovie()){ System.out.println( " \tMovie Name :- " + movie.getMovieName()); System.out.println( " \tYear :- " + movie.getYear()); System.out.println( " \tDirector :- " + movie.getDirector()); System.out.println( " \tComments :- " + movie.getComments() + "\n" ); } } catch (Exception ex) { ex.printStackTrace(); } finally { // release resources, if any } } } |
Output in console
Composer :- AR Rahman Languages :- English, Hindi, Tamil Movie Name :- Roja Year :- 1992 Director :- Mani Ratnam Comments :- Indian National Award Movie Name :- Alaipayuthey Year :- 2000 Director :- Mani Ratnam Comments :- Tamil Filmfare Award Movie Name :- Slumdog Millionaire Year :- 2008 Director :- Danny Boyle Comments :- Oscar, Bafta, Grammy, Golden Globe Award Movie Name :- Raanjhanaa Year :- 2013 Director :- Anand Rai Comments :- Topping musiz charts
Marshalling program
This class creates(generates/outputs) XML from Java objects defined in the class. With XSD set in the SchemaFactory, it checks for correctness and validates the XML before marshalling
Note: Some lines are commented out, which is an alternative approach
JAXBMarshaller.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | package in.mycompany.entities.music; import in.benchresources.entities.music.Movies; import in.benchresources.entities.music.Movies.Movie; import in.benchresources.entities.music.Music; import java.io.File; import java.util.List; import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; public class JAXBMarshaller { public static void main(String[] args) { createXML(); } public static void createXML(){ JAXBContext jaxbContext = null ; Marshaller marshaller = null ; try { // validation SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); Schema schema = schemaFactory.newSchema( new File( "src\\main\\resources\\entities\\Music.xsd" )); jaxbContext = JAXBContext.newInstance(Music. class ); marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); File file = new File( "src\\main\\resources\\marshalledxml\\Music.xml" ); // validate here against XSD marshaller.setSchema(schema); marshaller.marshal(JAXBMarshaller.createJavaObject(), file); marshaller.marshal(JAXBMarshaller.createJavaObject(), System.out); // create an element for marshalling //JAXBElement<MusicType> element = (new ObjectFactory()).createMusic(createJavaObject()); // create a Marshaller and marshal to System.out //JAXB.marshal(element, new FileOutputStream(new File("Muzix.xml"))); } catch (Exception ex){ ex.printStackTrace(); } finally { // release resources, if any } } public static Music createJavaObject(){ Movies movies = new Movies(); List<Movies.Movie> mvLst = movies.getMovie(); Movie movie1 = new Movie(); movie1.setMovieName( "Omkara" ); movie1.setYear( "2006" ); movie1.setDirector( "Vishal Bhardwaj" ); movie1.setComments( "National Award - Special Jury" ); Movie movie2 = new Movie(); movie2.setMovieName( "Ishqiya" ); movie2.setYear( "2010" ); movie2.setDirector( "Vishal Bhardwaj" ); movie2.setComments( "National Award" ); mvLst.add(movie1); mvLst.add(movie2); Music music = new Music(); music.setComposer( "Vishal Bhardwaj" ); music.setLanguages( "Hindi" ); music.setMovies(movies); return music; } } |
Output in console
Vishal Bhardwaj Hindi Omkara 2006 Vishal Bhardwaj National Award - Special Jury Ishqiya 2010 Vishal Bhardwaj National Award
Marshalled xml file (src\main\resources\marshalledxml\Musix.xml)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?> < composer >Vishal Bhardwaj</ composer > < languages >Hindi</ languages > < movies > < movie > < movieName >Omkara</ movieName > < year >2006</ year > < director >Vishal Bhardwaj</ director > < comments >National Award - Special Jury</ comments > </ movie > < movie > < movieName >Ishqiya</ movieName > < year >2010</ year > < director >Vishal Bhardwaj</ director > < comments >National Award</ comments > </ movie > </ movies > </ music > |
Conclusion: SOAP web service approaches like Top-down & Bottom-up uses JAXB for conversion of XML to Java objects and vice-versa for their data exchange with external client
Download project
JAXB - A XML Parsing technique (19kB)
Happy Coding !!
Happy Learning !!