public class GenericSAXHandler
extends org.xml.sax.helpers.DefaultHandler
getGlobalObjects(String)
method.
The handler can be configured to produce objects of arbitrary types by
supplying instances of custom Mapper
subclasses to it: each
such "mapper" is responsible for loading the XML data under a particular
XML element (attributes and child elements) into a "payload" Java object of
the right type.
The default behavior provided by Mapper
base class is to
attempt to relate XML attributes to setter methods in the Java class, on a
best effort basis, following the Java bean conventions. Attempts are made
to convert String
attribute values read from XML to the
respective properties' own types. In cases where this default approach does
not work, a custom property setter can be defined by Mapper
subclasses, overriding the one in the base (Mapper.setProperty(Object, String, String)
).
As the nested structure of XML nodes reflect the composite nature of Java
objects, mappers also have the duty of controlling how objects that spring
from a certain sub-tree of the XML document are "consumed" by the parent
object, corresponding to its ancestor node in the XML tree. Unlike setting
properties, no assumptions can be made here regarding how an object is to
be integrated in its container, therefore the Mapper
subclass
for the parent object would have to override method Mapper.mergeSubObj(Object, Object)
.
Recursive composite structures (types that contain instances of their own
type in the object structure) are supported by mappers by default. The same
mapper instance can be used simultaneously with any number of objects in
the process of being constructed at a given time and Mapper
subclasses can learn about the context where they're operating by using the
convenience methods provided by Mapper
base class (Mapper.getXmlPath()
, Mapper.getParentTag()
).
Mapping XML nodes to Java types is also sensitive to context. The same XML tag can be mapped to different types, depending on where in the XML tree it appears. If a mapper is installed for a more specific context (e.g. "cfg/schema/namespace/dialect-specific/parameter"), it takes precedence over a general purpose mapper installed for the simple tag name (in this case "parameter").
Constraints can be added for data that is read from XML: for any element,
sets of mandatory and optional attributes as well as required and optional
child elements can be specified with setConstraints(String, String[], String[], String[],
String[])
.
The handler can be instructed to regard particular XML tag names as "unhandled" (or "transparent"). XML elements having those names are not considered for translating into Java objects. Child elements of such a node are perceived as direct children of the node's first normal (non-transparent) ancestor. In case all nodes up to the root are unhandled, the respective child objects land as top-level objects in the global end-result object list. This dismisses the constraint of having a 1:1 correspondence between Java types and XML tag names, which increases flexibility.
This class is not synchronized.
Mapper
Modifier and Type | Class and Description |
---|---|
(package private) static class |
GenericSAXHandler.ActiveNode<T>
Simple convenience container to decouple the mapper from the object it
constructs, without breaking generic type safety.
|
Modifier and Type | Field and Description |
---|---|
private java.util.Map<java.lang.String,java.util.List<java.lang.Object>> |
globalObjs
The container for top-level objects that were constructed by this
handler during the parsing process.
|
private java.util.Stack<GenericSAXHandler.ActiveNode<?>> |
inProcess
The stack of objects currently being processed (populated), each by its
own kind of mapper.
|
private java.util.Map<java.lang.String,Mapper<?>> |
mappers
Container for all
Mapper objects, indexed by the name of
the XML tag they process. |
private java.util.Stack<java.lang.String> |
tagsInProcess
XML tags don't relate to mappers 1:1 so we keep track of tags here.
|
private java.util.Set<java.lang.String> |
unhandledTags
The set of "unhandled" tags that this handler was configured with.
|
static char |
XMLPATH_SEPARATOR
Separator for paths in the XML tree.
|
Constructor and Description |
---|
GenericSAXHandler() |
Modifier and Type | Method and Description |
---|---|
void |
endElement(java.lang.String uri,
java.lang.String localName,
java.lang.String qName)
Notification of the end of an XML element.
|
private java.lang.String |
getCurrentPath()
Gives the full path in the XML tree from the root to (and including) the
current node being processed.
|
java.util.List<java.lang.Object> |
getGlobalObjects(java.lang.String name)
Provides the list of top-level objects that were constructed from
top-level XML nodes having a specific name.
|
void |
installMapper(java.lang.String xmlKey,
Mapper<?> m)
Configures the handler with a specific
Mapper for handling
XML nodes. |
void |
reset()
Resets handler state and also discards all configuration data (installed
mappers, constraints, unhandled tags).
|
void |
resetState()
Resets the state built during processing; leaves configured data in
place (installed mappers, constraints, unhandled tags).
|
private void |
saveGlobalObject(java.lang.String name,
java.lang.Object g)
Save away (as end-result) a top-level object that was constructed from
XML.
|
void |
setConstraints(java.lang.String xmlKey,
java.lang.String[] reqAttrs,
java.lang.String[] optAttrs,
java.lang.String[] reqChld,
java.lang.String[] optChld)
Adds constraints for a specific kind of XML nodes, in the form of
mandatory and optional attributes and/or child elements.
|
void |
setUnhandledTags(java.lang.String[] tags)
Unhandled tags are "transparent", in that they are not considered for
encapsulation but have their content silently unfolded and processed as
if it belonged to their parent.
|
void |
startElement(java.lang.String uri,
java.lang.String localName,
java.lang.String qName,
org.xml.sax.Attributes attrs)
Notification of beginning of an XML element.
|
public static char XMLPATH_SEPARATOR
private java.util.Map<java.lang.String,Mapper<?>> mappers
Mapper
objects, indexed by the name of
the XML tag they process.private java.util.Stack<GenericSAXHandler.ActiveNode<?>> inProcess
private java.util.Stack<java.lang.String> tagsInProcess
private java.util.Set<java.lang.String> unhandledTags
private java.util.Map<java.lang.String,java.util.List<java.lang.Object>> globalObjs
public void startElement(java.lang.String uri, java.lang.String localName, java.lang.String qName, org.xml.sax.Attributes attrs) throws org.xml.sax.SAXException, java.lang.RuntimeException
startElement
in interface org.xml.sax.ContentHandler
startElement
in class org.xml.sax.helpers.DefaultHandler
uri
- The Namespace URI, or the empty string if the element has no
Namespace URI or if Namespace processing is not being performed.localName
- The local name (without prefix), or the empty string if
Namespace processing is not being performed.qName
- The qualified name (with prefix), or the empty string if
qualified names are not available.attrs
- The attributes attached to the element. If there are no
attributes, it shall be an empty Attributes object.org.xml.sax.SAXException
- On any SAX errors, possibly wrapping another exception.java.lang.RuntimeException
- wrapping a ConfigurationException
if any error
occurs while the objects are being populated with data read
from XML. This includes file format constraint violations
detected during parsing.ContentHandler.startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
public void endElement(java.lang.String uri, java.lang.String localName, java.lang.String qName) throws org.xml.sax.SAXException, java.lang.RuntimeException
endElement
in interface org.xml.sax.ContentHandler
endElement
in class org.xml.sax.helpers.DefaultHandler
uri
- The Namespace URI, or the empty string if the element has no
Namespace URI or if Namespace processing is not being performed.localName
- The local name (without prefix), or the empty string if
Namespace processing is not being performed.qName
- The qualified name (with prefix), or the empty string if
qualified names are not available.org.xml.sax.SAXException
- On any SAX error, possibly wrapping another exception.java.lang.RuntimeException
- wrapping a ConfigurationException
if any error
occurs while the objects are being populated with data read
from XML. This includes file format constraint violations
detected during parsing.ContentHandler.endElement(java.lang.String, java.lang.String, java.lang.String)
public java.util.List<java.lang.Object> getGlobalObjects(java.lang.String name)
name
- The XML tag / XML path that was used to install the mapper that
built the object.public void installMapper(java.lang.String xmlKey, Mapper<?> m)
Mapper
for handling
XML nodes.xmlKey
- A string identifying the XML nodes that will be handled by the
provided mapper. Normally, for general purpose mappers this is a
simple tag name, but it can also be a full path in the XML tree
denoting the specific context where the mapper is going to be
employed. The path uses XMLPATH_SEPARATOR
as separator,
defined as '/'.m
- The concrete mapper instance to be used for handling the
designated XML nodes.public void setConstraints(java.lang.String xmlKey, java.lang.String[] reqAttrs, java.lang.String[] optAttrs, java.lang.String[] reqChld, java.lang.String[] optChld) throws java.lang.IllegalArgumentException
null
value:
If the set of mandatory attributes/children is empty or null
, the respective constraint is disabled: there are no required
attributes or child elements, respectively. The meaning for the sets of
optional items is different: null
means the constraint is
disabled (any elements can appear), while the empty set indicates that
there are no optional elements.
The way the XML node name that the constraints apply to is specified is similar to how mappers are installed for specific nodes.
xmlKey
- The name of the XML node that the constraints apply to. Can be a
simple tag name or a specific path in the XML tree, using
XMLPATH_SEPARATOR
as separator (defined to '/').reqAttrs
- Array containing mandatory attribute names.optAttrs
- Array containing optional attribute names.reqChld
- Array containing mandatory child names.optChld
- Array containing optional attribute names.java.lang.IllegalArgumentException
- If the tag name is invalid.public void resetState()
public void reset()
public void setUnhandledTags(java.lang.String[] tags)
tags
- The set of unhandled XML tags.private void saveGlobalObject(java.lang.String name, java.lang.Object g)
name
- The name of the XML node corresponding to the constructed
object.g
- The constructed object.private java.lang.String getCurrentPath()
XMLPATH_SEPARATOR
as separator, defined as '/'.String
.