Bean Naming Conventions

The Java Beans specification contains various naming conventions that should be used when writing beans that will allow the beans introspector to automatically guess the properties in a bean and their getters, their setter methods etc. Betwixt will use these same naming conventions to deduce how to make the beans appear as XML. There are some other naming conventions that you can use to make your beans easier to output as XML or parse.

One common requirement when mapping beans to xml is that the property and type names from the bean must be processed (in some way) before they are used in the xml. For example, a property called WebApp might need to be mapped to an element called web-app.

Betwixt supports customization of these mappings through plug-in implementations of the org.apache.commons.betwixt.strategy.NameMapper interface. It is often useful to allow different mappings for elements and attribute and so different implementations can be set for elements and attributes. The default NameMapper implementation simply returns the type name without modification.

Note that the attribute and element names given in a .betwixt file (as usual) override the name mapping settings on the XMLIntrospector.

Using A Custom Type Name To Element Name Mapping

Betwixt supports pluggable conversion of type names to element names. Setting the ElementNameMapper property on an XMLIntrospector determines how names from the bean will be converted into element names.

Using A Custom Property Name To Attribute Name Mapping

Betwixt supports pluggable conversion of type names to attribute names. Setting the AttributeNameMapper property on an XMLIntrospector determines how names from the bean will be converted into attribute names.

Custom Mapping Example

Here's a simple bean which will be mapped to xml:

public class TallTreeBean {

    private float heightOfTree;
    
    public TallTreeBean(float height) {
        setHeightOfTree(height);
    }
    
    public float getHeightOfTree() {
        return heightOfTree;
    }	
    
    public void setHeightOfTree(float heightOfTree) {
        this.heightOfTree = heightOfTree;
    }
}	

Next is an application that writes that bean to xml. Custom name mappers for elements and attributes are set.

import org.apache.commons.betwixt.io.BeanWriter;
import org.apache.commons.betwixt.strategy.DecapitalizeNameMapper;
import org.apache.commons.betwixt.strategy.HyphenatedNameMapper;

public class NameMapperExampleApp {
    
    public static final void main(String args[]) throws Exception{
        
        // create write and set basic properties
	BeanWriter writer = new BeanWriter();
        writer.getXMLIntrospector().setAttributesForPrimitives(true);
        writer.enablePrettyPrint();
        writer.setWriteIDs(false);
        
        // set a custom name mapper for attributes
        writer.getXMLIntrospector().setAttributeNameMapper(new HyphenatedNameMapper());
        // set a custom name mapper for elements
        writer.getXMLIntrospector().setElementNameMapper(new DecapitalizeNameMapper());
        
        // write out the bean
        writer.write(new TallTreeBean(15.1f));
        System.out.println("");
    }
    
}

The application should print out (to System.out) an xml fragment which looks like:

<tallTreeBean height-of-tree="15.1"/>

As you can see, the first letter of the element name has been decapitalized and the capitals in the property separated by hyphens after being converted to lower case.

Nested Classes

When using a public nested class (whether static or not) the naming of the base type passed into the NameMapper obeys the standard inner classes naming semantics (using $). Typically, the mappers that ship with Betwixt ignore this symbol during type name processing. It will therefore appear in the name of the element.

For example, running the following application:

public class InnerClassWriter {
    public class TallTreeBean {

        private float heightOfTree;

        public TallTreeBean(float height) {
                setHeightOfTree(height);
        }

        public float getHeightOfTree() {
                return heightOfTree;
        }       

        public void setHeightOfTree(float heightOfTree) {
                this.heightOfTree = heightOfTree;
        }
    }

    public static final void main(String args[]) throws Exception {

        // create write and set basic properties
        BeanWriter writer = new BeanWriter();
        writer.getXMLIntrospector().getConfiguration()
            .setAttributesForPrimitives (true);
        writer.enablePrettyPrint();
        writer.getBindingConfiguration().setMapIDs(false);

        // set a custom name mapper for attributes
        writer.getXMLIntrospector().getConfiguration()
            .setAttributeNameMapper(new HyphenatedNameMapper());
        // set a custom name mapper for elements
        writer.getXMLIntrospector().getConfiguration()
            .setElementNameMapper(new  DecapitalizeNameMapper());

        // write out the bean
        writer.write(new InnerClassWriter().new TallTreeBean(15.1f));
    }
}

