Validation, Data-binding, the BeanWrapper, and PropertyEditorsIntroductionThere are pros and cons for considering validation as business logic,
and Spring offers a design for validation (and data binding) that
does not exclude either one of them. Specifically validation should not be
tied to the web tier, should be easy to localize and it should be
possible to plug in any validator available. Considering the above, Spring
has come up with a Validator interface that
is both basic and eminently usable in every layer of an application.Data binding is useful for allowing user input to be dynamically
bound to the domain model of an application (or whatever objects you use
to process user input). Spring provides the so-called
DataBinder to do exactly that. The
Validator and the
DataBinder make up the validation package,
which is primarily used in but not limited to the MVC framework.The BeanWrapper is a fundamental concept in the
Spring Framework and is used in a lot of places. However, you probably
will not ever have the need to use the BeanWrapper directly. Because this
is reference documentation however, we felt that some explanation might be
in order. We're explaining the BeanWrapper in this chapter since if you were
going to use it at all, you would probably do so when trying to bind
data to objects, which is strongly related to the BeanWrapper.Spring uses PropertyEditors all over the place. The concept of a
PropertyEditor is part of the JavaBeans specification. Just as the
BeanWrapper, it's best to explain the use of PropertyEditors in this
chapter as well, since it's closely related to the BeanWrapper and the
DataBinder.Validation using Spring's Validator interfaceSpring's features a Validator interface that you can
use to validate objects. The Validator interface works using
an Errors object so that while validating, validators can report
validation failures to the Errors object.Let's consider a small data object:// the usual getters and setters...We're going to provide validation behavior for the Person
class by implementing the following two methods of the
org.springframework.validation.Validator interface:
supports(Class) - Can this
Validator validate instances of the supplied
Class?validate(Object, org.springframework.validation.Errors) -
validates the given object and in case of validation errors, registers
those with the given Errors object
Implementing a Validator is fairly straightforward,
especially when you know of the ValidationUtils helper class
that the Spring Framework also provides./**
* This Validator validates justPerson instances
*/ 110) {
e.rejectValue("age", "too.darn.old");
}
}
}]]>As you can see, the staticrejectIfEmpty(..)
method on the ValidationUtils class is used to reject the
'name' property if it is null or the empty string.
Have a look at the Javadoc for the ValidationUtils class to see
what functionality it provides besides the example shown previously.While it is certainly possible to implement a single
Validator class to validate each of the nested objects
in a rich object, it may be better to encapsulate the validation logic for each nested
class of object in its own Validator implementation. A
simple example of a 'rich' object would be a
Customer that is composed of two String
properties (a first and second name) and a complex Address object.
Address objects may be used independently of
Customer objects, and so a distinct
AddressValidator has been implemented. If you want your
CustomerValidator to reuse the logic contained within the
AddressValidator class without recourse to copy-n-paste you can
dependency-inject or instantiate an AddressValidator within your
CustomerValidator, and use it like so:/**
* This Validator validates Customer instances, and any subclasses of Customer too
*/Validation errors are reported to the Errors
object passed to the validator. In case of Spring Web MVC you can use
<spring:bind/> tag to inspect the error messages, but
of course you can also inspect the errors object yourself. More information about
the methods it offers can be found from the Javadoc.Resolving codes to error messagesWe've talked about databinding and validation. Outputting messages corresponding to
validation errors is the last thing we need to discuss. In the example we've shown
above, we rejected the name and the age field.
If we're going to output the error messages by using a MessageSource,
we will do so using the error code we've given when rejecting the field ('name' and 'age'
in this case). When you call (either directly, or indirectly, using for example the
ValidationUtils class) rejectValue or one of
the other reject methods from the Errors
interface, the underlying implementation will not only register the code you've
passed in, but also a number of additional error codes. What error codes it registers
is determined by the MessageCodesResolver that is used.
By default, the DefaultMessageCodesResolver is used, which for example
not only registers a message with the code you gave, but also messages that include the
field name you passed to the reject method. So in case you reject a field using
rejectValue("age", "too.darn.old"), apart from the
too.darn.old code, Spring will also register
too.darn.old.age and too.darn.old.age.int
(so the first will include the field name and the second will include the type of the
field); this is done as a convenience to aid developers in targeting error
messages and suchlike.More information on the MessageCodesResolver and the default
strategy can be found online with the Javadocs for
MessageCodesResolver
and
DefaultMessageCodesResolver
respectively.Bean manipulation and the BeanWrapperThe org.springframework.beans package adheres to
the JavaBeans standard provided by Sun. A JavaBean is simply a class with
a default no-argument constructor, which follows a naming convention
where (by way of an example) a property named bingoMadness would have a setter
method setBingoMadness(..) and a getter method getBingoMadness().
For more information about JavaBeans and the specification, please refer
to Sun's website ( java.sun.com/products/javabeans).One quite important class in the beans package is the
BeanWrapper interface and its corresponding
implementation (BeanWrapperImpl). As quoted from the
Javadoc, the BeanWrapper offers functionality to set and get property
values (individually or in bulk), get property descriptors, and to query
properties to determine if they are readable or writable. Also, the
BeanWrapper offers support for nested properties, enabling the setting of
properties on sub-properties to an unlimited depth. Then, the BeanWrapper
supports the ability to add standard JavaBeans
PropertyChangeListeners and
VetoableChangeListeners, without the need for
supporting code in the target class. Last but not least, the BeanWrapper
provides support for the setting of indexed properties. The BeanWrapper
usually isn't used by application code directly, but by the
DataBinder and the
BeanFactory.The way the BeanWrapper works is partly indicated by its name:
it wraps a bean to perform actions on that bean, like
setting and retrieving properties.Setting and getting basic and nested propertiesSetting and getting properties is done using the
setPropertyValue(s) and
getPropertyValue(s) methods that both come with a
couple of overloaded variants. They're all described in more detail in
the Javadoc Spring comes with. What's important to know is that there
are a couple of conventions for indicating properties of an object. A
couple of examples:
Examples of propertiesExpressionExplanationnameIndicates the property name
corresponding to the methods getName() or
isName() and
setName(..)account.nameIndicates the nested property name
of the property account corresponding e.g.
to the methods getAccount().setName() or
getAccount().getName()account[2]Indicates the third element of the
indexed property account. Indexed
properties can be of type array,
list or other naturally
ordered collectionaccount[COMPANYNAME]Indicates the value of the map entry indexed by the key
COMPANYNAME of the Map property
account
Below you'll find some examples of working with the BeanWrapper to
get and set properties.(This next section is not vitally important to you if you're not
planning to work with the BeanWrapper directly. If you're
just using the DataBinder and the
BeanFactory and their out-of-the-box implementation, you
should skip ahead to the section about
PropertyEditors.)Consider the following two classes:The following code snippets show some examples of how to retrieve
and manipulate some of the properties of instantiated
Companies and Employees:// setting the company name..// ... can also be done like this:// ok, let's create the director and tie it to the company:// retrieving the salary of the managingDirector through the companyBuilt-in PropertyEditor implementationsSpring heavily uses the concept of PropertyEditors to effect the conversion
between an Object and a String. If you think about it,
it sometimes might be handy to be able to represent properties in a different way than the object itself.
For example, a Date can be represented in a human readable way (as the
String '2007-14-09'), while we're still able to convert the
human readable form back to the original date (or even better: convert any date entered in a human readable
form, back to Date objects). This behavior can be achieved by
registering custom editors, of type java.beans.PropertyEditor.
Registering custom editors on a BeanWrapper or alternately in a specific IoC
container as mentioned in the previous chapter, gives it the knowledge of how to convert properties to the
desired type. Read more about PropertyEditors in the Javadoc of the
java.beans package provided by Sun.A couple of examples where property editing is used in Spring:
setting properties on beans is done
using PropertyEditors. When mentioning
java.lang.String as the value of a property of
some bean you're declaring in XML file, Spring will (if the setter
of the corresponding property has a Class-parameter) use the
ClassEditor to try to resolve the parameter to
a Class object.parsing HTTP request parameters in
Spring's MVC framework is done using all kinds of PropertyEditors
that you can manually bind in all subclasses of the
CommandController.Spring has a number of built-in PropertyEditors to make life easy.
Each of those is listed below and they are all located in the
org.springframework.beans.propertyeditors package. Most, but not all (as indicated below),
are registered by default by BeanWrapperImpl. Where the property editor is configurable
in some fashion, you can of course still register your own variant to override the default one:
Built-in PropertyEditorsClassExplanationByteArrayPropertyEditorEditor for byte arrays. Strings will simply be
converted to their corresponding byte representations.
Registered by default by BeanWrapperImpl.ClassEditorParses Strings representing classes to actual classes
and the other way around. When a class is not found, an
IllegalArgumentException is thrown. Registered by default by
BeanWrapperImpl.CustomBooleanEditorCustomizable property editor for Boolean properties.
Registered by default by BeanWrapperImpl, but, can be
overridden by registering custom instance of it as custom
editor.CustomCollectionEditorProperty editor for Collections, converting any source
Collection to a given target Collection type.CustomDateEditorCustomizable property editor for java.util.Date,
supporting a custom DateFormat. NOT registered by default. Must
be user registered as needed with appropriate format.CustomNumberEditorCustomizable property editor for any Number subclass
like Integer, Long,
Float, Double. Registered
by default by BeanWrapperImpl, but can be
overridden by registering custom instance of it as a custom editor.FileEditorCapable of resolving Strings to
java.io.File objects. Registered by default by
BeanWrapperImpl. InputStreamEditorOne-way property editor, capable of taking a text
string and producing (via an intermediate ResourceEditor and
Resource) an
InputStream, so InputStream
properties may be directly set as Strings. Note that the default usage
will not close the InputStream for
you! Registered by default by BeanWrapperImpl.LocaleEditorCapable of resolving Strings to
Locale objects and vice versa (the String
format is [language]_[country]_[variant], which is the same
thing the toString() method of Locale provides). Registered by
default by BeanWrapperImpl.PatternEditorCapable of resolving Strings to JDK 1.5
Pattern objects and vice versa.PropertiesEditorCapable of converting Strings (formatted using the
format as defined in the Javadoc for the java.lang.Properties
class) to Properties objects. Registered by
default by BeanWrapperImpl.StringTrimmerEditorProperty editor that trims Strings. Optionally allows
transforming an empty string into a null value. NOT
registered by default; must be user registered as needed.URLEditorCapable of resolving a String representation of a URL
to an actual URL object. Registered by
default by BeanWrapperImpl.
Spring uses the java.beans.PropertyEditorManager to set
the search path for property editors that might be needed. The search path also includes
sun.bean.editors, which includes
PropertyEditor implementations for types such as
Font, Color, and most of the primitive types.
Note also that the standard JavaBeans infrastructure will automatically discover
PropertyEditor classes (without you having to register them
explicitly) if they are in the same package as the class they handle, and have the same name
as that class, with 'Editor' appended; for example, one could have the
following class and package structure, which would be sufficient for the
FooEditor class to be recognized and used as the
PropertyEditor for Foo-typed
properties.
// the PropertyEditor for the Foo classNote that you can also use the standard BeanInfo JavaBeans
mechanism here as well (described
in not-amazing-detail here).
Find below an example of using the BeanInfo mechanism for
explicitly registering one or more PropertyEditor instances
with the properties of an associated class.// the BeanInfo for the Foo class
Here is the Java source code for the referenced FooBeanInfo class. This
would associate a CustomNumberEditor with the age
property of the Foo class.
Registering additional custom PropertyEditorsWhen setting bean properties as a string value, a Spring IoC container
ultimately uses standard JavaBeans PropertyEditors to convert these
Strings to the complex type of the property. Spring pre-registers a number
of custom PropertyEditors (for example, to convert a classname expressed
as a string into a real Class object). Additionally, Java's standard
JavaBeans PropertyEditor lookup mechanism allows a
PropertyEditor for a class simply to be named appropriately and
placed in the same package as the class it provides support for, to be found automatically.If there is a need to register other custom PropertyEditors, there
are several mechanisms available. The most manual approach, which is not normally convenient or
recommended, is to simply use the registerCustomEditor() method of the
ConfigurableBeanFactory interface, assuming you have a
BeanFactory reference. Another, slightly more convenient, mechanism is to use
a special bean factory post-processor called CustomEditorConfigurer.
Although bean factory post-processors can be used with BeanFactory
implementations, the CustomEditorConfigurer has a nested property setup, so it is
strongly recommended that it is used with the ApplicationContext, where
it may be deployed in similar fashion to any other bean, and automatically detected and applied.Note that all bean factories and application contexts automatically use a number of built-in property
editors, through their use of something called a BeanWrapper to handle
property conversions. The standard property editors that the BeanWrapper
registers are listed in the previous section. Additionally,
ApplicationContexts also override or add an additional number of editors
to handle resource lookups in a manner appropriate to the specific application context type.Standard JavaBeans PropertyEditor instances are used to convert
property values expressed as strings to the actual complex type of the property.
CustomEditorConfigurer, a bean factory post-processor, may be used to conveniently
add support for additional PropertyEditor instances to an
ApplicationContext.Consider a user class ExoticType, and another class
DependsOnExoticType which needs ExoticType set as a property:When things are properly set up, we want to be able to assign the type property as a string, which a
PropertyEditor will behind the scenes convert into an actual
ExoticType instance:
]]>The PropertyEditor implementation could look similar to this:// converts string representation to ExoticType objectFinally, we use CustomEditorConfigurer to register the new
PropertyEditor with the ApplicationContext,
which will then be able to use it as needed:
]]>Using PropertyEditorRegistrarsAnother mechanism for registering property editors with the Spring container is to create and use
a PropertyEditorRegistrar. This interface is particularly useful when you
need to use the same set of property editors in several different situations: write a corresponding
registrar and reuse that in each case. PropertyEditorRegistrars work in conjunction
with an interface called PropertyEditorRegistry, an interface
that is implemented by the Spring BeanWrapper (and
DataBinder). PropertyEditorRegistrars are particularly
convenient when used in conjunction with the CustomEditorConfigurer
(introduced here), which exposes a
property called setPropertyEditorRegistrars(..):
PropertyEditorRegistrars added to a CustomEditorConfigurer in this
fashion can easily be shared with DataBinder and Spring MVC
Controllers. Furthermore, it avoids the need for synchronization on custom
editors: a PropertyEditorRegistrar is expected to create fresh
PropertyEditor instances for each bean creation attempt.Using a PropertyEditorRegistrar is perhaps best illustrated with an
example. First off, you need to create your own PropertyEditorRegistrar
implementation:// it is expected that new PropertyEditor instances are created// you could register as many custom property editors as are required here...See also the org.springframework.beans.support.ResourceEditorRegistrar for an
example PropertyEditorRegistrar implementation. Notice how in its
implementation of the registerCustomEditors(..) method it creates new instances
of each property editor.Next we configure a CustomEditorConfigurer and inject an
instance of our CustomPropertyEditorRegistrar into it:]]>Finally, and in a bit of a departure from the focus of this chapter, for those of you using
Spring's MVC web framework, using PropertyEditorRegistrars
in conjunction with data-binding Controllers (such as
SimpleFormController) can be very convenient. Find below an example of using a
PropertyEditorRegistrar in the implementation of an initBinder(..)
method:this.customPropertyEditorRegistrar.registerCustomEditors(binder);// other methods to do with registering a UserThis style of PropertyEditor registration can lead to concise code (the
implementation of initBinder(..) is just one line long!), and allows common
PropertyEditor registration code to be encapsulated in a class and then
shared amongst as many Controllers as needed.