JAXB marshal example
In this example we are going to show how to use the JAXB marshal functionalities. JAXB offers the possibility to convert Java objects into XML structures and vice versa, it comes with the JRE bundle since the first versions of the JRE 1.6.
As example, we are going to create a list of museums and store it in a specific XML file, each museum contains information like its name, about permanent and special exhibitions, city where is located, etc.
The java version used for these examples is the JRE 1.8.0 for 32b but only the usage of the LocalDate class is Java 8 specific; any 1.7 version can be used. The IDE used is Eclipse SDK Version: Luna (4.4) but the code should work in any other IDE supporting java.
So, here we go…
First of all we indicate JAXB what Java elements we want to store in our XML file
@XmlRootElement( name = "MUSEUM" ) public class Museum { String name; @XmlElement( name = "MUSEUM_NAME" ) public void setName( String name ) { this.name = name; } Boolean childrenAllowed; @XmlAttribute( name = "children_allowed" ) public void setChildrenAllowed( Boolean childrenAllowed ) { this.childrenAllowed = childrenAllowed; } ...
In the code shown above, we can see three JAXB annotations:
@XmlRootElement( name = "MUSEUM" )
: indicates the root node in the xml structure, the name is the name that will appear in the xml, if no name is specified, the class name will be used.@XmlElement( name = "MUSEUM_NAME" )
: indicates a child node.@XmlAttribute( name = "children_allowed" )
: indicates an attribute of the root node.
Next step is to marshal this object and generate the XML with the desired structure:
Museum simpleMuseum = new Museum(); simpleMuseum.setName( "Simple Museum" ); simpleMuseum.setCity( "Oviedo, Spain" ); JAXBContext jaxbContext = JAXBContext.newInstance( Museum.class ); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); jaxbMarshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true ); jaxbMarshaller.marshal( simpleMuseum, new File( "simple.xml" ) ); jaxbMarshaller.marshal( simpleMuseum, System.out );
The code is self explained and shows how a JAXB Marshaller can be used to generate an XML from a Java object. If the JAXB_FORMATTED_PROPERTY
is set to true, this indicates JAXB to generate an XML with a proper indentation. The marshal method uses an object and an output file where to store the generated XML as parameters.
The generated XML would be:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <MUSEUM children_allowed="false"> <MUSEUM_NAME>Simple Museum</MUSEUM_NAME> <CITY>Oviedo, Spain</CITY> </MUSEUM>
We now know how to generate an XML from a Java object, now we are going to show how to work with Lists of objects
How to store a list of museums:
Museum simpleMuseum = new Museum(); simpleMuseum.setName( "Simple Museum" ); simpleMuseum.setCity( "Oviedo, Spain" ); Museum anotherSimpleMuseum = new Museum(); anotherSimpleMuseum.setName( "Another Simple Museum" ); anotherSimpleMuseum.setCity( "Gijon, Spain" ); Museums listOfMuseums = new Museums(); listOfMuseums.add( simpleMuseum ); listOfMuseums.add( anotherSimpleMuseum ); JAXBContext jaxbContext = JAXBContext.newInstance( Museums.class ); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); jaxbMarshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true ); jaxbMarshaller.marshal( listOfMuseums, new File( "simple.xml" ) ); jaxbMarshaller.marshal( listOfMuseums, System.out );
It is important to notice that JAXB is not able to manage directly Lists as root element, so we need to create a new class with the list that we want to store in order to indicate JAXB what kind of XML structure it has to generate. In this example this class is called Museums and contains a List of Museum:
@XmlRootElement( name = "MUSEUMS" ) public class Museums { List<Museum> museums; @XmlElement( name = "MUSEUM" ) public void setMuseums( List<Museum> museums ) { this.museums = museums; } public void add( Museum museum ) { if( this.museums == null ) { this.museums = new ArrayList<Museum>(); } this.museums.add( museum ); ...
The generated XML would be:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <MUSEUMS> <MUSEUM> <MUSEUM_NAME>Simple Museum</MUSEUM_NAME> <CITY>Oviedo, Spain</CITY> </MUSEUM> <MUSEUM> <MUSEUM_NAME>Another Simple Museum</MUSEUM_NAME> <CITY>Gijon, Spain</CITY> </MUSEUM> </MUSEUMS>
Until now, we just generated XML that contained elements of the type String, so we are going to see what actions are needed in order to allow JAXB to store other types that are not configured per default. In Java 8, one of the new features is the new Date API; this API offers many new possibilities and enhances the old one. One of the new classes coming with this API is the java.time.LocalDate
. JAXB does not know how to manage this class, so we have to create an adapter in order to explain JAXB how to marshal and unmarshal it:
How to store complex Java types as children nodes using an adapter:
public class LocalDateAdapter extends XmlAdapter<String, LocalDate> { public LocalDate unmarshal( String v ) throws Exception { return LocalDate.parse( v ); } public String marshal( LocalDate v ) throws Exception { return v.toString(); } }
we just implement the marshal and unmarshal methods of the interface XmlAdapter with the proper types and results and afterwards, we indicate JAXB where to use it:
@XmlJavaTypeAdapter( LocalDateAdapter.class ) @XmlElement( name = "FROM" ) public void setFrom( LocalDate from ) { this.from = from; } ...
assuming that this.from is of the type LocalDate
.
The XML result would be:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <MUSEUM children_allowed="false"> <MUSEUM_NAME>Simple Museum</MUSEUM_NAME> <CITY>Oviedo, Spain</CITY> <PERMANENT_EXHIBITION> <NAME>one exhibition</NAME> <FROM>2014-01-01</FROM> </PERMANENT_EXHIBITION> </MUSEUM>
Summarizing, we know how to generate XML from Java objects, we know also how to use lists within these java objects and also as root element of the XML, we saw how to adapt complex types in order that JAXB can work with them and we also made as well.
The example bellow contains all the features explained in this article: A list of museums containing names, cities, permanent and special exhibitions with dates (using java 8 LocalDate) and list of artists in each exhibition is stored in an XML file.
Java main program:
public class MuseumJaxBExampleComplete { public static void main( String[] args ) { try { Museum reinaSofia = new Museum(); reinaSofia.setName( "Reina Sofia Museum" ); reinaSofia.setCity( "Madrid" ); Exhibition permanent = new Exhibition(); permanent.setName( "Permanent Exhibition - Reina Sofia Museum" ); permanent.setFrom( LocalDate.of( 1900, Month.JANUARY, 1 ) ); permanent.setTo( LocalDate.of( 2014, Month.DECEMBER, 31 ) ); List artistsReinaSofia = new ArrayList(); artistsReinaSofia.add( "Picasso" ); artistsReinaSofia.add( "Dali" ); artistsReinaSofia.add( "Miro" ); permanent.setArtists( artistsReinaSofia ); reinaSofia.setPermanent( permanent ); Museum prado = new Museum(); prado.setName( "Prado Museum" ); prado.setCity( "Madrid" ); Exhibition permanentPrado = new Exhibition(); permanentPrado.setName( "Permanent Exhibition - Prado Museum" ); permanentPrado.setFrom( LocalDate.of( 1500, Month.JANUARY, 1 ) ); permanentPrado.setTo( LocalDate.of( 2000, Month.DECEMBER, 31 ) ); List artistsPrado = new ArrayList(); artistsPrado.add( "Velazquez" ); artistsPrado.add( "Goya" ); artistsPrado.add( "Zurbaran" ); artistsPrado.add( "Tiziano" ); permanentPrado.setArtists( artistsPrado ); prado.setPermanent( permanentPrado ); Exhibition special = new Exhibition(); special.setName( "Game of Bowls (1908), by Henri Matisse" ); special.setFrom( LocalDate.of( 1908, Month.JANUARY, 1 ) ); special.setTo( LocalDate.of( 1908, Month.DECEMBER, 31 ) ); List artistsSpecial = new ArrayList(); artistsSpecial.add( "Mattise" ); special.setArtists( artistsSpecial ); prado.setSpecial( special ); Museums museums = new Museums(); museums.add( prado ); museums.add( reinaSofia ); JAXBContext jaxbContext = JAXBContext.newInstance( Museums.class ); Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); jaxbMarshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, true ); jaxbMarshaller.marshal( museums, new File( "museums.xml" ) ); jaxbMarshaller.marshal( museums, System.out ); } catch( JAXBException e ) { e.printStackTrace(); } } }
Generated XML:
<MUSEUMS> <MUSEUM> <MUSEUM_NAME>Prado Museum</MUSEUM_NAME> <CITY>Madrid</CITY> <PERMANENT_EXHIBITION> <NAME>Permanent Exhibition - Prado Museum</NAME> <ARTIST>Velazquez</ARTIST> <ARTIST>Goya</ARTIST> <ARTIST>Zurbaran</ARTIST> <ARTIST>Tiziano</ARTIST> <FROM>1500-01-01</FROM> <TO>2000-12-31</TO> </PERMANENT_EXHIBITION> <SPECIAL_EXHIBITION> <NAME>Game of Bowls (1908), by Henri Matisse</NAME> <ARTIST>Mattise</ARTIST> <FROM>1908-01-01</FROM> <TO>1908-12-31</TO> </SPECIAL_EXHIBITION> </MUSEUM> <MUSEUM> <MUSEUM_NAME>Reina Sofia Museum</MUSEUM_NAME> <CITY>Madrid</CITY> <PERMANENT_EXHIBITION> <NAME>Permanent Exhibition - Reina Sofia Museum</NAME> <ARTIST>Picasso</ARTIST> <ARTIST>Dali</ARTIST> <ARTIST>Miro</ARTIST> <FROM>1900-01-01</FROM> <TO>2014-12-31</TO> </PERMANENT_EXHIBITION> </MUSEUM> </MUSEUMS>
So that is all about marshaling Java objects into XML. JAXB contains other annotations that we did not touch in this article, for an overview of all possible JAXB annotations please go to: http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/package-summary.html
JAXB also provides the option to use XML schema definitions (XSD) in order to generate the Java classes that are going to be marshaled and unmarshaled afterwards, since this is very useful in cases like interfaces between backend systems, message queuing and others, we did not show it in this article because it would have complicated things too much.
You can find all the code used in this article with a lot of comments and explanations and some extra features in the following compressed file: museums_jaxb