|  |  |  | 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.

<notice> Copyright © 1999-2005 ExoLab Group, Intalio Inc., and Contributors. All rights reserved. </notice>
<notice> 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. </notice>