org.agaveblue.slash
Class SlashHandler
java.lang.Object
org.xml.sax.helpers.DefaultHandler
org.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 |
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).
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