public abstract class BaseXmlInspector extends Object implements DomInspector<Element>
Handles taking a 'flat' XML file (eg. only one <entity>
node deep) and
traversing nested paths, such as foo/bar
, from...
<entity type="foo">
<property name="myBar" type="bar">
</entity>
...to top level...
<entity type="bar">
...and constructing...
<entity name="myBar" type="bar">
...as output.
This class does not support schema validation - it is not that useful in practice for two
reasons. First, Inspectors like HibernateInspector
cannot use it because they can be
pointed at different kinds of files (eg. hibernate.cfg.xml or hibernate-mapping.hbm.xml). Second,
Inspectors that are intended for Android environments (eg. XmlInspector
) cannot use
it because Android's Dalvik preprocessor balks at the unsupported schema classes (even if they're
wrapped in a ClassNotFoundException
).
Several pieces of functionality apply to mixing XML-based Inspector
s (e.g.
XmlInspector
) and Object-based Inspector
s (e.g.
PropertyTypeInspector
) in the same application (i.e. via
CompositeInspector
).
First, you may encounter a problem whereby the Object-based Inspector
s will always
stop at null
or recursive references, whereas the XML Inspector
s (which
have no knowledge of Object values) will continue. This can lead to the
WidgetBuilder
s constructing a UI for a null
Object, which may upset
some WidgetProcessor
s (e.g. BeansBindingProcessor
). To resolve this,
you can set BaseXmlInspectorConfig.setRestrictAgainstObject
, whereby the XML-based
Inspector
will do a check for null
or recursive references, and not
return any XML.
In addition, setting restrictAgainstObject
allows the XML Inspector
to
traverse child relationships and infer their types using the Object. This saves having to
explicitly specify those types and relationships in the XML.
Second, by default you need to explicitly specify any inheritance relationships between types in
the XML, because the XML has no knowledge of your Java classes. This includes the names of any
proxied classes. If this becomes laborious, you can set
BaseXmlInspectorConfig.setInferInheritanceHierarchy
to infer the relationships
automatically from your Java classes. If you are using setRestrictAgainstObject
,
setInferInheritanceHierarchy
is implied.
Third, it is important the properties defined by the XML and the ones defined by the Java classes
stay in sync. To enforce this, you can set
BaseXmlInspectorConfig.setValidateAgainstClasses
.
Modifier and Type | Field and Description |
---|---|
protected LogUtils.Log |
mLog |
Modifier | Constructor and Description |
---|---|
protected |
BaseXmlInspector(BaseXmlInspectorConfig config)
Config-based constructor.
|
Modifier and Type | Method and Description |
---|---|
protected Element |
getDocumentElement(Document... documents)
Merge the given DOM Documents into a single Document, and return its root.
|
protected Element |
getDocumentElement(ResourceResolver resolver,
InputStream... files)
Parse the given InputStreams into a single DOM Document, and return its root.
|
protected String |
getExtendsAttribute()
The attribute on top-level elements that identifies a superclass relationship (if any).
|
protected String |
getNameAttribute()
The attribute on child elements that uniquely identifies them.
|
protected String |
getReferenceAttribute()
The attribute on child elements that identifies a reference to another element (if any).
|
protected String |
getTopLevelTypeAttribute()
The attribute on top-level elements that uniquely identifies them.
|
protected String |
getTypeAttribute()
The attribute on child elements that identifies another top-level element.
|
String |
inspect(Object toInspect,
String type,
String... names)
Inspect the given Object according to the given path, and return the result as a String
conforming to inspection-result-1.0.xsd.
|
protected Map<String,String> |
inspectAction(Element toInspect)
Inspect the given Element and return a Map of attributes if it is an action.
|
Element |
inspectAsDom(Object toInspect,
String type,
String... names)
Optimized verison of
inspect that avoids DOM serialization/deserialization. |
protected Map<String,String> |
inspectProperty(Element toInspect)
Inspect the given Element and return a Map of attributes if it is a property.
|
protected Element |
inspectTrait(Document toAddTo,
Element toInspect)
Inspect the given Element and return a Map of attributes if it is a trait.
|
protected void |
inspectTraits(Element toInspect,
Element toAddTo)
Inspect the
toInspect for properties and actions. |
protected void |
inspectTraitSiblings(Element toAddTo,
Element toInspect)
Inspect the given trait, looping over its siblings.
|
protected void |
preprocessDocument(Document document)
Hook for subclasses to preprocess the document after the Inspector is initialized.
|
protected ValueAndDeclaredType |
traverse(Object toTraverse,
String type,
boolean onlyToParent,
String... names) |
protected Element |
traverseFromTopLevelTypeToNamedChildren(Element topLevel)
Traverse from the given top-level element (as per
getTopLevelTypeAttribute ) to
the element which contains named children (as per getNameAttribute ). |
protected LogUtils.Log mLog
protected BaseXmlInspector(BaseXmlInspectorConfig config)
All BaseXmlInspector inspectors must be configurable, to allow specifying an XML file.
public final String inspect(Object toInspect, String type, String... names)
This method is marked final
because most Metawidget implementations will call
inspectAsDom
directly instead.
public Element inspectAsDom(Object toInspect, String type, String... names)
DomInspector
inspect
that avoids DOM serialization/deserialization.inspectAsDom
in interface DomInspector<Element>
protected Element getDocumentElement(ResourceResolver resolver, InputStream... files) throws Exception
resolver
- helper in case getDocumentElement
needs to resolve references defined
in the InputStream
.Exception
protected Element getDocumentElement(Document... documents) throws Exception
Exception
protected void preprocessDocument(Document document)
For example, HibernateInspector
preprocesses the class names in Hibernate
mapping files to make them fully qualified.
document
- DOM of XML being processedprotected void inspectTraits(Element toInspect, Element toAddTo)
toInspect
for properties and actions.
This method can be overridden by clients wishing to modify the inspection process. Most
clients will find it easier to override one of the sub-methods, such as
inspectTrait
or inspectProperty
.
protected void inspectTraitSiblings(Element toAddTo, Element toInspect)
This method can be overridden by clients wishing to modify the inspection process. Most
clients will find it easier to override one of the sub-methods, such as
inspectTrait
or inspectProperty
.
protected Element inspectTrait(Document toAddTo, Element toInspect)
It is this method's responsibility to decide whether the given Element does, in fact, qualify as a 'trait' - based on its own rules.
toInspect
- DOM element to inspectprotected Map<String,String> inspectProperty(Element toInspect)
It is this method's responsibility to decide whether the given Element does, in fact, qualify as a 'property' - based on its own rules. Does nothing by default.
toInspect
- DOM element to inspectprotected Map<String,String> inspectAction(Element toInspect)
It is this method's responsibility to decide whether the given Element does, in fact, qualify as an 'action' - based on its own rules. Does nothing by default.
toInspect
- DOM element to inspectprotected ValueAndDeclaredType traverse(Object toTraverse, String type, boolean onlyToParent, String... names)
protected String getTopLevelTypeAttribute()
protected String getNameAttribute()
protected String getTypeAttribute()
This is necessary for path traversal. If an XML format does not specify a way to traverse
from a child to another top-level element, the Inspector cannot find information along paths
(eg. foo/bar/baz
). There is a way around this but, on balance, we
decided against it (see http://blog.kennardconsulting.com/2008/01/ask-your-father.html).
protected String getExtendsAttribute()
protected String getReferenceAttribute()
typeAttribute
will always take precedence over
referenceAttribute
.protected Element traverseFromTopLevelTypeToNamedChildren(Element topLevel)
getTopLevelTypeAttribute
) to
the element which contains named children (as per getNameAttribute
). In many
cases this is one and the same, so by default this method simply returns the given element.
Subclasses can override this method if they need to do some intermediate traversal.
Copyright © 2015. All Rights Reserved.