ignore

Adding Converters

It is usually not necessary to create new converter annotations to use new converters. Data binders annotations should allow a Converter class to be explicitly specified. This class can be any custom Converter implementation that is appropriate for the binding operation. The limitation is that this converter cannot itself be parameterized in the binding annotation. To achieve this, you need to create a custom converter annotation.

As with validators and data binders, there are three steps to creating custom converter annotations.

  1. Write an implementation of Converter. Converter's form is as follows:

    public interface Converter<S extends Object, T extends Object>
    {
        public T toTargetType(S toConvert) throws ConversionException;
    
        public S toSourceType(T toConvert) throws ConversionException;
        
        public void setTargetClass(Class clazz);
    }
    

    Notice how the Converter interface is parameterized using generics, making it possible to implement a converter which converts back and forth from any two types. In practice, converters are probably more likely to use String as a source type, and some other object type as a target type.

    The methods toTargetType() and toSourceType() correspond with the inward and outward binding operations, that is, binding from form property to domain model, and vice versa. The setTargetClass() method can serve one of two purposes, depending on where it is used. Converters can either be generic in the sense that they can convert to and from a wide range of types, or type-specific. An example of a generic converter is the converter used by default by the data binders, SafeBeanUtilsConverter. This converter is capable of converting to quite a range of types. The actual conversion performed depends on the the class specified in the setTargetClass() method.

    The implementation of SafeBeanUtilsConverter is shown below. Behind the scenes, it uses Jakarta Commons BeanUtils.

    public class SafeBeanUtilsConverter implements Converter
    {
        private Class clazz;
    
        public void setTargetClass(Class clazz)
        {
            this.clazz = clazz;
        }
    
        public Object toTargetType(String toConvert) 
            throws ConversionException
        {
            Assert.notNull(clazz);
            
            if (!StringUtils.notBlankOrNull(toConvert))
                return null;
            
            Object convert = null;
            try
            {
                convert = BeanUtilsConverter.getInstance().
                	convert(toConvert, clazz);
            }
            catch (Exception e)
            {
                throw new ConversionException(e);
            }
            return convert;
        }
    
        public String toSourceType(Object toConvert) 
            throws ConversionException
        {
            Assert.notNull(clazz);
            
            if (toConvert == null)
                return null;
            
            String convert = null;
            try
            {
                convert = BeanUtilsConverter.
                    getInstance().convert(toConvert);
            }
            catch (Exception e)
            {
                throw new ConversionException(e);
            }
            return convert;
        }
    }
    

    Other converters, such as DatePatternConverter, are designed only to work with particular target types. Specifically, DatePatternConverter implements Converter<String, Date>. In this case, the setTargetClass() method can be used to perform a runtime check to ensure that the target class's type is appropriate for the conversion being attempted, as shown below:

    public void setTargetClass(Class clazz)
    {
        if (!clazz.equals(Date.class))
        {
            throw new IllegalArgumentException(
                "Converter will only convert to and from java.util.Date instances");
        }
    }
    
  2. Next, a converter annotation is required. The converter annotation identifies a factory class and provides any additional parameters required to configure the Converter. The @ConvertDate annotation is shown below:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @ConverterFactoryClass(DateConverterFactory.class)
    public @interface ConvertDate
    {
        String pattern();
    }
    

    Apart from identifying the factory class, the only additional information provided by the annotation is the textual pattern used for the conversion.

  3. Finally, we need to provide an implementation of the ConverterFactory, which in our example above is DateConverterFactory. The implementation is very simple and is shown below:
    public class DateConverterFactory implements ConverterFactory
    {
        public Converter createConverter(Annotation annotation)
        {
            ConvertDate annot = (ConvertDate) annotation;
            DatePatternConverter converter = 
                new DatePatternConverter(annot.pattern());
            converter.setTargetClass(Date.class);
            return converter;
        }
    }
    

    Apart from instantiating the converter, the only function performed by this ConverterFactory is providing the converter with a pattern String.

SourceForge.net logo java.net Member logo Copyright © 2005-2007 Realsolve Solutions