Full disclosure, I am not J2EE expert so my descriptions may be a bit off. However, using JAXB is just to powerful to ignore. The first part of this topic is pretty basic, while the second part is a bit more interesting.
When xml started to become an interesting format for data files and configuration files I didn’t really see the interest. It is a very verbose format that is a pain in the neck to parse through with your own code.
Of course when my colleague recommended to get with the program and use SAX to parse through these files I gave it a shot. For simple files it was ok for the complex formats it was indeed a pain.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Magazine> <Year>2016</Year> <Month>6</Month> <Title>Economist</Title> <Price>9.99</Price> </Magazine>
Sax is the simple API for XML which lets you evaluate various elements while parsing through the through XML documents. If you need to parse through the XML picking up information as you go it may be right for you. The SAX parser is just retrieving the data notifying you when interesting events occur.
SAX isn’t bad but it does have its limitations it isn’t just a case of programmer laziness. Not only that the limitations of SAX are not trivial.
- No random access to the structure
- The entire xml structure is not loaded
- You need to write your own code for storing the data
One of the other solutions that was developed to help with dealing with XML files is JAXB. JAXB stands for Java architecture for XML binding. This API is used to convert XML data to java objects and java objects to XML data.
The converting between XML and Java objects is done by marshaling and unmarshaling.
Name | Description |
---|---|
Marshal | The process of transforming the representation of an object in one format to another object format suitable for storage or processing. |
UnMarshal | The reverse process of converting the object format back into its original data format. |
However the marshaling/unmarshaling cannot be done without some providing some hints in our code. These hints are in the form of the following annotations.
Annotation | Description |
---|---|
@XmlRootElement(name=”name here”) | This defines the name of the root element of the XML file. |
@XmlElement (name=”name here”) | This defines the connection between the variable in the java class and the element name in the XML structure. |
@XmlAccessorType (XmlAccessType.FIELD) | When this annotation is used in this manner we don’t need to annotate the getter and setter methods for each field. |
@XmlElementWrapper (name= “name here”) | It generates a wrapper element around XML representation |
Simple Example
The first example is basically how to load a simple xml file into a java object.
The XML file looks like this.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Magazine> <Year>2016</Year> <Month>6</Month> <Title>Economist</Title> <Price>9.99</Price> </Magazine>
This is a rather silly example, what might be much more meaningful would be a xml configuration file that contains a lot of settings for some sort of interface or system.
The actual code below is actually more complex that you might see for loading the “magazine” object. The methods dump, load and save would probably be methods in your actual program and would not necessarily be in this class.
The annotation @XmlRootElement is what creates the “Magazine” opening and closing tags for the file while the @XmlElement annotations marks each field for our XML structure.
The only real work that does happen is indeed in the save and load methods. We create either a marshaller or unmarshaller depending on whether we are trying to get the values from an xml file (unmarshaller) or write out our java object into an xml file (marshaller)
There is really not a lot of code to review, we create a JAXB context and then create the necessary marshaller.
Computers don’t need all of that fancy formatting in order to parse through their data or source code for that matter. The formatting is done for the humans involved as it is easier to see a nicely formatted xml structure than the following.
<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?><Magazine><Year>2016</Year><Month>6</Month><Title>Economist</Title><Price>9.99</Price></Magazine>
JAXB provides for this case as well. If we simply tell our marshaller we want formatted output, the output will be formatted into the xml magazine structure with all of the indenting.
This is done by simply setting the JAXB_FORMATTED_OUTPUT property and is commented in the code.
The only method that isn’t so clearly defined is the dump method. To be honest, it is exactly like the save method but rather than writing the data to a file it is just sent to standard out / console.
package de.companyname.simple; /* * * example for writing a simple xml file * */ import java.io.File; @XmlRootElement(name="Magazine") @XmlAccessorType(XmlAccessType.FIELD) public class magazine { // Microsoft Exchange values @XmlElement(name="Year") private int year; @XmlElement(name="Month") private int month; @XmlElement(name="Title") private String title; @XmlElement(name="Price") private double price; public magazine() { } public magazine(int year, int month, String title, double price) { this.year = year; this.month = month; this.title = title; this.price = price; } public int getYear() { return year; } public void setYear(int value) { this.year= value; } public int getMonth() { return month; } public void setMonth(int value) { this.month= value; } public String getTitle() { return title; } public void setTitle(String value) { this.title = value; } public double getPrice() { return price; } public void setPrice(double value) { this.price = value; } public void dump() { JAXBContext jc = null; try { jc = JAXBContext.newInstance(magazine.class); } catch (JAXBException ex) { // TODO Auto-generated catch block ex.printStackTrace(); } Marshaller marshaller; try { marshaller = jc.createMarshaller(); // tell marshaller to format the data for humans marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(this, System.out); } catch (JAXBException ex) { // TODO Auto-generated catch block ex.printStackTrace(); } } public magazine load(String filename) { magazine loaded = new magazine(); JAXBContext jc = null; try { jc = JAXBContext.newInstance(magazine.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); File xml = new File(filename); loaded = (magazine) unmarshaller.unmarshal(xml); } catch (JAXBException ex) { // TODO Auto-generated catch block ex.printStackTrace(); } return loaded; } public void save(String filename) { JAXBContext jc = null; try { jc = JAXBContext.newInstance(magazine.class); } catch (JAXBException ex) { // TODO Auto-generated catch block ex.printStackTrace(); } Marshaller marshaller; try { marshaller = jc.createMarshaller(); // tell the marshaller to format the data for humans marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); OutputStream os = new FileOutputStream( filename ); marshaller.marshal( this, os ); os.close(); } catch (JAXBException ex) { // TODO Auto-generated catch block ex.printStackTrace(); } catch (FileNotFoundException ex) { // TODO Auto-generated catch block ex.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) throws Exception { magazine single = new magazine (); single.setTitle("Economist"); single.setPrice(9.99); single.setYear(2016); single.setMonth(6); single.dump(); single.save("first.xml"); magazine second = single.load("first.xml"); second.dump(); } }
This example is a very convenient way to have a simple xml file and load it into a java object. I actually do use this when creating small status files or configuration files but it really wasn’t what I was initially interested in.
What I was really interested in was the ability to load and save an indeterminate number of objects into an array. This allows me the flexibility to add one more of my object to the list and then write it out.
In Part II of JAXB, my example will be for this exact situation.
Note: The example was compiled with java 1.7.