|
You can customize the default behavior by creating sub-classes of
Marshaller and Unmarshaller, and registering them with an
ObjectXMLReader and ObjectXMLWriter using an XMLMap. The function of
the XMLMap is to associate classes with Marshallers, and XML elements
with Unmarshallers. An XMLMap can be initialized programmatically,
or by reading an XML specification. The XMLMap class defines a static
method for unmarshalling maps from XML files, and, for convenience,
ObjectXMLReader and ObjectXMLWriter objects can parse XMLMap specifications
when given the file name.
Example marshaller and unmarshaller specification in test/data/jxm.xml:
<jxm>
<default_package>com.lifecde.jxm</default_package>
<element name="node"
unmarshaller="com.lifecde.jxm.NodeUnmarshaller"/>
<element name="connection"
unmarshaller="com.lifecde.jxm.ConnectionUnmarshaller"/>
<class name="com.lifecde.jxm.Connection"
marshaller="com.lifecde.jxm.ConnectionMarshaller"/>
<class name="com.lifecde.jxm.Graph"
marshaller="com.lifecde.jxm.GraphMarshaller"/>
</jxm>
Note that the specification can also declare default packages.
If no Unmarshaller is associated with an element, the default Unmarshaller will
form fully-qualified class names using the default package names and the XML element
name. If a class with the generated name is found, that class is instantiated for
unmarshalling.
You write a custom Marshaller by creating a sub-class of Marshaller. The Marshaller
defines default writeAttributes and writeContent methods
for writing the XML attributes and XML content associated with an Object.
An XMLWriter
is passed into these methods to handle XML formatting and
escape characters.
Writing a custom Unmarshaller is much like implementing a SAX ContentHandler.
The Unmarshaller has a readAttributes method which is
passed a SAX Attributes object containing the XML attributes for the element.
The Unmarshaller add method is called to add objects that
were unmarshalled from the element's content.
Finally, you may want to incorporate the marshalling and unmarshalling
setup code into Java objects that might be mapped to the root elements of XML
documents.
It's also easier for users of the classes if any necessary JXM
specification files are packaged in the associated JAR file.
When this is done, users never need to be aware of the existence of JXM or
the specification files. Here is a pattern to follow:
protected static XMLMap xmlMap;
// load XMLMap during class loading.
static
{
try
{
Reader in =
new InputStreamReader(Person.class.getResourceAsStream(
"jxm.xml"));
xmlMap = XMLMap.unmarshal(in);
in.close();
}
// an exception here will prevent the class from loading. This is
// acceptable, because it indicates that the JAR file
// was built incorrectly.
//
catch (IOException e)
{
throw new ExceptionInInitializerError(
"Unable to read XML marshalling specification.");
}
catch (SAXException e)
{
throw new ExceptionInInitializerError(
"Unable to parse XML marshalling specification..");
}
}
public void marshal(Writer out)
throws IOException, TranslationException, SAXException
{
ObjectXMLWriter wr = new ObjectXMLWriter(out);
wr.setXMLMap(xmlMap);
wr.write(this);
}
public static Person unmarshal(Reader in)
throws IOException, SAXException
{
ObjectXMLReader xr = new ObjectXMLReader();
xr.setXMLMap(xmlMap);
return (Person) xr.parse(in);
}
|