Page 1 of 1

Serializing/Deserializing objects as XML?

Posted: Sat Feb 09, 2008 3:23 pm
by paradoxoff
Hi,
I am working on an JFreeChart based charting app. One of the final things that are missing is a templating mechanism that allows users to apply predefined formats to a chart.
For that purpose I need to serialize and deserialize Color,Font,Stroke,Shape etc. objects.
I have discovered the class inside the org.jfree.xml.* packages that already seemd to do most of what I needed.
So far I have succeeded in serializing and deserializing some objects but I can´t get really my mind around these. After a lot of experimentation and head scratching I came up with the following test case:

Code: Select all

import java.io.*;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import org.jfree.xml.writer.*;
import org.jfree.xml.parser.*;
import org.jfree.xml.util.*;
import org.jfree.xml.parser.coretypes.*;
import org.jfree.xml.*;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

public class JFreeXMLDemo{
	public static void main(String[] args){
		try{
			FileWriter writer = new FileWriter("freexmltest.xml");
			ConfigXmlWriteHandler configwriter = new ConfigXmlWriteHandler();
			XMLWriter xmlwriter = new XMLWriter(writer);
			xmlwriter.writeTag(writer,"root");
			configwriter.write("stroke", new BasicStroke(3.0f),BasicStroke.class,xmlwriter);
			configwriter.write("color", new Color(255,128,0),Color.class,xmlwriter);
			configwriter.write("shape", new Rectangle2D.Double(30,30,10,10),Rectangle2D.class,xmlwriter);
			xmlwriter.writeCloseTag(writer,"root");
			xmlwriter.close();
			Drawer drawer = new Drawer(new Rectangle2D.Double(10,10,100,100),Color.BLUE); 
			ConfigXmlReadHandler configreader = new ConfigXmlReadHandler(drawer);
			XMLReader reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
			System.out.println("ConfigXmlReadHandler --> "+configreader);
			reader.setContentHandler(configreader);
			try{
				InputStream is = new FileInputStream("freexmltest.xml");
				System.out.println("InputStream --> "+is);
				InputSource source = new InputSource(is);
				System.out.println("InputSource --> "+source);
				reader.parse(source);
				JFrame frame = new JFrame("JFree XML Demo");
				frame.getContentPane().add(drawer);
				frame.pack();
				frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
				frame.setVisible(true);
			}
			catch(ParseException pe){
				System.out.println("Error on parsing! "+pe.getClass().getName()+", "+pe.getMessage());
			}
			catch(NullPointerException npe){
				System.out.println("Error on parsing! "+npe.getClass().getName()+", "+npe.getMessage());
			}
		}
		catch(Exception e){
			System.out.println("Error##! "+e.getClass().getName()+", "+e.getMessage());
		}
	}
}
class ConfigXmlWriteHandler extends RootXmlWriteHandler{
	ObjectFactory of = new SimpleObjectFactory();
	ConfigXmlWriteHandler(){
		super();
	}
	public ObjectFactory getFactoryLoader(){
		return this.of;
	}
}
class MyXmlReadHandler extends AbstractXmlReadHandler{
	private XmlReadHandler handler;
	MyXmlReadHandler(){
		super();
	}
	public Object getObject(){
		try{
			if(handler != null){
				return handler.getObject();
			}
			else return new String("No object definition for MyXmlReadHandler");
		}
		catch(XmlReaderException e){
			return new String("Error in handler.getObject(): "+e.getClass().getName()+", "+e.getMessage());
		}
	}
    protected XmlReadHandler getHandlerForChild(final String tagName, final Attributes atts)
        throws XmlReaderException, SAXException {
        if(tagName.equals("color")){
	        ColorReadHandler colorhandler = new ColorReadHandler();
	        this.handler = colorhandler;
	        return colorhandler;
        }
        
        else {
        	this.handler = null;
        	return null;	
        }		
    }
}
class ConfigXmlReadHandler extends RootXmlReadHandler{
	ObjectFactory of = new SimpleObjectFactory();
	private Drawer d;
	ConfigXmlReadHandler(Drawer d){
		super();
		this.d = d;
		XmlReadHandler roothandler = new MyXmlReadHandler();
		setRootHandler(roothandler);
	}
	public FrontendDefaultHandler newInstance(){
		return this;
	}
	public ObjectFactory getFactoryLoader(){
		return this.of;
	}
	public void characters(char[] ch, int start, int length){
	}
	public void startElement(String uri,String localeName,String qName,Attributes attributes){
		try{
			System.out.println("[ConfigXmlReadHandler.startElement] begin");
			try{
				super.startElement(uri,localeName,qName,attributes);
			}
			catch(NullPointerException npe){
				System.out.println("[ConfigXmlReadHandler.startElement] NullPointerException in RootXmlReadHandler.startElement()");
			}
			System.out.println("[ConfigXmlReadHandler.startElement] result ");
			if(getResult() instanceof Color){
				d.setColor((Color)getResult());
			}
			System.out.println(getResult());
		}
		catch(Exception e){
			System.out.println("[ConfigXmlReadHandler.startElement] Error "+e.getClass().getName()+", message "+e.getMessage());
		}
		
	}
}
class Drawer extends JComponent{
	private Dimension preferredSize = new Dimension(200,200);
	private Shape shape;
	private Color color;
	Drawer(Shape shape, Color color){
		this.shape = shape;
		this.color = color;
	}
	public void paintComponent(Graphics g){
		Graphics2D g2 = (Graphics2D)g;
		g2.setColor(color);
		g2.draw(shape);
	}
	public void setColor(Color color){
		this.color = color;
	}
	public Dimension getPreferredSize(){
		return preferredSize;
	}
}
Finally that behaved as I wanted, but I am not really happy with that. How can I get a Class object based on a tag name? Do I have to create my own mapping or can I use an existing one?
And I am not sure whether I have really understood how things work. Is the above procedure a useful one?
  • a) create an object that extends RootXmlReadHandler and that contains an "inner object" that should be generated or modified based on the informations stored in the xml file.
    b) for the RootXmlReadHandler, use an object as rootHandler (I was very confused by the fact that a RootXmlReadHandler contains a rootHandler that, despite the similaritiy in the names, does not extend RootXmlReadHandler and that doesn´t even share a common ancestor with RootXmlReadHandler in the inheritance hierarchie) that extends AbstractXmlReadHandler and is mainly responsible for
    b1) translating the tag names into object classes from which a suitable child XmlReadHandler class can be obtained and
    b2) making the objects returned by the child XmlReadHandler classes accessible to the surrounding RootXmlReadHandlerinstance
Any comments are welcome!
Regards and thanks, paradoxoff

Posted: Tue Feb 12, 2008 2:57 am
by david.gilbert
This is stuff that Thomas developed for JFreeReport, so I don't know so much about how it works. For XML serialization, though, I can suggest XStream:

http://xstream.codehaus.org/

...which I've seen working pretty well for JFreeChart (possibly there are some issues, but I haven't seen them yet).

Posted: Sat Feb 23, 2008 12:48 pm
by paradoxoff
Thanks for the pointer! I have started to play with that library and it seems to be indeed a very good combination of flexibility and ease of use.