org.agaveblue.slash
Class SlashHandler

java.lang.Object
  extended byorg.xml.sax.helpers.DefaultHandler
      extended byorg.agaveblue.slash.SlashHandler
All Implemented Interfaces:
org.xml.sax.ContentHandler, org.xml.sax.DTDHandler, org.xml.sax.EntityResolver, org.xml.sax.ErrorHandler

public class SlashHandler
extends org.xml.sax.helpers.DefaultHandler

SlashHandler is an extension of the SAX DefaultHandler that provides for Simple Lightweight Automatic parsing of XML into beans, collections, or collections of beans. The XML is parsed into Object format using zero or more hints supplied as a java.util.Map to the constructor. The structure of the hints Map is such that the keys in the map are localized tag names and the values are java.lang.Class objects representing the class or interface to use for the element specified by the key.

The default behavior of the SlashHandler if provided an empty hints map is to generate a recursive object tree of the form:

O = java.lang.String | java.lang.LinkedList[O]

For instance, the following XML:

<sometag>somevalue</sometag>

would result in the SlashHandler returning a java.lang.String whose value is "somevalue". And, more interestingly, the following XML:

<sometag>
    <somesubtag1>somevalue1</somesubtag1>
    <somesubtag2>
       <somelowleveltag>somevalue2</somelowleveltag>
       <somelowleveltag>somevalue3</somelowleveltag>
    </somesubtag2>
</sometag>


would result in the SlashHandler returning a java.util.LinkedList which contains, in order, a java.lang.String whose value is "somevalue1", followed by a java.util.LinkedList containing two java.lang.String objects of "somevalue2" followed by "somevalue3".

However, if supplied with one or more hints the SlashHandler becomes even more powerful. For the XML described above, suppose we have the following bean object:

...
public class SomeBean
{
    private String somesubtag1;
    private Set somesubtag2;

    public SomeBean(){}

    public void setSomesubtag1(String s){...}

    public void setSomesubtag2(Set set){...}
...


For the XML above and the bean "SomeBean", the following code will result in automatic parsing of the XML such that the SlashHandler.getResult() will return a new instance of SomeBean with all of its members populated by the XML:

...
    java.util.HashMap hints = new java.util.HashMap();
    hints.put("sometag", SomeBean.class);
    SlashHandler handler = new SlashHandler(hints, true);
    SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
    parser.parse(someXMLFile, handler);
    SomeBean result = (SomeBean) handler.getResult();
...


It is important to notice two things about this example. First, the SlashHandler was not provided any hint for the somesubtag2 tag/bean attribute combination, and second, the parameter type for somesubtag2 is the Set interface. However, the SlashHandler handles both of these issues without any problem. First, the SlashHandler will check for a hint for each tag, however if a hint is not provided then the SlashHandler will reflect the parent bean for a setter method that corresponds to the tag name, and then determine the parameter type from that setter method. If the parameter type is a String (as is the case with somesubtag1), then the setter method is simply called with the tag's value. If the parameter type is primitive, then the SlashHandler will automatically convert the tag's value to that type and call the setter. And finally, if the parameter is a non-primitive, non-String then the SlashHandler will attempt to treat the parameter as a bean. However, in the example above, the parameter type is the java.util.Set interface, yet the SlashHandler is still able to successfully parse this XML and populate the SomeBean. This is because the SlashHandler makes some default assumptions for the Java Collections Framework interfaces. Any time the SlashHandler encounters the parameter type specified by the first column of the table below, it automatically substitutes it for the concrete implementation specified in the second column:

Interface encountered Class used
java.util.Collection java.util.LinkedList
java.util.List java.util.LinkedList
java.util.Set java.util.HashSet
java.util.SortedSet java.util.TreeSet


Any parameter type can be overridden by providing a hint, but obviously if the class provided by the hint is not compatible with the setter method, an IllegalArgumentException will be generated, and parsing will fail with a SAXException being thrown by the parser.

The SlashHandler extends the DefaultHandler class which allows for all other facilities within the SAX 2.0 framework to be used in conjunction with the SlashHandler. DTD and XML Schema validation can be applied as it would be with any other DefaultHandler implementation. Also, the SlashHandler may be extended and any of its methods may be overridden to provide any additional XML parsing concerns such as filtering or translating tags or anything else that might need to be done. Note, however, that overriding the startElement, endElement, and characters methods will require calls to the super as appropriate for bean parsing to occur.

Finally, the constructor also takes a boolean parameter to set the mode of the SlashHandler to be strict (if true), or lenient (if false). This strict/lenient flag does not refer to whether or not the XML is properly formatted, rather this flag tells the SlashHandler how to behave if it encounters tags that it can't figure out how to handle. If set to true, the SlashHandler will throw a SAXException if it cannot find a setter method or a valid type to use for any given tag. However, if the strict flag is set to false, then the SlashHandler will simply ignore and drop any tag that it encounters that it cannot determine how to handle.

This version requires that all hint classes have a default constructor and either implement the java.util.Collection interface or have a bean setter method that corresponds to each tag in the XML.

For more comprehensive documentation and a tutorial, see http://www.agaveblue.org/projects/slash/.

Version:
1.0
Author:
Wade Wassenberg

Constructor Summary
SlashHandler(java.util.Map hints, boolean strict)
           
 
Method Summary
 void characters(char[] ch, int start, int length)
           
 void endElement(java.lang.String uri, java.lang.String localName, java.lang.String qName)
           
 java.lang.Object getResult()
           
 void startElement(java.lang.String uri, java.lang.String localName, java.lang.String qName, org.xml.sax.Attributes attributes)
           
 
Methods inherited from class org.xml.sax.helpers.DefaultHandler
endDocument, endPrefixMapping, error, fatalError, ignorableWhitespace, notationDecl, processingInstruction, resolveEntity, setDocumentLocator, skippedEntity, startDocument, startPrefixMapping, unparsedEntityDecl, warning
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

SlashHandler

public SlashHandler(java.util.Map hints,
                    boolean strict)
Parameters:
hints - a map whose key values are localized tag names, and whose values are java.lang.Class objects representing the type to use for the localized tag specified.
strict - a boolean telling the SlashHandler whether to throw a SAXException (if true) or drop/ignore tags that the SlashHandler cannot figure out how to handle (if false).
Method Detail

startElement

public void startElement(java.lang.String uri,
                         java.lang.String localName,
                         java.lang.String qName,
                         org.xml.sax.Attributes attributes)
                  throws org.xml.sax.SAXException
Throws:
org.xml.sax.SAXException
See Also:
DefaultHandler.startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)

endElement

public void endElement(java.lang.String uri,
                       java.lang.String localName,
                       java.lang.String qName)
                throws org.xml.sax.SAXException
Throws:
org.xml.sax.SAXException
See Also:
DefaultHandler.endElement(java.lang.String, java.lang.String, java.lang.String)

characters

public void characters(char[] ch,
                       int start,
                       int length)
                throws org.xml.sax.SAXException
Throws:
org.xml.sax.SAXException
See Also:
DefaultHandler.characters(char[], int, int)

getResult

public java.lang.Object getResult()
Returns:
the resultant object of any type specified by a hint for the root tag or a LinkedList or String if no hint is provided for the root tag.


Copyright 2008 Wade Wassenberg.
On the web: http://www.agaveblue.org/projects/slash/.
Send bug reports to slash@wass.homelinux.net.
Last Modified June 10, 2008