License     Codehaus     OpenEJB     OpenJMS     OpenORB     Tyrex     

Old releases
  General
  Release 1.3
  Release 1.3rc1
  Release 1.2

Main
  Home
  About
  Features
  Download
  Dependencies
  Reference guide
  Publications
  JavaDoc
  Maven 2 support
  Maven 2 archetypes
  DTD & Schemas
  Recent HTML changes
  News Archive
  RSS news feed
  Project Wiki

Development/Support
  Mailing Lists
  SVN/JIRA
  Contributing
  Support
  Continuous builds
  Prof. services

Related projects
  Spring ORM support
  Spring XML factories
  WS frameworks

XML
  XML

XML Code Generator
  XML Code Generator

JDO
  Introduction
  First steps
  Using JDO
  JDO Config
  Types
  JDO Mapping
  JDO FAQ
  JDO Examples
  JDO HOW-TOs
  Tips & Tricks
  Other Features
  JDO sample JAR

Tools
  Schema generator

Advanced JDO
  Caching
  OQL
  Trans. & Locks
  Design
  KeyGen
  Long Trans.
  Nested Attrs.
  Pooling Examples
  LOBs
  Best practice

DDL Generator
  Using DDL Generator
  Properties
  Ant task
  Type Mapping

More
  The Examples
  3rd Party Tools
  JDO Tests
  XML Tests
  Configuration
 
 

About
  License
  User stories
  Contributors
  Marketplace
  Status, Todo
  Changelog
  Library
  Contact
  Project Name

  



How to write a ConfigurableFieldHandler


Intended Audience
When (not) to use ConfigurableFieldHandler
Implement your ConfigurableFieldHandler
Define and use the handler


Intended Audience

Anyone who wants to write a configurable field hander.

When (not) to use ConfigurableFieldHandler

If you want to have a custom FieldHandler that works in a fixed manner, you should consider subclassing GeneralizedFieldHandler , or implementing FieldHandler.

However if you want your FieldHandler to operate more flexibly, based on configuration, ConfigurableFieldHandler may be what you're looking for.

Implement your ConfigurableFieldHandler

Basically, two approaches exist for implementing a configurable field handler.

The most straightforward one is simply to implement the ConfigurableFieldHandler interface. This interface extends the FieldHandler interface.

The other approach is to subclass any of the convenience FieldHandler implementations. These are AbstractFieldHandler and GeneralizedFieldHandler. Both classes already implement the ConfigurableFieldHandler interface, so you don't have to implement it yourself explicitly. However the implementation of the single ConfigurableFieldHandler method (setConfiguration) is an empty method. So you'd have to override this method yourself in order to do something useful with the configuration.

The two approaches differ only marginally. If the convenience classes provide useful functionality for you, you'd probably be better off using them. Otherwise simply implementing the ConfigurableFieldHandler interface is a good choice.

For this exercise, we choose to implement the ConfigurableFieldHandler, and decide to convert dates, using a configurable date pattern:

FieldHandlerImpl.java
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import org.exolab.castor.mapping.ConfigurableFieldHandler;
import org.exolab.castor.mapping.ValidityException;

public class FieldHandlerImpl implements ConfigurableFieldHandler {

    private SimpleDateFormat formatter;

    public FieldHandlerImpl() {
    	//
    }

    /**
     * Sets the configuration for this field handler. The config object is supposed to have one
     * property, named "date-format", with a date format pattern compatible with 
     * java.text.SimpleDateFormat.
     * 
     * @param config the configuration object.
     * @throws ValidityException if config doesn't have the required parameter, or if the parameter
     *      value is not a valid date pattern.
     */    
    public void setConfiguration(Properties config) throws ValidityException {
    	String pattern = config.getProperty("date-format");
    	if (pattern == null) {
    		throw new ValidityException("Required parameter \"date-format\" is missing for CustomDateFieldHandler.");
    	}
    	try {
    		formatter = new SimpleDateFormat(pattern);
    	} catch (IllegalArgumentException e) {
    		throw new ValidityException("Pattern \""+pattern+"\" is not a valid date format.");
    	}
    }

