Data binders contain the glue code necessary for implementing a data binding operation, which itself typically involves reflective getter and setter operations as well as some data type conversion(s). Adding data binders follows a similar mechanism to adding validators, and again, is applied in three steps.
Write an implementation of BindHandler
. BindHandler
has the following form:
public interface BindHandler { public void bindInwards(Object source, Object target, Object convertedValue); public void bindOutwards(Object source, Object target); public Converter getConverter(); }
The method bindInwards()
is called when binding from a form property to a domain model object property.
bindOutwards()
is called when the reverse operation occurs. In both cases, the source object refers to
the source object from which inward binding occurs, i.e. the ActionForm
implementation.
The target object refers to the object from which the target binding expressions are referenced.
Currently, this is also the ActionForm
, although in the future it is likely to be possible to
bind directly to an object referenced from an action bean.
getConverter()
returns the data type converter that
has been configured to work with the BindHandler
.
Note that the arguments of bindInwards()
and bindOutwards()
only provide request-specific
information.
While creating a BindHandler
is not especially difficult, it is not as simple as
creating a new validator or converter.
The best starting point is to examine the existing implementations:
BindSimple
and BindSelect
.
Create an annotation for the bind handler.
The annotation should include attributes for all the information
required to create and configure a BindHandler
instance.
Consider the @BindSimple
annotation, shown below:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @BindFactoryClass(BindSimpleFactory.class) public @interface BindSimple { String expression(); Class<? extends Converter> converter() default SafeBeanUtilsConverter.class; }
This annotation includes three pieces of information. First, the bind factory class
(BindSimpleFactory
)
which has the intelligence to create a BindHandler
from information provided in the annotation.
Second, a binding expression is needed. Finally, a Converter
class can be specified if necessary.
The converter is used to perform type conversions.
Next, we need to provide an implementation of the BindHandlerFactory specified in our new annotation's @BindFactoryClass annotation. BindHandlerFactory has the following form.
public interface BindHandlerFactory { public BindHandler createHandler(Annotation annotation, Method getterMethod, Converter converter, ConversionHandler conversionHandler); }
The arguments include a reference to the getter method containing the annotation,
the converter, and a ConversionHandler
instance,
which the BindHandler
implementation
can use to calls the Converter
methods.
BindHandlerFactory
returns a BindHandler
instance, which should be configured with all the information required
to handle request-initiated binding operations.