results in:

    <innerClassWriter$TallTreeBean height-of-tree="15.1"/>

It is recommended that those that make extensive use of inner classes create a custom NameMapper implementation that processes inner class names appropriately.

Note: that since Betwixt uses reflection during introspection, the usual rules concerning class scoping and visibility apply.

For example, if the scope of the nested class in the example above is changed from public to protected, friendly or private then the following result will be produced:

    <innerClassWriter$TallTreeBean/>

Using Adder Methods For Composite Properties

This naming convention is used to indicate the singular type of some composite property.

To use: create an add method to match the getter method for 'composite properties'.

public class SomeBean {
    public <CollectionType> getFoo*();
    public void addFoo(<SingularType> foo);
}

Where CollectionType can be an array, a Collection, Enumeration, Iterator, Map. The [SinglularType] refers to the type of an item in the collection. The name of the getter property starts with 'Foo'. So 'Foo' is the singular name, the plural collection name could be Foos, FooArray, FooList, FooIterator or some other encoding, though the plural name should start with the singular name for auto-detection to work properly.

Using A Custom Plural Stemmer

Betwixt allows this auto-detection of plurals from singulars to be customized. Implementations of org.apache.commons.betwixt.PluralStemmer allow different strategies for this mapping to be plugged into XMLIntrospector. The strategy used by XMLIntrospector to match singular properties and plural methods is determined by the PluralStemmer property value.

One important usage of custom plural stemmers is to support classes with non-english method names. A custom PluralStemmer implementation can be created containing the plural rules for the language. Betwixt will then be able to recognize matching plural and singular methods.

The default implementation supports common english plural patterns and then falls back to finding any property that starts with the singular name. For example, it will match a plural property called FooBars for a singular property called FooBar.

Reading And Writing Map Properties

Maps are a special kind of composite property. Each entry in a map has a key and a value. Betwixt handles maps by adding extra elements which wrap each entry. Each entry is wrapped in a <entry> element. That element contains the key wrapped in a <key> element and the entry value wrapped in a <value> element.

The structure is something like:

    ...
    <entry>
        <key>...</key>
        <value>...</value>
    <entry>
    <entry>
        <key>...</key>
        <value>...</value>
    <entry>
    ...
The key and the value content are standard betwixt mappings of the objects.

Reading map properties is an extension of the ways that Betwixt handles collections. Rather than searching for an add* method that takes a single parameter, now Betwixt looks (in a similar fashion) for such a method that takes two parameters.

Customized Mapping (Advanced)

Caching and the XMLRegistry

Introspection is slow and so caching the results improves performance. Though the writers and readers can - by nature - only be used safely in a single thread, a single XMLIntrospector instance can be safely shared amongst multiple threads. Sharing a single instance will improve performance by sharing it's XMLBeanInfo cache.

The XMLBeanInfoRegistry interface allows finely grained, pluggable control over the caching strategy used by a XMLIntrospector. The implementation used can be set by passing an instance to XMLIntrospector.setRegistry.

Before using the standard introspection techniques to create a new XMLBeanInfo instance for a bean, the current XMLBeanInfoRegistry is first checked. Only if the registry does not return an XMLBeanInfo will a new one be created. Once a new instance has been created by introspection, the XMLBeanInfoRegistry implementation will be called so that the XMLBeanInfo can (if required) be cached.

The default strategy caches everything and supports flushes. Betwixt contains an alternative implementation that does not cache anything. Users that require more sophisticated caching strategies should create custom implementations.

The XMLBeanInfoRegistry can also be used to override the standard introspection mechanism on a per class basis. The safest way to do this is to create a custom XMLBeanInfoRegistry implementation that pre-loads XMLBeanInfo's for the required classes. If flush is called, the cache should be reset that it contains only those that it contained at the start.

Other XMLIntrospector Settings

Here are discussed the important settings that haven't been covered already.

The AttributesForPrimitives property determines whether a primitive type (including strings) should be - by default - mapped to elements or attributes. For example, a property called Age of a bean called PersonBean would be mapped to something like:

        <PersonBean>
            <age>21</age>
            ...
when isAttributesForPrimitives is false but to
        <PersonBean age='21'>
            ...
when it is true.

