More on XML serialization with JAXB

I posted some days ago an article explaining how to “XML-serialize” objects with JAXB in Eclipse. The downside of using XSD for XML serialization is the dependency on the XML schema that will generate java classes; this is because I wanted to extend the classes to have extra-functionality, more constructors and so on. So I started looking for a way to serialize objects to XML without creating XSD definitions… but I found a problem: every time java classes are generated, an additional class, called ObjectFactory.java is also created. It is also needed for XML marshalling/unmarshalling. The only viable solution I found was to write my one ObjectFactory.java class, to be used by JAXB when serializing objects.

Step 1: Create the java classes that you need. In my case, I had two main entities, Node and Line, and two additional collections, Lines and Nodes. I also created a Graph entity, holding a list with nodes and a list with lines. Below are presented Line.java, Lines.java and Graph.java files

Line.java

package drawgraph.objects;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Line", propOrder = { "startNode", "endNode" })
public class Line {

    @XmlAttribute(name = "StartNode")
    protected int startNode;
    @XmlAttribute(name = "EndNode")
    protected int endNode;

    public Line(int start, int end) {
        this.setStartNode(start);
        this.setEndNode(end);
    }
    
    public Line() {
        this(0, 0);
    }
    
    public int getStartNode() {
        return startNode;
    }

    public void setStartNode(int value) {
        this.startNode = value;
    }

    public int getEndNode() {
        return endNode;
    }

    public void setEndNode(int value) {
        this.endNode = value;
    }

}

Lines.java

package drawgraph.objects;

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "lines", propOrder = { "lines" })
public class Lines {

    @XmlElement(name = "Line")
    protected List<Line> lines;

    public List<Line> getLines() {
        if (lines == null) {
            lines = new ArrayList<Line>();
        }
        return this.lines;
    }
}

Graph.java

package drawgraph.objects;

import java.io.*;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Graph")
public class Graph {

    @XmlElement(name = "Nodes", required = true)
    protected Nodes nodes = new Nodes();
    @XmlElement(name = "Lines", required = true)
    protected Lines lines = new Lines();
    @XmlAttribute(name = "StartNode")
    protected int startNode;
    @XmlAttribute(name = "EndNode")
    protected int endNode;
    
    public void addNode(int x, int y) {
        getNodes().add(new Node(x, y, getNodes().size() + 1));
    }

    public void addLine(int start, int end) {
        getLines().add(new Line(start, end));
    }
    
    public List<Node> getNodes() {
        return nodes.getNodes();
    }

    public void setNodes(Nodes value) {
        this.nodes = value;
    }

    public List<Line> getLines() {
        return lines.getLines();
    }

    public void setLines(Lines value) {
        this.lines = value;
    }

    public int getStartNode() {
        return startNode;
    }

    public void setStartNode(int value) {
        this.startNode = value;
    }

    public int getEndNode() {
        return endNode;
    }

    public void setEndNode(int value) {
        this.endNode = value;
    }
    
    public void marshalToFile(String fileName) {
        try {
            JAXBContext jc = JAXBContext.newInstance(this.getClass().getPackage().getName());
            Marshaller m = jc.createMarshaller();
            m.marshal( this, new FileOutputStream(fileName) );
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    public static Graph unmarshalFromFile(String fileName) {
        try {
            JAXBContext jc = JAXBContext.newInstance((new Graph()).getClass().getPackage().getName());
            Unmarshaller um = jc.createUnmarshaller();
            return (Graph) um.unmarshal(new File(fileName));
        } catch (Exception e) {
            return new Graph();
        }
    }
    

}

In order to be able to serialize the above classes, we must use the XML annotations like @XmlRootElement, @XmlElement, @XmlAttribute, @XmlType. For the serialization, we use the same JAXBContext, Marshaller and Unmarshaller classes.

Step 2: Implement the ObjectFactory.java class

package drawgraph.objects;

import javax.xml.bind.annotation.XmlRegistry;

@XmlRegistry
public class ObjectFactory {

    public ObjectFactory() {
    }

    public Graph createGraph() {
        return new Graph();
    }

    public Node createNode() {
        return new Node();
    }

    public Line createLine() {
        return new Line();
    }

}

As you can see, the class must be preceded by @XmlRegistry annotation.

Step 3: Test the serialization

package drawgraph.objects;

import org.junit.*;
import static org.junit.Assert.*;

public class GraphTest {

    Graph graph;
    
    @Test
    public void test_graph()
    {
        createGraph();
        graph.marshalToFile("newGraphOutput.xml");
        Graph secondGraph = Graph.unmarshalFromFile("newGraphOutput.xml");
        assertTrue(secondGraph.getLines().size() == 2);
        assertTrue(secondGraph.getNodes().size() == 3);
    }
    
    private void createGraph()
    {
        graph = new Graph();
        graph.addNode(60, 60);
        graph.addNode(110, 110);
        graph.addNode(60, 110);
        graph.addLine(1, 3);
        graph.addLine(2, 3);
    }
}

Step 4: Check the result

01MoreXmlJaxbFileOutput

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: