IntroductionThere 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.
+ 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
+ ands 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.
+ 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 have the need to use the BeanWrapper directly. Because this
- is reference documentation however, we felt that some explanation might be
- in order. We will explain the BeanWrapper in this chapter since, if you were
- going to use it at all, you would most likely do so when trying to bind data to objects.
+ The BeanWrapper is a fundamental
+ concept in the Spring Framework and is used in a lot of places. However,
+ you probably will not have the need to use the
+ BeanWrapper directly. Because this is
+ reference documentation however, we felt that some explanation might be in
+ order. We will explain the BeanWrapper in
+ this chapter since, if you were going to use it at all, you would most
+ likely do so when trying to bind data to objects.
- Spring's DataBinder and the lower-level BeanWrapper both use PropertyEditors to parse and format property values.
- The PropertyEditor concept is part of the JavaBeans specification, and is also explained in this chapter.
- Spring 3 introduces a "core.convert" package that provides a general type conversion facility, as well as a higher-level "format" package for formatting UI field values.
- These new packages may be used as simpler alternatives to PropertyEditors, and will also be discussed in this chapter.
-
+ Spring's DataBinder and the lower-level BeanWrapper both use
+ PropertyEditors to parse and format property values. The
+ PropertyEditor concept is part of the
+ JavaBeans specification, and is also explained in this chapter. Spring 3
+ introduces a "core.convert" package that provides a general type
+ conversion facility, as well as a higher-level "format" package for
+ formatting UI field values. These new packages may be used as simpler
+ alternatives to PropertyEditors, and will also be discussed in this
+ chapter.
-
- Validation using Spring's Validator interface
- Spring 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:
-
+ Validation using Spring's Validator
+ interface
+
+ Spring 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.
- 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
*/
- 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 resorting to copy-and-paste,
- you can dependency-inject or instantiate an AddressValidator
- within your CustomerValidator, and use it like so:
- As you can see, the static
+ rejectIfEmpty(..) 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.
- public CustomerValidator(Validator addressValidator) {
- if (addressValidator == null) {
- throw new IllegalArgumentException(
- "The supplied [Validator] is required and must not be null.");
- }
- if (!addressValidator.supports(Address.class)) {
- throw new IllegalArgumentException(
- "The supplied [Validator] must support the validation of [Address] instances.");
- }
- this.addressValidator = addressValidator;
- }
+ 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 resorting
+ to copy-and-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 messages
- We'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.
-
+
+ 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 messages
+
+ We'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 BeanWrapper
+ 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).
+ 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.
+ 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.
+ 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 properties
+ 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:
-
-
-
-
-
- Expression
- Explanation
-
-
+
+ Examples of properties
-
-
- name
+
+
+
+
+
+ Expression
+ Explanation
+
+
- Indicates the property name
- corresponding to the methods getName() or
- isName() and
+
+
+ name
+
+ Indicates the property name
+ corresponding to the methods getName()
+ or isName() and
setName(..)
-
+
-
- account.name
+
+ account.name
- Indicates the nested property name
- of the property account corresponding e.g.
- to the methods getAccount().setName() or
+ Indicates the nested property name of
+ the property account corresponding e.g. to
+ the methods getAccount().setName() or
getAccount().getName()
-
+
-
- account[2]
+
+ account[2]
- Indicates the third element of the
- indexed property account. Indexed
- properties can be of type array,
- list or other naturally
- ordered collection
-
+ Indicates the third element of the
+ indexed property account. Indexed properties
+ can be of type array, list
+ or other naturally ordered
+ collection
+
-
- account[COMPANYNAME]
+
+ account[COMPANYNAME]
- Indicates the value of the map entry indexed by the key
+ 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.
+ 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.)
+ (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:
+ and manipulate some of the properties of instantiated
+ Companies and Employees:
+
// setting the company name..
- Built-in PropertyEditor implementations
+ Built-in PropertyEditor
+ implementations
- Spring 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.
+ Spring 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.
-
+ 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.
-
-
-
+
+ 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:
+ 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 PropertyEditors
+ Built-in PropertyEditors
-
-
-
+
+
+
-
-
- Class
- Explanation
-
-
+
+
+ Class
+ Explanation
+
+
-
-
- ByteArrayPropertyEditor
+
+
+ ByteArrayPropertyEditor
- Editor for byte arrays. Strings will simply be
- converted to their corresponding byte representations.
- Registered by default by BeanWrapperImpl.
-
+ Editor for byte arrays. Strings will simply be converted to
+ their corresponding byte representations. Registered by default
+ by BeanWrapperImpl.
+
-
- ClassEditor
+
+ ClassEditor
- Parses 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
+ Parses 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.
-
+
-
- CustomBooleanEditor
+
+ CustomBooleanEditor
- Customizable property editor for Boolean properties.
- Registered by default by BeanWrapperImpl, but, can be
+ Customizable property editor for
+ Boolean properties. Registered by default
+ by BeanWrapperImpl, but, can be
overridden by registering custom instance of it as custom
editor.
-
-
- CustomCollectionEditor
- Property editor for Collections, converting any source
- Collection to a given target Collection type.
-
-
- CustomDateEditor
+
+
+ CustomCollectionEditor
+ Property editor for Collections, converting any source
+ Collection to a given target
+ Collection type.
+
+
+ CustomDateEditor
- Customizable property editor for java.util.Date,
- supporting a custom DateFormat. NOT registered by default. Must
- be user registered as needed with appropriate format.
-
+ Customizable property editor for java.util.Date, supporting
+ a custom DateFormat. NOT registered by default. Must be user
+ registered as needed with appropriate format.
+
-
- CustomNumberEditor
+
+ CustomNumberEditor
- Customizable 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.
-
+ Customizable 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.
+
-
- FileEditor
+
+ FileEditor
- Capable of resolving Strings to
- java.io.File objects. Registered by default by
- BeanWrapperImpl.
-
+ Capable of resolving Strings to
+ java.io.File objects. Registered by
+ default by BeanWrapperImpl.
+
-
- InputStreamEditor
+
+ InputStreamEditor
- One-way property editor, capable of taking a text
- string and producing (via an intermediate ResourceEditor and
+ One-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.
-
+ 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.
+
-
- LocaleEditor
+
+ LocaleEditor
- Capable of resolving Strings to
+ Capable 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.
-
+
-
- PatternEditor
+
+ PatternEditor
- Capable of resolving Strings to JDK 1.5
+ Capable of resolving Strings to JDK 1.5
Pattern objects and vice versa.
-
+
-
- PropertiesEditor
+
+ PropertiesEditor
- Capable 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.
-
+ Capable 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.
+
-
- StringTrimmerEditor
+
+ StringTrimmerEditor
- Property editor that trims Strings. Optionally allows
- transforming an empty string into a null value. NOT
- registered by default; must be user registered as needed.
-
+ Property editor that trims Strings. Optionally allows
+ transforming an empty string into a null
+ value. NOT registered by default; must be user registered as
+ needed.
+
-
- URLEditor
+
+ URLEditor
- Capable of resolving a String representation of a URL
- to an actual URL object. Registered by
- default by BeanWrapperImpl.
-
-
-
-
+ Capable 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.
-
- 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 class
- Note 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.
- Note 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.
-
- 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
+ PropertyEditors
-
- Registering additional custom PropertyEditors
+ When 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.
- When 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.
+ 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.
- 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:
+ 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:
-
+
+ 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 objectThe PropertyEditor implementation
+ could look similar to this:
+ // converts string representation to ExoticType object
- Finally, we use CustomEditorConfigurer to register the new
- PropertyEditor with the ApplicationContext,
- which will then be able to use it as needed:
-
+
+ Finally, we use CustomEditorConfigurer to
+ register the new PropertyEditor with
+ the ApplicationContext, which will then
+ be able to use it as needed:
+
+
]]>
-
- Using PropertyEditorRegistrars
+
+ Using
+ PropertyEditorRegistrars
- Another 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:
+ Another 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:
+
+ // 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:
-
+
+ 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:
+
@@ -701,14 +821,19 @@ public final class CustomPropertyEditorRegistrar implements PropertyEditorRegist
]]>
- 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:
+ 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:
- // other methods to do with registering a User
- This 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.
-
-
-
-
-
+ This 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.
+
+
-
- Spring 3 Type Conversion
-
- Spring 3 introduces a core.convert package that provides a general type conversion system.
- The system defines an SPI to implement type conversion logic, as well as an API to execute type conversions at runtime.
- Within a Spring container, this system can be used as an alternative to PropertyEditors to convert externalized bean property value strings to required property types.
- The public API may also be used anywhere in your application where type conversion is needed.
-
-
- Converter SPI
-
- The SPI to implement type conversion logic is simple and strongly typed:
-
-
+ Spring 3 Type Conversion
+
+ Spring 3 introduces a core.convert package that
+ provides a general type conversion system. The system defines an SPI to
+ implement type conversion logic, as well as an API to execute type
+ conversions at runtime. Within a Spring container, this system can be used
+ as an alternative to PropertyEditors to convert externalized bean property
+ value strings to required property types. The public API may also be used
+ anywhere in your application where type conversion is needed.
+
+
+ Converter SPI
+
+ The SPI to implement type conversion logic is simple and strongly
+ typed:
+
+ {
- T convert(S source);
-
+ T convert(S source);
+
}]]>
-
- To create your own Converter, simply implement the interface above.
- Parameterize S as the type you are converting from, and T as the type you are converting to.
- For each call to convert(S), the source argument is guaranteed to be NOT null.
- Your Converter may throw any Exception if conversion fails.
- An IllegalArgumentException should be thrown to report an invalid source value.
- Take care to ensure your Converter implementation is thread-safe.
-
-
- Several converter implementations are provided in the core.convert.support package as a convenience.
- These include converters from Strings to Numbers and other common types.
- Consider StringToInteger as an example Converter implementation:
-
-
-package org.springframework.core.convert.support;
-
+
+ To create your own Converter, simply implement the interface above.
+ Parameterize S as the type you are converting from, and T as the type
+ you are converting to. For each call to convert(S), the source argument
+ is guaranteed to be NOT null. Your Converter may throw any Exception if
+ conversion fails. An IllegalArgumentException should be thrown to report
+ an invalid source value. Take care to ensure your Converter
+ implementation is thread-safe.
+
+ Several converter implementations are provided in the
+ core.convert.support package as a convenience.
+ These include converters from Strings to Numbers and other common types.
+ Consider StringToInteger as an example Converter
+ implementation:
+
+ package org.springframework.core.convert.support;
+
final class StringToInteger implements Converter<String, Integer> {
public Integer convert(String source) {
return Integer.valueOf(source);
}
-
+
}
-
-
- ConverterFactory
-
- When you need to centralize the conversion logic for an entire class hierarchy, for example, when converting from String to java.lang.Enum objects, implement ConverterFactory:
-
-
+
+
+ ConverterFactory
+
+ When you need to centralize the conversion logic for an entire
+ class hierarchy, for example, when converting from String to
+ java.lang.Enum objects, implement
+ ConverterFactory:
+
+ {
- Converter getConverter(Class targetType);
-
+ Converter getConverter(Class targetType);
+
}]]>
-
- Parameterize S to be type you are converting from and R to be base type defining the range of classes you can convert to.
- Then implement getConverter(Class<T>), where T is a subclass of R.
-
-
- Consider the StringToEnum ConverterFactory as an example:
-
- Parameterize S to be type you are converting from and R to be base
+ type defining the range of classes you can convert
+ to. Then implement getConverter(Class<T>), where T is a subclass
+ of R.
+
+ Consider the StringToEnum ConverterFactory
+ as an example:
+
+ {
@@ -813,26 +949,31 @@ final class StringToEnumConverterFactory implements ConverterFactory implements Converter {
private Class enumType;
-
+
public StringToEnumConverter(Class enumType) {
this.enumType = enumType;
}
-
+
public T convert(String source) {
return (T) Enum.valueOf(this.enumType, source.trim());
}
}
}]]>
-
-
- GenericConverter
-
- When you require a sophisticated Converter implementation, consider the GenericConverter interface.
- With a more flexible but less strongly typed signature, a GenericConverter supports converting between multiple source and target types.
- In addition, a GenericConverter makes available source and target field context you can use when implementing your conversion logic.
- Such context allows a type conversion to be driven by a field annotation, or generic information declared on a field signature.
-
-
+
+
+ GenericConverter
+
+ When you require a sophisticated Converter implementation, consider
+ the GenericConverter interface. With a more flexible but less strongly
+ typed signature, a GenericConverter supports converting between multiple
+ source and target types. In addition, a GenericConverter makes available
+ source and target field context you can use when implementing your
+ conversion logic. Such context allows a type conversion to be driven by
+ a field annotation, or generic information declared on a field
+ signature.
+
+
-
-
- To implement a GenericConverter, have getConvertibleTypes() return the supported source->target type pairs.
- Then implement convert(Object, TypeDescriptor, TypeDescriptor) to implement your conversion logic.
- The source TypeDescriptor provides access to the source field holding the value being converted.
- The target TypeDescriptor provides access to the target field where the converted value will be set.
-
-
- A good example of a GenericConverter is a converter that converts between a Java Array and a Collection.
- Such an ArrayToCollectionConverter introspects the field that declares the target Collection type to resolve the Collection's element type.
- This allows each element in the source array to be converted to the Collection element type before the Collection is set on the target field.
-
-
-
- Because GenericConverter is a more complex SPI interface, only use it when you need it.
- Favor Converter or ConverterFactory for basic type conversion needs.
-
-
-
- ConditionalGenericConverter
-
- Sometimes you only want a Converter to execute if a specific condition holds true.
- For example, you might only want to execute a Converter if a specific annotation is present on the target field.
- Or you might only want to execute a Converter if a specific method, such as static valueOf method, is defined on the target class.
- ConditionalGenericConverter is an subinterface of GenericConverter that allows you to define such custom matching criteria:
-
-
+
+ To implement a GenericConverter, have getConvertibleTypes() return
+ the supported source->target type pairs. Then implement
+ convert(Object, TypeDescriptor, TypeDescriptor) to implement your
+ conversion logic. The source TypeDescriptor provides access to the
+ source field holding the value being converted. The target
+ TypeDescriptor provides access to the target field where the converted
+ value will be set.
+
+ A good example of a GenericConverter is a converter that converts
+ between a Java Array and a Collection. Such an
+ ArrayToCollectionConverter introspects the field that declares the
+ target Collection type to resolve the Collection's element type. This
+ allows each element in the source array to be converted to the
+ Collection element type before the Collection is set on the target
+ field.
+
+ Because GenericConverter is a more complex SPI interface, only
+ use it when you need it. Favor Converter or ConverterFactory for basic
+ type conversion needs.
+
+
+
+ ConditionalGenericConverter
+
+ Sometimes you only want a Converter to execute if a specific
+ condition holds true. For example, you might only want to execute a
+ Converter if a specific annotation is present on the target field. Or
+ you might only want to execute a Converter if a specific method, such
+ as static valueOf method, is defined on the target class.
+ ConditionalGenericConverter is an subinterface of GenericConverter
+ that allows you to define such custom matching criteria:
+
+
-
-
- A good example of a ConditionalGenericConverter is an EntityConverter that converts between an persistent entity identifier and an entity reference.
- Such a EntityConverter might only match if the target entity type declares a static finder method e.g. findAccount(Long).
- You would perform such a finder method check in the implementation of matches(TypeDescriptor, TypeDescriptor).
-
-
-
-
- ConversionService API
-
- The ConversionService defines a unified API for executing type conversion logic at runtime.
- Converters are often executed behind this facade interface:
-
-
+
+ A good example of a ConditionalGenericConverter is an
+ EntityConverter that converts between an persistent entity identifier
+ and an entity reference. Such a EntityConverter might only match if
+ the target entity type declares a static finder method e.g.
+ findAccount(Long). You would perform such a finder method check in the
+ implementation of matches(TypeDescriptor, TypeDescriptor).
+
+
+
+
+ ConversionService API
+
+ The ConversionService defines a unified API for executing type
+ conversion logic at runtime. Converters are often executed behind this
+ facade interface:
+
+ sourceType, Class> targetType);
-
+
T convert(Object source, Class targetType);
-
+
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
-
+
}]]>
-
- Most ConversionService implementations also implement ConverterRegistry, which provides an SPI for registering converters.
- Internally, a ConversionService implementation delegates to its registered converters to carry out type conversion logic.
-
-
- A robust ConversionService implementation is provided in the core.convert.support package.
- GenericConversionService is the general-purpose implementation suitable for use in most environments.
- ConversionServiceFactory provides a convenient factory for creating common ConversionService configurations.
-
-
-
- Configuring a ConversionService
-
- A ConversionService is a stateless object designed to be instantiated at application startup, then shared between multiple threads.
- In a Spring application, you typically configure a ConversionService instance per Spring container (or ApplicationContext).
- That ConversionService will be picked up by Spring and then used whenever a type conversion needs to be performed by the framework.
- You may also inject this ConversionService into any of your beans and invoke it directly.
-
-
-
- If no ConversionService is registered with Spring, the original PropertyEditor-based system is used.
-
-
-
- To register a default ConversionService with Spring, add the following bean definition with id conversionService:
-
- Most ConversionService implementations also implement
+ ConverterRegistry, which provides an SPI for
+ registering converters. Internally, a ConversionService implementation
+ delegates to its registered converters to carry out type conversion
+ logic.
+
+ A robust ConversionService implementation is provided in the
+ core.convert.support package.
+ GenericConversionService is the general-purpose
+ implementation suitable for use in most environments.
+ ConversionServiceFactory provides a convenient
+ factory for creating common ConversionService configurations.
+
+
+
+ Configuring a ConversionService
+
+ A ConversionService is a stateless object designed to be
+ instantiated at application startup, then shared between multiple
+ threads. In a Spring application, you typically configure a
+ ConversionService instance per Spring container (or ApplicationContext).
+ That ConversionService will be picked up by Spring and then used
+ whenever a type conversion needs to be performed by the framework. You
+ may also inject this ConversionService into any of your beans and invoke
+ it directly.
+
+ If no ConversionService is registered with Spring, the original
+ PropertyEditor-based system is used.
+
+
+ To register a default ConversionService with Spring, add the
+ following bean definition with id conversionService:
+ ]]>
-
-
- A default ConversionService can convert between strings, numbers, enums, collections, maps, and other common types.
- To suppliment or override the default converters with your own custom converter(s), set the converters property.
- Property values may implement either of the Converter, ConverterFactory, or GenericConverter interfaces.
-
-
+
+ A default ConversionService can convert between strings, numbers,
+ enums, collections, maps, and other common types. To suppliment or
+ override the default converters with your own custom converter(s), set
+ the converters property. Property values may implement
+ either of the Converter, ConverterFactory, or GenericConverter
+ interfaces.
+
+
@@ -944,13 +1106,15 @@ public interface ConversionService {
]]>
-
-
- Using a ConversionService programatically
-
- To work with a ConversionService instance programatically, simply inject a reference to it like you would for any other bean:
-
-
+
+
+ Using a ConversionService programatically
+
+ To work with a ConversionService instance programatically, simply
+ inject a reference to it like you would for any other bean:
+
+
-
-
-
-
- Spring 3 Field Formatting
-
- As discussed in the previous section, core.convert is a general-purpose type conversion system.
- It provides a unified ConversionService API as well as a strongly-typed Converter SPI for implementing conversion logic from one type to another.
- A Spring Container uses this system to bind bean property values.
- In addition, both the Spring Expression Language (SpEL) and DataBinder use this system to bind field values.
- For example, when SpEL needs to coerce a Short to a Long to complete an expression.setValue(Object bean, Object value) attempt, the core.convert system performs the coercion.
-
-
- Now consider the type conversion requirements of a typical client environment such as a web or desktop application.
- In such environments, you typically convert from String to support the client postback process, as well as back to String to support the view rendering process.
- In addition, you often need to localize String values.
- The more general core.convert Converter SPI does not address such formatting requirements directly.
- To directly address them, Spring 3 introduces a convenient Formatter SPI that provides a simple and robust alternative to PropertyEditors for client environments.
-
-
- In general, use the Converter SPI when you need to implement general-purpose type conversion logic; for example, for converting between a java.util.Date and and java.lang.Long.
- Use the Formatter SPI when you're working in a client environment, such as a web application, and need to parse and print localized field values.
- The ConversionService provides a unified type conversion API for both SPIs.
-
-
- Formatter SPI
-
- The Formatter SPI to implement field formatting logic is simple and strongly typed:
-
-
+
+
+
+ Spring 3 Field Formatting
+
+ As discussed in the previous section, core.convert is a general-purpose type
+ conversion system. It provides a unified ConversionService API as well as
+ a strongly-typed Converter SPI for implementing conversion logic from one
+ type to another. A Spring Container uses this system to bind bean property
+ values. In addition, both the Spring Expression Language (SpEL) and
+ DataBinder use this system to bind field values. For example, when SpEL
+ needs to coerce a Short to a
+ Long to complete an
+ expression.setValue(Object bean, Object value)
+ attempt, the core.convert system performs the coercion.
+
+ Now consider the type conversion requirements of a typical client
+ environment such as a web or desktop application. In such environments,
+ you typically convert from String to support the
+ client postback process, as well as back to String to
+ support the view rendering process. In addition, you often need to
+ localize String values. The more general core.convert
+ Converter SPI does not address such formatting
+ requirements directly. To directly address them, Spring 3 introduces a
+ convenient Formatter SPI that provides a simple and robust alternative to
+ PropertyEditors for client environments.
+
+ In general, use the Converter SPI when you need to implement
+ general-purpose type conversion logic; for example, for converting between
+ a java.util.Date and and java.lang.Long. Use the Formatter SPI when you're
+ working in a client environment, such as a web application, and need to
+ parse and print localized field values. The ConversionService provides a
+ unified type conversion API for both SPIs.
+
+
+ Formatter SPI
+
+ The Formatter SPI to implement field formatting logic is simple and
+ strongly typed:
+ extends Printer, Parser {
}]]>
-
-
- Where Formatter extends from the Printer and Parser building-block interfaces:
-
-
+
+ Where Formatter extends from the Printer and Parser building-block
+ interfaces:
+ {
String print(T fieldValue, Locale locale);
}]]>
-
-
+ {
T parse(String clientValue, Locale locale) throws ParseException;
}]]>
-
-
- To create your own Formatter, simply implement the Formatter interface above.
- Parameterize T to be the type of object you wish to format, for example, java.util.Date.
- Implement the print operation to print an instance of T for display in the client locale.
- Implement the parse operation to parse an instance of T from the formatted representation returned from the client locale.
- Your Formatter should throw a ParseException or IllegalArgumentException if a parse attempt fails.
- Take care to ensure your Formatter implementation is thread-safe.
-
-
- Several Formatter implementations are provided in format subpackages as a convenience.
- The number package provides a NumberFormatter, CurrencyFormatter, and PercentFormatter to format java.lang.Number objects using a java.text.NumberFormat.
- The datetime package provides a DateFormatter to format java.util.Date objects with a java.text.DateFormat.
- The datetime.joda package provides comprehensive datetime formatting support based on the Joda Time library.
-
-
- Consider DateFormatter as an example Formatter implementation:
-
-
+
+ To create your own Formatter, simply implement the Formatter
+ interface above. Parameterize T to be the type of object you wish to
+ format, for example, java.util.Date. Implement
+ the print operation to print an instance of T
+ for display in the client locale. Implement the
+ parse operation to parse an instance of T from
+ the formatted representation returned from the client locale. Your
+ Formatter should throw a ParseException or IllegalArgumentException if a
+ parse attempt fails. Take care to ensure your Formatter implementation
+ is thread-safe.
+
+ Several Formatter implementations are provided in
+ format subpackages as a convenience. The
+ number package provides a NumberFormatter,
+ CurrencyFormatter, and PercentFormatter to format java.lang.Number
+ objects using a java.text.NumberFormat. The
+ datetime package provides a DateFormatter to format
+ java.util.Date objects with a java.text.DateFormat. The
+ datetime.joda package provides comprehensive
+ datetime formatting support based on the Joda Time library.
+
+ Consider DateFormatter as an example
+ Formatter implementation:
+
+ {
private String pattern;
-
+
public DateFormatter(String pattern) {
this.pattern = pattern;
}
-
+
public String print(Date date, Locale locale) {
if (date == null) {
return "";
@@ -1062,51 +1247,57 @@ public final class DateFormatter implements Formatter {
}
}]]>
-
- The Spring team welcomes community-driven Formatter contributions; see http://jira.springframework.org to contribute.
-
-
-
- Annotation-driven Formatting
-
- As you will see, field formatting can be configured by field type or annotation.
- To bind an Annotation to a formatter, implement AnnotationFormatterFactory:
-
- The Spring team welcomes community-driven Formatter contributions;
+ see http://jira.springframework.org to contribute.
+
+
+
+ Annotation-driven Formatting
+
+ As you will see, field formatting can be configured by field type
+ or annotation. To bind an Annotation to a formatter, implement
+ AnnotationFormatterFactory:
+
+ {
- Set> getFieldTypes();
-
+ Set> getFieldTypes();
+
Printer> getPrinter(A annotation, Class> fieldType);
-
+
Parser> getParser(A annotation, Class> fieldType);
-}]]>
-
-
- Parameterize A to be the field annotationType you wish to associate formatting logic with, for example org.springframework.format.annotation.DateTimeFormat.
- Have getFieldTypes return the types of fields the annotation may be used on.
- Have getPrinter return a Printer to print the value of an annotated field.
- Have getParser return a Parser to parse a clientValue for an annotated field.
-
-
- The example AnnotationFormatterFactory implementation below binds the @NumberFormat Annotation to a formatter.
- This annotation allows either a number style or pattern to be specified:
-
-
+
+ Parameterize A to be the field annotationType you wish to associate
+ formatting logic with, for example
+ org.springframework.format.annotation.DateTimeFormat. Have
+ getFieldTypes return the types of fields the
+ annotation may be used on. Have getPrinter
+ return a Printer to print the value of an annotated field. Have
+ getParser return a Parser to parse a
+ clientValue for an annotated field.
+
+ The example AnnotationFormatterFactory implementation below binds
+ the @NumberFormat Annotation to a formatter. This annotation allows
+ either a number style or pattern to be specified:
+
+ {
public Set> getFieldTypes() {
- return new HashSet>(asList(new Class>[] {
+ return new HashSet>(asList(new Class>[] {
Short.class, Integer.class, Long.class, Float.class, Double.class, BigDecimal.class, BigInteger.class }));
}
-
+
public Printer getPrinter(NumberFormat annotation, Class> fieldType) {
return configureFormatterFrom(annotation, fieldType);
}
-
+
public Parser getParser(NumberFormat annotation, Class> fieldType) {
return configureFormatterFrom(annotation, fieldType);
}
@@ -1125,51 +1316,54 @@ public final class NumberFormatAnnotationFormatterFactory implements AnnotationF
}
}
}
-}]]>
-
-
- To trigger formatting, simply annotate fields with @NumberFormat:
-
-
+
+ To trigger formatting, simply annotate fields with @NumberFormat:
+
+
-
-
- Format Annotation API
-
- A portable format annotation API exists in the org.springframework.format.annotation package.
- Use @NumberFormat to format java.lang.Number fields.
- Use @DateTimeFormat to format java.util.Date, java.util.Calendar, java.util.Long, or Joda Time fields.
-
-
- The example below uses @DateTimeFormat to format a java.util.Date as a ISO Date (yyyy-MM-dd):
-
-
+
+
+ Format Annotation API
+
+ A portable format annotation API exists in the
+ org.springframework.format.annotation package.
+ Use @NumberFormat to format java.lang.Number fields. Use
+ @DateTimeFormat to format java.util.Date, java.util.Calendar,
+ java.util.Long, or Joda Time fields.
+
+ The example below uses @DateTimeFormat to format a java.util.Date
+ as a ISO Date (yyyy-MM-dd):
+
+
-
-
-
-
- FormatterRegistry SPI
-
- At runtime, Formatters are registered in a FormatterRegistry.
- The FormatterRegistry SPI allows you to configure Formatting rules centrally, instead of duplicating such configuration across your Controllers.
- For example, you might want to enforce that all Date fields are formatted a certain way, or fields with a specific annotation are formatted in a certain way.
- With a shared FormatterRegistry, you define these rules once and they are applied whenever formatting is needed.
-
-
- Review the FormatterRegistry SPI below:
-
-
+
+
+
+
+ FormatterRegistry SPI
+
+ At runtime, Formatters are registered in a FormatterRegistry. The
+ FormatterRegistry SPI allows you to configure Formatting rules
+ centrally, instead of duplicating such configuration across your
+ Controllers. For example, you might want to enforce that all Date fields
+ are formatted a certain way, or fields with a specific annotation are
+ formatted in a certain way. With a shared FormatterRegistry, you define
+ these rules once and they are applied whenever formatting is needed.
+
+ Review the FormatterRegistry SPI below:
+
+ fieldType, Formatter> formatter);
void addFormatterForAnnotation(AnnotationFormatterFactory, ?> factory);
-
+
}]]>
-
- As shown above, Formatters can be registered by fieldType or annotation.
- FormattingConversionService is the implementation of FormatterRegistry suitable for most environments.
- This implementation may be configured programatically, or declaratively as a Spring bean using FormattingConversionServiceFactoryBean.
- Because this implemementation also implements ConversionService, it can be directly configured for use with Spring's DataBinder and the Spring Expression Language (SpEL).
-
-
-
- Configuring Formatting in Spring MVC
-
- In a Spring MVC application, you may configure a custom ConversionService instance explicity as an attribute of the annotation-driven element of the MVC namespace.
- This ConversionService will then be used anytime a type conversion is required during Controller model binding.
- If not configured explicitly, Spring MVC will automatically register default formatters and converters for common types such as numbers and dates.
-
-
- To rely on default formatting rules, no custom configuration is required in your Spring MVC config XML:
-
- As shown above, Formatters can be registered by fieldType or
+ annotation. FormattingConversionService is the
+ implementation of FormatterRegistry suitable for
+ most environments. This implementation may be configured
+ programatically, or declaratively as a Spring bean using
+ FormattingConversionServiceFactoryBean. Because
+ this implemementation also implements
+ ConversionService, it can be directly configured
+ for use with Spring's DataBinder and the Spring Expression Language
+ (SpEL).
+
+
+
+ Configuring Formatting in Spring MVC
+
+ In a Spring MVC application, you may configure a custom
+ ConversionService instance explicity as an attribute of the
+ annotation-driven element of the MVC namespace. This
+ ConversionService will then be used anytime a type conversion is
+ required during Controller model binding. If not configured explicitly,
+ Spring MVC will automatically register default formatters and converters
+ for common types such as numbers and dates.
+
+ To rely on default formatting rules, no custom configuration is
+ required in your Spring MVC config XML:
+
+
-
+
-]]>
-
-
- With this one-line of configuation, default formatters for Numbers and Date types will be installed, including support for the @NumberFormat and @DateTimeFormat annotations.
- Full support for the Joda Time formatting library is also installed if Joda Time is present on the classpath.
-
-
- To inject a ConversionService instance with custom formatters and converters registered, set the conversion-service attribute:
-
-
+
+ With this one-line of configuation, default formatters for Numbers
+ and Date types will be installed, including support for the
+ @NumberFormat and @DateTimeFormat annotations. Full support for the Joda
+ Time formatting library is also installed if Joda Time is present on the
+ classpath.
+
+ To inject a ConversionService instance with custom formatters and
+ converters registered, set the conversion-service attribute:
+
-
+
-
+
-]]>
-
-
- A custom ConversionService instance is often constructed by a FactoryBean that internally registers custom Formatters and Converters programatically before the ConversionService is returned.
- See FormattingConversionServiceFactoryBean for an example.
-
-
-
-
- Spring 3 Validation
-
- Spring 3 introduces several enhancements to its validation support.
- First, the JSR-303 Bean Validation API is now fully supported.
- Second, when used programatically, Spring's DataBinder can now validate objects as well as bind to them.
- Third, Spring MVC now has support for declaratively validating @Controller inputs.
-
-
- Overview of the JSR-303 Bean Validation API
-
- JSR-303 standardizes validation constraint declaration and metadata for the Java platform.
- Using this API, you annotate domain model properties with declarative validation constraints and the runtime enforces them.
- There are a number of built-in constraints you can take advantage of.
- You may also define your own custom constraints.
-
-
- To illustrate, consider a simple PersonForm model with two properties:
-
-
+
+ A custom ConversionService instance is often constructed by a
+ FactoryBean that internally registers custom Formatters and Converters
+ programatically before the ConversionService is returned. See
+ FormattingConversionServiceFactoryBean for an example.
+
+
+
+
+ Spring 3 Validation
+
+ Spring 3 introduces several enhancements to its validation support.
+ First, the JSR-303 Bean Validation API is now fully supported. Second,
+ when used programatically, Spring's DataBinder can now validate objects as
+ well as bind to them. Third, Spring MVC now has support for declaratively
+ validating @Controller inputs.
+
+
+ Overview of the JSR-303 Bean Validation API
+
+ JSR-303 standardizes validation constraint declaration and metadata
+ for the Java platform. Using this API, you annotate domain model
+ properties with declarative validation constraints and the runtime
+ enforces them. There are a number of built-in constraints you can take
+ advantage of. You may also define your own custom constraints.
+
+ To illustrate, consider a simple PersonForm model with two
+ properties:
+
+
-
- JSR-303 allows you to define declarative validation constraints against such properties:
-
- JSR-303 allows you to define declarative validation constraints
+ against such properties:
+
+
-
- When an instance of this class is validated by a JSR-303 Validator, these constraints will be enforced.
-
-
- For general information on JSR-303, see the Bean Validation Specification.
- For information on the specific capabilities of the default reference implementation, see the Hibernate Validator documentation.
- To learn how to setup a JSR-303 implementation as a Spring bean, keep reading.
-
-
-
- Configuring a Bean Validation Implementation
-
- Spring provides full support for the JSR-303 Bean Validation API.
- This includes convenient support for bootstrapping a JSR-303 implementation as a Spring bean.
- This allows for a javax.validation.ValidatorFactory or javax.validation.Validator
- to be injected wherever validation is needed in your application.
-
-
- Use the LocalValidatorFactoryBean to configure a default JSR-303 Validator as a Spring bean:
-
- When an instance of this class is validated by a JSR-303 Validator,
+ these constraints will be enforced.
+
+ For general information on JSR-303, see the Bean Validation
+ Specification. For information on the specific capabilities of
+ the default reference implementation, see the Hibernate Validator
+ documentation. To learn how to setup a JSR-303 implementation as a
+ Spring bean, keep reading.
+
+
+
+ Configuring a Bean Validation Implementation
+
+ Spring provides full support for the JSR-303 Bean Validation API.
+ This includes convenient support for bootstrapping a JSR-303
+ implementation as a Spring bean. This allows for a
+ javax.validation.ValidatorFactory or
+ javax.validation.Validator to be injected wherever
+ validation is needed in your application.
+
+ Use the LocalValidatorFactoryBean to
+ configure a default JSR-303 Validator as a Spring bean:
+
+ ]]>
-
-
- The basic configuration above will trigger JSR-303 to initialize using its default bootstrap mechanism.
- A JSR-303 provider, such as Hibernate Validator, is expected to be present in the classpath and will be detected automatically.
-
-
- Injecting a Validator
-
- LocalValidatorFactoryBean implements both javax.validation.ValidatorFactory
- and javax.validation.Validator, as well as Spring's org.springframework.validation.Validator.
- You may inject a reference to either of these interfaces into beans that need to invoke validation logic.
-
-
- Inject a reference to javax.validation.Validator if you prefer to work with the JSR-303 API directly:
-
-
+
+
+ The basic configuration above will trigger JSR-303 to initialize
+ using its default bootstrap mechanism. A JSR-303 provider, such as
+ Hibernate Validator, is expected to be present in the classpath and will
+ be detected automatically.
+
+
+ Injecting a Validator
+
+ LocalValidatorFactoryBean implements both
+ javax.validation.ValidatorFactory and
+ javax.validation.Validator, as well as Spring's
+ org.springframework.validation.Validator. You may inject
+ a reference to either of these interfaces into beans that need to
+ invoke validation logic.
+
+ Inject a reference to javax.validation.Validator if
+ you prefer to work with the JSR-303 API directly:
+
+
import javax.validation.Validator;
@Service
@@ -1329,10 +1549,12 @@ public class MyService {
@Autowired
private Validator validator;
-
- Inject a reference to org.springframework.validation.Validator if your bean requires the Spring Validation API:
-
- Inject a reference to
+ org.springframework.validation.Validator if your bean
+ requires the Spring Validation API:
+
+
-
-
- Configuring Custom Constraints
-
- Each JSR-303 validation constraint consists of two parts.
- First, a @Constraint annotation that declares the constraint and its configurable properties.
- Second, an implementation of the javax.validation.ConstraintValidator interface that implements the constraint's behavior.
- To associate a declaration with an implementation, each @Constraint annotation references a corresponding ValidationConstraint implementation class.
- At runtime, a ConstraintValidatorFactory instantiates the referenced implementation when the constraint annotation is encountered in your domain model.
-
-
- By default, the LocalValidatorFactoryBean configures a SpringConstraintValidatorFactory that uses Spring to create ConstraintValidator instances.
- This allows your custom ConstraintValidators to benefit from dependency injection like any other Spring bean.
-
-
- Shown below is an example of a custom @Constraint declaration, followed by an associated ConstraintValidator implementation that uses Spring for dependency injection:
-
-
+
+
+ Configuring Custom Constraints
+
+ Each JSR-303 validation constraint consists of two parts. First,
+ a @Constraint annotation that declares the constraint and its
+ configurable properties. Second, an implementation of the
+ javax.validation.ConstraintValidator interface that
+ implements the constraint's behavior. To associate a declaration with
+ an implementation, each @Constraint annotation references a
+ corresponding ValidationConstraint implementation class. At runtime, a
+ ConstraintValidatorFactory instantiates the referenced
+ implementation when the constraint annotation is encountered in your
+ domain model.
+
+ By default, the LocalValidatorFactoryBean
+ configures a SpringConstraintValidatorFactory that uses
+ Spring to create ConstraintValidator instances. This allows your
+ custom ConstraintValidators to benefit from dependency injection like
+ any other Spring bean.
+
+ Shown below is an example of a custom @Constraint declaration,
+ followed by an associated ConstraintValidator
+ implementation that uses Spring for dependency injection:
+
+
-
+
+
-
- As you can see, a ConstraintValidator implementation may have its dependencies @Autowired like any other Spring bean.
-
-
-
- Additional Configuration Options
-
- The default LocalValidatorFactoryBean configuration should prove sufficient for most cases.
- There are a number of other configuration options for various JSR-303 constructs, from message interpolation to traversal resolution.
- See the JavaDocs of LocalValidatorFactoryBean for more information on these options.
-
-
-
-
- Configuring a DataBinder
-
- Since Spring 3, a DataBinder instance can be configured with a Validator.
- Once configured, the Validator may be invoked by calling binder.validate().
- Any validation Errors are automatically added to the binder's BindingResult.
-
-
- When working with the DataBinder programatically, this can be used to invoke validation logic after binding to a target object:
-
- Foo target = new Foo();
+
+ As you can see, a ConstraintValidator implementation may have its
+ dependencies @Autowired like any other Spring bean.
+
+
+
+ Additional Configuration Options
+
+ The default LocalValidatorFactoryBean
+ configuration should prove sufficient for most cases. There are a
+ number of other configuration options for various JSR-303 constructs,
+ from message interpolation to traversal resolution. See the JavaDocs
+ of LocalValidatorFactoryBean for more
+ information on these options.
+
+
+
+
+ Configuring a DataBinder
+
+ Since Spring 3, a DataBinder instance can be configured with a
+ Validator. Once configured, the Validator may be invoked by calling
+ binder.validate(). Any validation Errors are automatically
+ added to the binder's BindingResult.
+
+ When working with the DataBinder programatically, this can be used
+ to invoke validation logic after binding to a target object:
+
+ Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator());
@@ -1411,41 +1648,46 @@ binder.validate();
// get BindingResult that includes any validation errors
BindingResult results = binder.getBindingResult();
-
-
- Spring MVC 3 Validation
-
- Beginning with Spring 3, Spring MVC has the ability to automatically validate @Controller inputs.
- In previous versions it was up to the developer to manually invoke validation logic.
-
-
- Triggering @Controller Input Validation
-
- To trigger validation of a @Controller input, simply annotate the input argument as @Valid:
-
- @Controller
+
+
+
+ Spring MVC 3 Validation
+
+ Beginning with Spring 3, Spring MVC has the ability to
+ automatically validate @Controller inputs. In previous versions it was
+ up to the developer to manually invoke validation logic.
+
+
+ Triggering @Controller Input Validation
+
+ To trigger validation of a @Controller input, simply annotate the
+ input argument as @Valid:
+
+ @Controller
public class MyController {
@RequestMapping("/foo", method=RequestMethod.POST)
public void processFoo(@Valid Foo foo) { /* ... */ }
-
- Spring MVC will validate a @Valid object after binding so-long as an appropriate Validator has been configured.
-
-
-
- The @Valid annotation is part of the standard JSR-303 Bean Validation API, and is not a Spring-specific construct.
-
-
-
-
- Configuring a Validator for use by Spring MVC
-
- The Validator instance invoked when a @Valid method argument is encountered may be configured in two ways.
- First, you may call binder.setValidator(Validator) within a @Controller's @InitBinder callback.
- This allows you to configure a Validator instance per @Controller class:
-
- Spring MVC will validate a @Valid object after binding so-long as
+ an appropriate Validator has been configured.
+
+ The @Valid annotation is part of the standard JSR-303 Bean
+ Validation API, and is not a Spring-specific construct.
+
+
+
+
+ Configuring a Validator for use by Spring MVC
+
+ The Validator instance invoked when a @Valid method argument is
+ encountered may be configured in two ways. First, you may call
+ binder.setValidator(Validator) within a @Controller's @InitBinder
+ callback. This allows you to configure a Validator instance per
+ @Controller class:
+
+
-
- Second, you may call setValidator(Validator) on the global WebBindingInitializer.
- This allows you to configure a Validator instance across all @Controllers.
- This can be achieved easily by using the Spring MVC namespace:
-
- Second, you may call setValidator(Validator) on the global
+ WebBindingInitializer. This allows you to configure a Validator
+ instance across all @Controllers. This can be achieved easily by using
+ the Spring MVC namespace:
+
+
-
+
-]]>
-
-
-
- Configuring a JSR-303 Validator for use by Spring MVC
-
- With JSR-303, a single javax.validation.Validator instance typically validates all model objects that declare validation constraints.
- To configure a JSR-303-backed Validator with Spring MVC, simply add a JSR-303 Provider, such as Hibernate Validator, to your classpath.
- Spring MVC will detect it and automatically enable JSR-303 support across all Controllers.
-
-
- The Spring MVC configuration required to enable JSR-303 support is shown below:
-
-
+
+
+
+ Configuring a JSR-303 Validator for use by Spring MVC
+
+ With JSR-303, a single javax.validation.Validator
+ instance typically validates all model objects
+ that declare validation constraints. To configure a JSR-303-backed
+ Validator with Spring MVC, simply add a JSR-303 Provider, such as
+ Hibernate Validator, to your classpath. Spring MVC will detect it and
+ automatically enable JSR-303 support across all Controllers.
+
+ The Spring MVC configuration required to enable JSR-303 support
+ is shown below:
+
+
-
+
-]]>
-
-
- With this minimal configuration, anytime a @Valid @Controller input is encountered, it will be validated by the JSR-303 provider.
- JSR-303, in turn, will enforce any constraints declared against the input.
- Any ConstraintViolations will automatically be exposed as errors in the BindingResult renderable by standard Spring MVC form tags.
-
-
-
-
+]]>
+
+ With this minimal configuration, anytime a @Valid @Controller
+ input is encountered, it will be validated by the JSR-303 provider.
+ JSR-303, in turn, will enforce any constraints declared against the
+ input. Any ConstraintViolations will automatically be exposed as
+ errors in the BindingResult renderable by standard Spring MVC form
+ tags.
+
+
+