More finely grained control over which primitive properties are mapped to elements and which to attributes can be supplied by creating a custom SimpleTypeMapper strategy and plugging that into the introspection configuration.

Here is an example implementation (which maps strings to elements and everything else to attributes):

    
    /** Implementation binds strings to elements but everything else to attributes */
    public class StringsAsElementsSimpleTypeMapper extends SimpleTypeMapper {
        /**
         * Binds strings to elements but everything else to attributes
         */
        public Binding bind(
                            String propertyName, 
                            Class propertyType, 
                            IntrospectionConfiguration configuration) {
            if (String.class.equals(propertyType)) {
                return SimpleTypeMapper.Binding.ELEMENT;
            }
            return SimpleTypeMapper.Binding.ATTRIBUTE;
        }
    }

This class can be used to configure Betwixt so that strings are bounds to elements but other primitives are bound to attributes as follows:

     
        XMLIntrospector introspector = new XMLIntrospector();
        introspector.getConfiguration().setSimpleTypeMapper(
            new StringsAsElementsSimpleTypeMapper());
        ...

The WrapCollectionsInElement property determines whether the elements for a composite property (i.e. one that returns a collection or iterator) should be wrapped in a parent element. For example, if isWrapCollectionsInElement is true then a property with signature List getChildren() would wrap a <children> element around the elements representing the contents of the list.

Using .betwixt files To Read And Write Mixed Content

An element with mixed content contains child elements and text. For example, element foo has mixed content in the following:

<foo>
        Some text
        <bar/>
    </foo>
Betwixt supports writing mixed content through text elements in the .betwixt file.

A text element can be mapped to a property in which case it must have a property attribute and may (optionally) have a type attribute. Otherwise, the text element is mapped to a static value, in which case it must have a value attribute. If a text element has both value and property attributes then an exception will be thrown.

For example, a simple bean with the .betwixt file

<?xml version="1.0" encoding="UTF-8" ?>
<info primitiveTypes="attribute">
    <element name='foo'>
        <attribute name='version' value='1.0'/>
        <element name='bar'>
            <attribute name='version' property='alpha'/>
            <text value='static text'/>
            <element name='baa' property='beta'/>
            <text property='gamma'/>
        </element>
    </element>
</info>
and with property values alpha='One', beta='Two' and gamma='Three' will write an output like:
<foo version="1.0">
    <bar version="One">static text<baa>Two</baa>Three</bar>
</foo>

Betwixt supports reading back mixed content in one special situation which happily is also a common use case. Betwixt will call a single property with all the mixed content text. So, only one mixed content property is specified then the bean can be written and then read back.

Introspection And Normalization

When an Object is introspected by the XMLIntrospector, the class is examined and an XMLBeanInfo created based upon it. But there are occasions when some variation is needed - for example when reading or writing Entity Beans or Proxy implementations.

Betwixt provides the ClassNormalizer strategy class as a way to allow users to customise the process by which Betwixt works out which Class should be introspected for a given Object. The default implementation simply supplies the Class of the Object. But by setting the classNormalizer property of XMLIntrospector, a custom implementation can be used instead.

Betwixt supplies a second implementation called ListedClassNormalizer. This contains a list of classes to match together with the Class which should be returned when the Class is matched.

For example, take a class FaceImpl that implements an interface IFace. Betwixt will introspect every instance of FaceImpl as if it just implemented IFace by use of the following code:

        XMLIntrospector introspector = ...;
        ListedClassNormalizer classNormalizer = new ListedClassNormalizer();
        classNormalizer.addSubstitution( IFace.class );
        introspector.setClassNormalizer( classNormalizer );

Ignoring Properties

As well as the finely grained tuning available when using dot betwixt files, it is sometimes very useful to be able to ignore all properties with a certain name or a certain type. For example, the default Betwixt configuration ignores all properties called 'class'. The PropertySuppressionStrategy pluggable strategy can be set on the IntrospectionConfiguration and allows course grained rules concerning which properties are to be ignored to be set.

The following example shows a PropertySuppressionStrategy that shows all properties, including the class property:

beanWriter.getXMLIntrospector().getConfiguration().setPropertySuppressionStrategy(
        new PropertySuppressionStrategy() {
             public boolean suppressProperty(Class clazz, Class type, String name) {
                 return false;
             }
        });

