metawidget.xml is an alternate (and optional) way to configure Metawidget.
It allows you to configure a Metawidget without writing any Java code. This
can be useful in environments with intermediate languages that shield the developer from the
raw Java, such as JSPs or Facelets. It can also be useful as a single place for configuring multiple Metawidgets,
such as across multiple dialogs of a desktop application.
The metawidget.xml format, as parsed by org.metawidget.config.ConfigReader,
is specialised for configuring Metawidget instances. The following sections explore some of the features of the
XML format and ConfigReader.
ConfigReader can construct new instances of objects. The XML element name is the Java class name
and the XML namespace is the Java package. The following example constructs an org.metawidget.swing.SwingMetawidget.
<metawidget xmlns="http://metawidget.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://metawidget.org http://metawidget.org/xsd/metawidget-1.0.xsd"> <swingMetawidget xmlns="java:org.metawidget.swing"/> </metawidget>
Using the XML namespace to denote the Java package allows the (optional) plugging in of XML Schema validation on a per-package basis. For example:
<swingMetawidget xmlns="java:org.metawidget.swing" xsi:schemaLocation="java:org.metawidget.swing http://metawidget.org/xsd/org.metawidget.swing-1.0.xsd"/>
Within an object, ConfigReader can call setXXX methods. The following example
calls the setOpaque method of SwingMetawidget:
<metawidget xmlns="http://metawidget.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://metawidget.org http://metawidget.org/xsd/metawidget-1.0.xsd"> <swingMetawidget xmlns="java:org.metawidget.swing"> <opaque> <boolean>true</boolean> </opaque> </swingMetawidget> </metawidget>
Multi-parameter methods are also supported. The following example calls the setParameter method
of HtmlMetawidget (it takes two arguments):
<metawidget xmlns="http://metawidget.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://metawidget.org http://metawidget.org/xsd/metawidget-1.0.xsd"> <htmlMetawidget xmlns="java:org.metawidget.faces.component.html"> <parameter> <string>numberOfColumns</string> <int>2</int> </parameter> </htmlMetawidget> </metawidget>
As alluded to in the previous section, when calling setXXX methods the XML format can
specify simple types. The previous example used boolean, string
and int. Also supported are:
| Element name | Java type |
|---|---|
<array> |
constructs a Java array. The array's component type (ie. String[], int[] etc)
is based on the signature of the method being invoked (ie. setInspectors( Inspector... ))
|
<boolean> |
Java boolean primitive |
<bundle> |
uses ResourceBundle.getBundle to construct a ResourceBundle
|
<class> |
Java Class |
<file> |
uses FileInputStream to open a file as an InputStream
|
<int> |
Java int primitive |
<list> |
constructs a java.util.ArrayList |
<null> |
Java null value |
<pattern> |
Java Pattern |
<resource> |
uses Class.getResourceAsStream to open a resource as an InputStream |
<set> |
constructs a java.util.HashSet |
<string> |
constructs a java.lang.String |
<url> |
uses URL.openStream to open a URL as an InputStream |
Some environments store their resources in specialized locations that are inaccessible
by normal means (ie. ClassLoader.getResource). For example, Web
environments use a WEB-INF folder that must be accessed through
ServletContext.getResource. Simiarly, Android environments must resolve
resources using Context.getResources.
ConfigReader and its specialized subclasses, such as
ServletConfigReader and AndroidConfigReader
understand this distinction and provide resource resolving capability to all the
objects they create. Specifically, ConfigReader implements
ResourceResolver and passes itself to any xxxConfig
classes that implement NeedsResourceResolver.
Metawidget dictates all Inspectors, WidgetBuilders, WidgetProcessors
and Layouts be threadsafe and immutable. This is an important design decision as
it means a single instance can be reused across an entire application. Immutabilty
is enforced by not having any setXXX methods on the objects themselves.
Rather, the setXXX methods are called on Config objects, which are then passed
to the object's constructor. Once constructed, the object cannot be changed.
ConfigReader understands this distinction by way of a config attribute. The following example
configures an immutable Inspector. The setInspectors method is called
on org.metawidget.inspector.composite.CompositeInspectorConfig
and then passed to CompositeInspector:
<compositeInspector xmlns="java:org.metawidget.inspector.composite" config="CompositeInspectorConfig"> <inspectors> <array> <metawidgetAnnotationInspector xmlns="java:org.metawidget.inspector.annotation" /> <propertyTypeInspector xmlns="java:org.metawidget.inspector.propertytype"/> </array> </inspectors> </compositeInspector>
Having constructed an immutable object, ConfigReader will cache the instance and reuse it. The
config attribute defaults to using the same package as the xmlns (ie.
org.metawidget.inspector.composite in the example above). This can be overridden if a fully
qualified classname is provided.
![]() | Config classes must override equals and hashCode |
|---|---|
In order to reliably cache and reuse an immutable object that uses a config attribute, the
xxxConfig class must override equals
and hashCode. This is important to bear in mind when implementing your own custom objects.
|