You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by rd...@apache.org on 2003/08/14 23:25:26 UTC

cvs commit: jakarta-commons/betwixt/xdocs/guide binding.xml

rdonkin     2003/08/14 14:25:26

  Added:       betwixt/xdocs/guide binding.xml
  Log:
  Split Overview into separate documents in guide directory.
  
  Revision  Changes    Path
  1.1                  jakarta-commons/betwixt/xdocs/guide/binding.xml
  
  Index: binding.xml
  ===================================================================
  <?xml version="1.0"?>
  
  <document>
  
   <properties>
    <title>Binding Bean To XML</title>
    <author email="jstrachan@apache.org">James Strachan</author>
   </properties>
  
  <body>
  
  <section name="Bean Naming Conventions">
  
      <p>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.
      </p>
      
      <p>
      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 <code>WebApp</code> might need to be mapped to an element called <code>web-app</code>.
      </p>
      
      <p>
      Betwixt supports customization of these mappings through plug-in implementations of the 
      <code>org.apache.commons.betwixt.strategy.NameMapper</code> 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.
      </p>
      
      <p>
      <strong>Note</strong> that the attribute and element names given in a .betwixt file (as usual)
      override the name mapping settings on the <code>XMLIntrotrospector</code>.
      </p>
  
  <subsection name="Using A Custom Type Name To Element Name Mapping">
  
      <p>
      Betwixt supports pluggable conversion of type names to element names. Setting the 
      <code>ElementNameMapper</code> property on an <code>XMLIntrospector</code> determines
      how names from the bean will be converted into element names.
      </p>
  
  </subsection>
  
  
  <subsection name="Using A Custom Property Name To Attribute Name Mapping">
  
      <p>
      Betwixt supports pluggable conversion of type names to attribute names. Setting the 
      <code>AttributeNameMapper</code> property on an <code>XMLIntrospector</code> determines
      how names from the bean will be converted into attribute names.
      </p>
  
  </subsection>
  
  <subsection name="Custom Mapping Example">
  
      <p>
      Here's a simple bean which will be mapped to xml:
      
  <source><![CDATA[
  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;
      }
  }	
  ]]></source>
  
      </p>
      <p>
      Next is an application that writes that bean to xml. Custom name mappers for elements
      and attributes are set.
      
  <source><![CDATA[
  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("");
      }
      
  }
  ]]></source>
      </p>
      
      <p>
      The application should print out (to System.out) an xml fragment which looks like:
      
  <source><![CDATA[
  <tallTreeBean height-of-tree="15.1"/>
  ]]></source>
      
      </p>
      <p>
      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.
      </p>
  </subsection>
  
  </section>
  
  <section name="Using Adder Methods For Composite Properties">
  
      <p>
      This naming convention is used to indicate the singular type of some composite property.
      </p>
      
      <p>
      To use: create an add method to match the getter method for 'composite 
      properties'.
      </p>
  
  <source><![CDATA[public class SomeBean {
      public <CollectionType> getFoo*();
      public void addFoo(<SingularType> foo);
  }]]></source>
  
      <p>
      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.
      </p>
  
  <subsection name="Using A Custom Plural Stemmer">
      <p>
      Betwixt allows this auto-detection of plurals from singulars to be customized.
      Implementations of <code>org.apache.commons.betwixt.PluralStemmer</code> allow different
      strategies for this mapping to be plugged into <code>XMLIntrospector</code>.
      The strategy used by <code>XMLIntrospector</code> to match singlular properties and plural methods
      is determined by the <code>PluralStemmer</code> property value.
      </p>
  
      <p>
      One important usage of custom plural stemmers is to support classes with non-english method names.
      A custom <code>PluralStemmer</code> implementation can be created containing the plural rules for
      the language. Betwixt will then be able to recognize matching plural and singular methods.
      </p>
  
      <p>
      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
      <code>FooBars</code> for a singular property called <code>FooBar</code>. 
      </p>
  </subsection>
  
  <subsection name="Reading And Writing Map Properties">
      <p>
  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 <code>&lt;entry&gt;</code> element. That element contains the key wrapped in a <code>&lt;key&gt;</code>
  element and the entry value wrapped in a <code>&lt;value&gt;</code> element.
          </p>
      <p>
  The structure is something like:
  <source><![CDATA[
      ...
      <entry>
          <key>...</key>
          <value>...</value>
      <entry>
      <entry>
          <key>...</key>
          <value>...</value>
      <entry>
      ...
  ]]></source>
  The key and the value content are standard betwixt mappings of the objects.
          </p>
      <p>
  Reading map properties is an extension of the ways that Betwixt handles collections. Rather than 
  searching for an <code>add*</code> method that takes a single parameter, now Betwixt looks 
  (in a similar fashion) for such a method that takes two parameters.
          </p> 
  </subsection>
  
  </section>
  
  <section name="Customized Mapping (Advanced)">
  
  <subsection name="Caching and the XMLRegistry">
      
      <p>
      Introspection is slow and so caching the results improves preformance. Though the writers 
      and readers can - by nature - only be used safely in a single thread, a single 
      <code>XMLIntrospector</code> instance can be safely shared amongst multiple threads. Sharing a
      single instance will improve performance by sharing it's <code>XMLBeanInfo</code> cache.
      </p>
      
      <p>
      The <code>XMLBeanInfoRegistry</code> interface allows finely grained, pluggable control over 
      the caching strategy used by a <code>XMLIntrospector</code>. The implementation used can be set
      by passing an instance to <code>XMLIntrospector.setRegistry</code>.
      </p>
      
      <p>
      Before using the standard introspection techniques to create a new <code>XMLBeanInfo</code> instance
      for a bean, the current <code>XMLBeanInfoRegistry</code> is first checked. Only if the registry 
      does not return an <code>XMLBeanInfo</code> will a new one be created. Once a new instance has been
      created by introspection, the <code>XMLBeanInfoRegistry</code> implementation will be called so that
      the <code>XMLBeanInfo</code> can (if required) be cached.
      </p>
      
      <p>
      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.
      </p>
      
      <p>
      The <code>XMLBeanInfoRegistry</code> 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 <code>XMLBeanInfoRegistry</code> 
      implementation that pre-loads <code>XMLBeanInfo</code>'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. 
      </p>
  
  </subsection>
  
  <subsection name="Other XMLIntrospector Settings">
      
      <p>
      Here are discussed the important settings that haven't been covered already. 
      </p>
      
      <p>
      The <strong><code>AttributesForPrimitives</code></strong> property determines whether a primitive
      type (including strings) should be - by default - mapped to elements or attributes. For example, a
      property called <code>Age</code> of a bean called <code>PersonBean</code> would be mapped to something
      like:
      
  <source><![CDATA[
          <PersonBean>
              <age>21</age>
              ...
  ]]></source>
      
      when <code>isAttributesForPrimitives</code> is false but to 
      
  <source><![CDATA[
          <PersonBean age='21'>
              ...
  ]]></source>
      
      when it is true.
      </p>
      
      <p>
      The <strong><code>WrapCollectionsInElement</code></strong> property determines whether the elements 
      for a composite property (ie one that returns a collection or iterator) should be wrapped in a parent
      element. For example, if <code>isWrapCollectionsInElement</code> is true then a property with signature 
      <code>List getChildren()</code> would wrap a <code>&lt;children&gt;</code> element around the elements
      representing the contents of the list.
      </p>
  </subsection>
  
  <subsection name="Using .betwixt files To Read And Write Mixed Content">
      <p>
      An element with mixed content contains child elements and text. 
      For example, element <code>foo</code> has mixed content in the following:
  <source>
  <![CDATA[<foo>
          Some text
          <bar/>
      </foo>]]>
  </source>
      Betwixt supports writing mixed content through <code>text</code> elements in the 
      .betwixt file. 
      </p>
      
      <p>
      A <code>text</code> element can be mapped to a property in which case it must have
      a <code>property</code> attribute and may (optionally) have a <code>type</code> attribute.
      Otherwise, the <code>text</code> element is mapped to a static value, in which case it
      must have a <code>value</code> attribute. If a <code>text</code> element has both 
      <code>value</code> and <code>property</code> attributes then an exception will be thrown.
      </p>
      
      <p>
      For example, a simple bean with the .betwixt file 
  <source><![CDATA[<?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>]]>
  </source>
      and with property values alpha='One', beta='Two' and gamma='Three' will write an output like:
  <source>
  <![CDATA[<foo version="1.0">
      <bar version="One">static text<baa>Two</baa>Three</bar>
  </foo>
  ]]></source>
      </p>
          <p>
  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.
      </p>
  </subsection>
  
  <subsection name='Using ConvertUtils To Customize Conversion Of Primitives'>
          <p>
  <code>ConvertUtils</code> is part of <a href='http://jakarta.apache.org/commons/beanutils.html'>commons-beanutils</a>
  and it can be used to flexibly convert strings to objects and back again. Betwixt uses ConvertUtils to 
  perform these conversions and so standard <code>ConvertUtils</code> methods can be called to customize these 
  conversions.
      </p>
  </subsection>
  
  </section>
  
  </body>
  </document>