Here is another example making the choice dependent on what class contains the property. This one shows the class property only for classes like Throwable, Exception, Error and so on:

beanWriter.getXMLIntrospector().getConfiguration().setPropertySuppressionStrategy(
        new PropertySuppressionStrategy() {
             public boolean suppressProperty(Class classContainingTheProperty,
                     Class propertyType, String propertyName) {
                 if (Class.class.equals(propertyType) 
                         && "class".equals(propertyName)) {
                         
                     if (!Throwable.class
                                .isAssignableFrom(classContainingTheProperty)) {
                        return true;
                     }
                 }
                 return false;
             }
         });

Mixed Collections - Guessing Element Names

A collection may contain objects of several different types. If you specify a name for the collections elements in the dot-betwixt-files (for these 'mixed' collections), you can't say by its XML element what kind of object it was. Therefore, by omitting the name-attribute for a collection in dot-betwixt-files, Betwixt will map each object contained in that collection separately.

As an example, we assume a small TestClass having only one property named col of type java.util.Collection. The collection contains object of different types. With a usual dot-betwixt-file we would expect to have all items in the collection be of the same element-type in the XML output. Now we omit the name and let Betwixt guess the names for the items in the collection:

  <?xml version="1.0" encoding="ISO-8859-15"?>
  <info primitiveTypes="element">
    <element name="test-class">
      <element name="mixed-collection">
         <element property="col"/> <!-- without name-attribute! -->
      </element>
    </element>
  </info>
The output would now look like:
  <test-class>
    <mixed-collection>
      <string>String x</string>
      <integer>5</integer>
      <another-class>
        ...
      </another-class>
    </mixed-collection>
  </test-class>
As you can see above the collection's items are named different depending on their type.

Writing To Inaccessible Setters

Betwixt finds the getter from the bean property. When a custom updater is specified, though, Betwixt uses reflection to find a matching method name. By default, Betwixt will only search for a public method with the correct name. This behaviour can be controlled through the dot betwixt file. The forceAccessible attribute of the element element allows this behaviour to be configured.

For example, consider a bean such as:

public class SomeBean {
    ...
    public SomeClass getSomeProperty() {
        ...
    }
    
    void setSomeProperty(SomeClass value) {
        ...
    }
    ...
}

By default, the setter would not be found. To ensure that the method is found, the following dot betwixt fragment could be used:

...
<element
    name='SomeName' 
    property='someProperty' 
    updater='setSomeProperty' <!-- this attribute must be present -->
    forceAccessible="true"/>  <!-- for this line to work -->
...

Note: when this attribute is set to true, Betwixt will conduct a search upwards through the superclasses if no matching methods are found in the implementation class. Also note that the updater must be specified even if the method conforms to JavaBean standards in order to override the accessibility. Overriding the accessibility of a method is subject to the SecurityManager currently in effect.

Converting Objects And Primitives To Strings (And Back Again)

Using ConvertUtils To Customize Conversion Of Primitives

ConvertUtils is part of commons-beanutils and it can be used to flexibly convert strings to objects and back again. By default, Betwixt uses ConvertUtils to perform these conversions and so standard ConvertUtils methods can be called to customize these conversions.

Converting Dates (And Other Objects)

There are numerous situations when read beans from xml or writing beans to xml that String to Object or Object to String conversions are required. Betwixt uses a Strategy class to allow a convenient default which will work well for most basic users whilst allowing advanced users to fully hook in and customize this process.

The default strategy uses ConvertUtils from commons-beanutils to perform these conversions. This is a powerful component that allows flexible customization of the conversion process.

There is one exception to this rule. If the class is a java.util.Date - or a subclass of java.util.Date which is not a subclass of java.sql.Date, java.sql.Time or java.sql.Timestamp - then this is converted to and from a string following this pattern:

    EEE MMM dd HH:mm:ss zzz yyyy
(using the SimpleDateFormat notation). Observant readers will realise that this is the same pattern that is returned by java.util.Date.toString - and that's why this pattern was chosen. It provides a good default for casual users.

Advanced users will probably need a particular date format. The recommended way to do this is through registering appropriate converters with ConvertUtils. The default conversion strategy must also be replaced with an instance of ConvertUtilsObjectStringConverter . This is set though a BindingConfiguration property.