    /**
     * Returns the value of the field from the object.
     *
     * @param object The object
     * @return The value of the field
     * @throws IllegalStateException The Java object has changed and
     *  is no longer supported by this handler, or the handler is not
     *  compatible with the Java object
     */
    public Object getValue( Object object )
        throws IllegalStateException
    {
        Root root = (Root)object;
        Date value = root.getDate();
        if (value == null) return null;
        return formatter.format(value);
    }

    /**
     * Sets the value of the field on the object.
     *
     * @param object The object
     * @param value The new value
     * @throws IllegalStateException The Java object has changed and
     *  is no longer supported by this handler, or the handler is not
     *  compatible with the Java object
     * @throws IllegalArgumentException The value passed is not of
     *  a supported type
     */
    public void setValue( Object object, Object value )
        throws IllegalStateException, IllegalArgumentException
    {
        Root root = (Root)object;
        Date date = null;
        try {
            date = formatter.parse((String)value);
        }
        catch(ParseException px) {
            throw new IllegalArgumentException(px.getMessage());
        }
        root.setDate(date);

    }
    
    /**
     * Creates a new instance of the object described by this field.
     *
     * @param parent The object for which the field is created
     * @return A new instance of the field's value
     * @throws IllegalStateException This field is a simple type and
     *  cannot be instantiated
     */
    public Object newInstance( Object parent )
        throws IllegalStateException
    {
        //-- Since it's marked as a string...just return null,
        //-- it's not needed.
        return null;
    }

    /**
     * Sets the value of the field to a default value.
     *
     * Reference fields are set to null, primitive fields are set to
     * their default value, collection fields are emptied of all
     * elements.
     *
     * @param object The object
     * @throws IllegalStateException The Java object has changed and
     *  is no longer supported by this handler, or the handler is not
     *  compatible with the Java object
     */
    public void resetValue( Object object )
        throws IllegalStateException, IllegalArgumentException
    {
        ((Root)object).setDate(null);
    }

    /**
     * @deprecated No longer supported
     */
    public void checkValidity( Object object )
        throws ValidityException, IllegalStateException
    {
        // do nothing
    }
}

For a ConfigurableFieldHandler, we have to override the method setConfiguration of the superclass AbstractFieldHandler. AbstractFieldHandler implements this method on behalf of the ConfigurableFieldHandler interface, but does not do anything.

Define and use the handler

All we have to do now is define the ConfigurableFieldHandler in the mapping file (using a <field-handler> element), configure it, and use it in some xml field.

mapping.xml
<?xml version="1.0"?>
<mapping>
   
   <field-handler name="myHandler" class="org.some.package.CustomFieldHandlerImpl">
      <param name="date-format" value="yyyyMMddHHmmss"/>
   </field-handler>
   
   <class name="Root">
      <field name="date" type="string" handler="myHandler"/>
   </class>

</mapping>

This mapping file defines a custom configurable field handler instance named "myHandler", of the type we've just implemented, and configures it with some fancy date pattern. A regular class mapping defines a field called "date", and specifies that conversion to and from this field will be performed by the "myHandler" instance.

It would be perfectly legal to use "myHandler" for other fields as well, and also to define other field-handler instances of the class FieldHandlerImpl (or any other class).

To complete the example, here's the "Root" class that is used in the example mapping file:

Root.java
import java.util.Date;

public class Root {

    private Date _date = null;

    public Root() {
    }

    public Date getDate() {
        return _date;
    }

    public void setDate(Date date) {
       this._date = date;
    }

}

And here a sample XML document:

Sample XML document
<?xml version="1.0" encoding="UTF-8"?>
<root>
   <date>20070711234859</date>
</root>

With these classes, xml mapping file and xml sample file, you should be able to marshall and unmarshall the date field.

 
   
  
   
 


Copyright © 1999-2005 ExoLab Group, Intalio Inc., and Contributors. All rights reserved.
 
Java, EJB, JDBC, JNDI, JTA, Sun, Sun Microsystems are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and in other countries. XML, XML Schema, XSLT and related standards are trademarks or registered trademarks of MIT, INRIA, Keio or others, and a product of the World Wide Web Consortium. All other product names mentioned herein are trademarks of their respective owners.