Class JOCLContentHandler

java.lang.Object
org.xml.sax.helpers.DefaultHandler
org.apache.commons.jocl.JOCLContentHandler
All Implemented Interfaces:
ContentHandler, DTDHandler, EntityResolver, ErrorHandler

public class JOCLContentHandler extends DefaultHandler
A ContentHandler for the Java Object Configuration Language.

JOCL provides an XML syntax for constructing arbitrary Java Object instances. It does not define a full XML document type (there's no root element), but rather an XML fragment describing the Objects to be constructed.

In a JOCL fragment, one may define a series of objects using the object element. A trivial example is:

 <object class="java.util.Date"/>
which constructs an instance of java.util.Date using the no-argument constructor.

After a "root-level" <object> element has been processed (that is, once endElement(java.lang.String,java.lang.String,java.lang.String) has been invoked by the XMLReader), it will be appended to a list of Objects maintained by the JOCLContentHandler.

(See size(), clear(), clear(int), getType(int), getValue(int), getTypeArray(), and getValueArray().)

You can list multiple object elements in a fragment. For example, after processing the JOCL fragment:

 <object class="java.util.Date"/>
 <object class="java.util.Date"/>
The getTypeArray() method will return an array composed of two instances of java.util.Date. The sequence of Objects in the array will correspond to the sequence of <object> elements in the JOCL fragment.

As we've seen, when used with no child-elements, the <object> tag will cause the no-argument constructor of the specified class to be invoked. It is also possible to nest <object> tags to provide arguments for the constructor. For example, the fragment:

 <object class="mypackage.Foo">
   <object class="mypackage.Bar"/>
 </object>
will add an instance of mypackage.Foo to the object list, constructed via new mypackage.Foo(new mypackage.Bar()).

There is a special syntax available creating primitive values and arguments, as well as for constructing Strings. Some examples:

 <byte value="3"/>
 <boolean value="false"/>
 <char value="c"/>
 <double value="3.14159"/>
 <float value="3.14"/>
 <int value="17"/>
 <long value="1700000"/>
 <short value="1"/>
 <string value="The quick brown fox..."/>

When invoked at the "root" level (that is, with no <object> parent), this will cause the corresponding "object wrapper" to be added to the list of Objects. The type for these objects will reflect the proper primitive type, however. When invoked with an <object> parent, these will be treated as primitive arguments to the specified Object's constructor. For example, while:

 <int value="5"/>
 <int value="26"/>
 <int value="100"/>

results in three Integer instances being added to the list of values, with types corresponding to Integer, the fragment:

 <int value="5"/>
 <int value="26"/>
 <int value="100"/>

results in three Integer instances being added to the list of values, with types corresponding to Integer.TYPE.

Hence if you want to invoke the mypackage.Foo(java.lang.Integer,java.lang.Integer,java.lang.Integer) constructor, use:

 <object class="mypackage.Foo"/>
   <object class="java.lang.Integer"><int value="5"/></object>
   <object class="java.lang.Integer"><int value="26"/></object>
   <object class="java.lang.Integer"><int value="100"/></object>
 </object>

If you want to invoke the mypackage.Foo(int,int,int) constructor, use:

 <object class="mypackage.Foo"/>
   <int value="5"/>
   <int value="26"/>
   <int value="100"/>
 </object>

If you'd like to creat a null object, use:

 <object class="mypackage.Bar" null="true"/>

Here's a simple but complete example:

 <?xml version="1.0"?>
 <arbitrary-root xmlns="http://apache.org/xml/xmlns/jakarta/commons/jocl">
   <string value="Hello World!"/>
   <string/>
   <boolean/>
   <boolean value="true"/>
   <byte value="1"/>
   <short value="1"/>
   <int value="1"/>
   <long value="1"/>
   <float value="1.0"/>
   <double value="1.0"/>
   <object class="java.util.Date"/>
   <object class="java.util.Date">
    <int value="1"/>
    <int value="1"/>
    <int value="1"/>
   </object>
 </arbitrary-root>

Formally, a DTD for the JOCL grammar is as follows:

 <!ELEMENT object (object|array|collection|list|byte|boolean|char|double|float|int|long|short|string)*>
 <!ATTLIST object
   class CDATA #REQUIRED
   null (true|false) "false">

 <!ELEMENT byte EMPTY>
 <!ATTLIST byte value CDATA #REQUIRED>

 <!ELEMENT boolean EMPTY>
 <!ATTLIST boolean value (true|false) #REQUIRED>

 <!ELEMENT char EMPTY>
 <!ATTLIST char value CDATA #REQUIRED>

 <!ELEMENT double EMPTY>
 <!ATTLIST double value CDATA #REQUIRED>

 <!ELEMENT float EMPTY>
 <!ATTLIST float value CDATA #REQUIRED>

 <!ELEMENT int EMPTY>
 <!ATTLIST int value CDATA #REQUIRED>

 <!ELEMENT long EMPTY>
 <!ATTLIST long value CDATA #REQUIRED>

 <!ELEMENT short EMPTY>
 <!ATTLIST short value CDATA #REQUIRED>

 <!ELEMENT string EMPTY>
 <!ATTLIST string value CDATA #REQUIRED>
 

This class can also be used as a base class for ContentHandlers that include JOCL as part of their grammar. Simply extend this class, and override the startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes), DefaultHandler.characters(char[], int, int), and endElement(java.lang.String, java.lang.String, java.lang.String) methods to handle your tags, and invoke the method of the parent class (i.e., super.XXX for elements and data that you don't handle.

A number of static methods are available for simply reading a list of objects from a InputStream, Reader or InputSource.

Note that this class is not synchronized.

Version:
$Revision: 883416 $ $Date: 2009-11-23 12:12:14 -0500 (Mon, 23 Nov 2009) $
Author:
Rodney Waldhoff