For example, to delegate to ConvertUtils for all conversions in a read:

    BeanReader reader = new BeanReader();
    reader.getBindingConfiguration()
        .setObjectStringConverter(new ConvertUtilsObjectStringConverter());
    reader.parse...
and in a write:
    BeanWriter writer = new BeanWriter();
    writer.getBindingConfiguration()
        .setObjectStringConverter(new ConvertUtilsObjectStringConverter());
    writer.write...

Custom ObjectStringConverters (Advanced)

ConvertUtils is flexible and powerful. It comes with a range of Converter implementations which allow quick and easy customization. But, there are occasions where this will not suit all the requirements of the user. Betwixt supports this need by allowing a custom ObjectStringConverter to be plugged in.

The strategy class ObjectStringConverter is simple: containing only two simple methods. For more information about creating subclasses, see the javadocs. The implementation to be used is set through the BindingConfigurationObjectStringConverter property.

For example, to set a custom ObjectStringConverter for all conversions in a read:

    ObjectStringConverter converter = new MyObjectStringConverter();
    BeanReader reader = new BeanReader();
    reader.getBindingConfiguration(converter);
    reader.parse...
and in a write:
    ObjectStringConverter converter = new MyObjectStringConverter();
    BeanWriter writer = new BeanWriter();
    writer.getBindingConfiguration(converter);
    writer.write...

Betwixt is distributed with a range of ObjectStringConverter's in the org.apache.commons.betwixt.strategy package. Examining the source code for these classes is a good please to start when creating your own implementation.

Flavours For Custom Converters

One problem facing those who create custom converters is that objects of the same type may (in different contexts) require different conversions. For example, a java.util.Date may in one context have the semantic meaning of a day (and so the conversion needs to suppress the time component) and in another may indicate a date time (and so the conversion in this case needs to render the time components). The same type may come in different flavours.

The recommended way to solve this kind of problem is to added options to the betwixt file which can then be picked up by the custom converter and used to determine the appropriate conversion. Note that options are not directly inherited. Instead use getInheritedOption on Context.

For example, consider a bean representing a person with an attribute giving that person's date of birth. Suppose that this is stored as a java.util.Date. This needs to be rendered as a date string (without a time component). A good approach would be to add an option to the dot betwixt file as follows:

<?xml version='1.0'?>
<info primitiveTypes="attribute">
	<element name=''>
		<element name='birthday' property='birthday'>
			<option>
				<name>org.apache.commons.betwixt.flavour</name>
				<value>Day</value>
			</option>
		</element>
		<addDefaults/>
	</element>
</info>

The following code snippet illustrates how a custom converter can use this information:

    public String objectToString(Object object, Class type, Context context) {
        String flavour = null;
        Options options = context.getOptions();
        if (options != null) {
            flavour = options.getValue("org.apache.commons.betwixt.flavour");
        }

        if ("Day".equals(flavour)) {
            // render as date with no time component
            ...
        } else {
            // Do normal rendering
            ...
        }
    }

Of course, the choice of the option name is purely arbitrary.

Multi Mapping

Custom Dot Betwixt Documents

There are occasions when it proves useful to be able to override the standard loading behaviour for .betwixt mapping file. For example, this is one way in which multiple mapping for the same object can be supported (but see later sections for more sophisticated solutions to this problem).

Betwixt supports this by providing writing and reading methods which allow an InputSource specifying a .betwixt document to be passed in. For example:

     
        StringReader dotBetwixtDocument = new StringReader(
                "<?xml version='1.0' ?>" +
                "<info>" +
                "    <element name='address'>" +
...
                "    </element>" +
                "</info>");

        BeanReader reader = new BeanReader();
        reader.registerBeanClass(new InputSource(dotBetwixtDocument), Address.class);
        Address address = reader.parse(in);

        

parses the input document using the mapping specified in the string whilst:

     
        StringReader reader = new StringReader(
                "<?xml version='1.0' ?>" +
                "<info>" +
                "    <element name='address'>" +
...
                "    </element>" +
                "</info>");

        	
        BeanWriter writer;
...
        writer.write(bean, new InputSource(reader));

        

writes out a bean according to the mapping given in the string.

Multi Mapping Document Format

This xml document format extends the .betwixt vocabulary so that several different classes mapping can be registered by a single document. The mapping file format is an intuitive extension to the standard .betwixt format. The root element is <betwixt-config> which contains one or more <class> elements. Each of these specifies a class and contains a mapping definition for that class (as found in a standard dot betwixt document).

For example:

     
  <?xml version="1.0"?>
  <betwixt-config>
  <!--name of the class to map -->
   <class name="org.some.package.MyClass">
   <!-- standard definitions (same as in standard .betwixt file)    -->
     <element name="repository-registration-result">
       <element name="repository-id" property="repositoryId"/>
       <element name="id-mapping" property="idMapping" class="org.some.package.SomeOtherClass"/>
       <element name="status" property="status"/>
       <element name="exception" property="exception"/>
       <element name="primary-luid" property="primaryLuid"/>
       <addDefaults add-properties='false'/>
     </element>
   </class>
  ...
   <!--additional class mappings -->
   <class>
  ...
   </class>
  ...
  </betwixt-config>

    

Multi mappings are used directly to register multiple mappings with a single introspector. For example,

     
    String MAPPING = "<?xml version='1.0'?>" +
    		"     <betwixt-config>" +
    		"            <class name='org.apache.commons.betwixt.PartyBean'>" +
    		"    		    	<element name='party'>" +
...
    		"            </class>" +
...
    		"     </betwixt-config>";
    BeanReader beanReader = new BeanReader();
	beanReader.registerMultiMapping(new InputSource(new StringReader(MAPPING)));
    ...
    PartyBean result = (PartyBean)beanReader.parse(xmlReader);

        

registers all mappings in the file then reads beans according to those settings. The following does something similar for writing:

     
    String MAPPING = "<?xml version='1.0'?>" +
    		"     <betwixt-config>" +
    		"            <class name='org.apache.commons.betwixt.PartyBean'>" +
    		"    		    	<element name='party'>" +
...
    		"            </class>" +
...
    		"     </betwixt-config>";
		    BeanWriter beanWriter = new BeanWriter(outputWriter);
...
		    beanWriter.getXMLIntrospector()
                 .register(new InputSource(new StringReader(MAPPING)));
		    beanWriter.write(partyBean);

        

Multiple Mappings For The Same Object

Betwixt maps an entire object graph. So, though it might see (at first) that specifying a custom dot betwixt is all that's required, for all (but the most simple cases) several mappings must be specified to map the graph corrected. This is where multi mapping documents become very useful.

A common usage pattern for this problem is to use one XMLIntrospector for each of the different ways that the mappings should be done and register the mappings through a multi mapping file. All the reader and writers for that particular type can then share the same introspector.

(Brief) Guide To Creating Custom Strategy Plugins

It is common for users of Betwixt to need to develop their own custom strategies to handle some parts of the binding process. This section contains some information that may of of some use for those people. Help to create a more comprehensive guide would be appreciated.

Using Options

Options provide an extensible way for extra mapping information to be communicated from the binding to those components executing the mapping. Each Descriptor exposes an Options property . This contains a set of values indexed by name (both are strings). These options can be set programmatically during the binding. They can also be set through the .betwixt file.

Setting option values through the .betwixt file is easy: just add an <option> child element to an <element> element. For example, the XMLBeanInfo for the following betwixt file:


<?xml version='1.0'?>
<info primitiveTypes="attribute">
	<element name='some-bean'>
		<element name='some-property' property='someProperty'>
			<option>
				<name>org.apache.commons.betwixt.example-one</name>
				<value>value-one</value>
			</option>
		</element>
		<element name='another-property' property='anotherProperty'>
			<option>
				<name>org.apache.commons.betwixt.example-two</name>
				<value>value-two</value>
			</option>
		</element>
	</element>
</info>

will have the value value-one associated with the option name org.apache.commons.betwixt.example-one in the options for the some-property descriptor and value-two associated with org.apache.commons.betwixt.example-two for another-property. Note that the last value set for a particular option name is the one that will be used.

The recommended convention for naming option's is to prefix with the reverse domain name (the same convention that is used for the standard naming of packages). In any case, all option names beginning with org.apache should be avoided since these may be used by ASF products in the future.

At the moment, there is no support for inheritance of options (from parent to child) through this may be considered later if there is sufficient demand.