Validation, Data Binding, and Type Conversion
Introduction There 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 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.
Validation using Spring's <interfacename>Validator</interfacename> interface Spring'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 just Person instances */ 110) { e.rejectValue("age", "too.darn.old"); } } }]]> 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. 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 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 <interfacename>BeanWrapper</interfacename> The 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 properties Setting 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 Expression Explanation name Indicates the property name corresponding to the methods getName() or isName() and setName(..) account.name Indicates 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 collection account[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 company
Built-in <interface>PropertyEditor</interface> 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. 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 <literal>PropertyEditors</literal> Class Explanation ByteArrayPropertyEditor Editor for byte arrays. Strings will simply be converted to their corresponding byte representations. Registered by default by BeanWrapperImpl. 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 BeanWrapperImpl. CustomBooleanEditor 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 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 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 Capable of resolving Strings to java.io.File objects. Registered by default by BeanWrapperImpl. InputStreamEditor 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. LocaleEditor 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 Capable of resolving Strings to JDK 1.5 Pattern objects and vice versa. 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. 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. URLEditor 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. // 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. // 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 <interfacename>PropertyEditors</interfacename> 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. 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 object Finally, we use CustomEditorConfigurer to register the new PropertyEditor with the ApplicationContext, which will then be able to use it as needed: ]]>
Using <interfacename>PropertyEditorRegistrars</interfacename> 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: // 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 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.
Spring 3 Type Conversion Spring 3 introduces a core.convert package that provides a general type conversion system. The system defines an API to implement type conversion logic, as well as an API to execute type conversions at runtime. Within a Spring container, if configured, 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 API The API to implement type conversion logic is simple and strongly typed: { 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.converters 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.converters; public 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 a ConverterFactory: { 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: { public Converter getConverter(Class targetType) { return new StringToEnum(targetType); } private final class StringToEnum implements Converter { private Class enumType; public StringToEnum(Class enumType) { this.enumType = enumType; } public T convert(String source) { return (T) Enum.valueOf(this.enumType, source.trim()); } } }]]>
ConversionService API The ConversionService defines a public 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); }]]> Most ConversionService implementations also implement ConverterRegistry, which provides an SPI for registering converters. Internally, a ConversionService implementation delegates to its registered Converters and ConverterFactories to carry out type conversion logic. Two ConversionService implementations are provided with the system in the core.convert.support package. GenericConversionService is a generic implementation designed to be explicitly configured, either programatically or declaratively as a Spring bean. DefaultConversionService is a subclass that pre-registers the common Converters in the core.converter package as a convenience.
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 the DefaultConversionService with Spring, simply configure it as a bean with the id conversionService: ]]> To override the default set of converters with your own custom converter(s), set the converters property: ]]>
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: extends Printer, Parser { }]]> 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: { private String pattern; public DateFormatter(String pattern) { this.pattern = pattern; } public String print(Date date, Locale locale) { if (date == null) { return ""; } return getDateFormat(locale).format(date); } public Date parse(String formatted, Locale locale) throws ParseException { if (formatted.length() == 0) { return null; } return getDateFormat(locale).parse(formatted); } protected DateFormat getDateFormat(Locale locale) { DateFormat dateFormat = new SimpleDateFormat(this.pattern, locale); dateFormat.setLenient(false); return dateFormat; } }]]> 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(); 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: { public Set> getFieldTypes() { 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); } private Formatter configureFormatterFrom(NumberFormat annotation, Class fieldType) { if (!annotation.pattern().isEmpty()) { return new NumberFormatter(annotation.pattern()); } else { Style style = annotation.style(); if (style == Style.PERCENT) { return new PercentFormatter(); } else if (style == Style.CURRENCY) { return new CurrencyFormatter(); } else { return new NumberFormatter(); } } } }]]> 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):
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, Printer printer, Parser parser); void addFormatterForFieldType(Class 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: ]]> 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 FormatingConversionServiceFactoryBean 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 can take advantage of. You may also define your own custom constraints. To illustrate, consider a simple Person model with two 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 a 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. Using LocalValidatorFactoryBean programmatically If you choose to use LocalValidatorFactoryBean programmatically – i.e., by instantiating it directly – make sure you call its afterPropertiesSet() method. Otherwise, the LocalValidatorFactoryBean will not be initialized properly.
Injecting a Validator LocalValidatorFactoryBean implements both javax.validation.Validator and org.springframework.validation.Validator. You may inject a reference to one of these two 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 public class MyService { @Autowired private Validator validator; 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: 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 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()); // bind to the target object binder.bind(propertyValues); // validate the target object 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 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: Second, you may call setValidator(Validator) on the global WebBindingInitializer. This allows you to configure a Validator instance across all @Controllers: ]]>
Configuring a JSR-303 Validator for use by Spring MVC With JSR-303, the default javax.validation.Validator implementation is generic. A single instance typically coordinates the validation of all application objects that declare validation constraints. To configure such a general purpose Validator for use by Spring MVC, simply inject a LocalValidatorFactoryBean reference into the WebBindingInitializer. A full configuration example showing injection of a JSR-303 backed Validator into Spring MVC is shown below: ]]> With this 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 ConstaintViolations will automatically be exposed as errors in the BindingResult renderable by standard Spring MVC form tags.
Spring 3 Object Mapping There are scenarios, particularly in large message-oriented business applications, where object transformation is required. For example, consider a complex Web Service where there is a separation between the data exchange model and the internal domain model used to structure business logic. In cases like this, a general-purpose object-to-object mapping facility can be useful for automating the mapping between these disparate models. Spring 3 introduces such a facility built on the Spring Expression Language (SpEL). This facility is described in this section.
Mapper API The API to implement object mapping logic is simple and strongly typed: { T map(S source, T target); }]]> To create your own Mapper, simply implement the interface above. Parameterize S as the type you are mapping from, and T as the type you are mapping to. The source and target arguments provided to you should never be null. Your Mapper may throw any RuntimeException if mapping fails. Take care to ensure your Mapper implementation is thread-safe. Consider the following hand-coded Mapper example: public class PersonDtoPersonMapper implements Mapper<PersonDto, Person> { public Person map(PersonDto source, Person target) { String[] names = source.getName().split(" "); target.setFirstName(names[0]); target.setLastName(names[1]); return target; } } In this trivial example, the Mapper maps the PersonDto's name property to the Person's firstName and lastName properties. The fully mapped Person object is returned.
General Purpose Object Mapper Implementation A general purpose object-to-object mapping system exists in the org.springframework.mapping.support package. Built on the Spring Expression Language (SpEL), this system is capable of mapping between a variety of object types, including JavaBeans, Arrays, Collections, and Maps. It can perform field-to-field, field-to-multi-field, multi-field-to-field, and conditional mappings. It also can carry out type conversion and recursive mapping, which are often required with rich object models.
Usage To obtain a general purpose object Mapper with its default configuration, simply call MappingFactory.getDefaultMapper(). Then invoke the Mapper by calling its map(Object, Object) operation: By default, the defaultMapper will map the fields on the source and target that have the same names. If the field types differ, the mapping system will attempt a type conversion using Spring 3's type conversion system. Nested bean properties are mapped recursively. Any mapping failures will trigger a MappingException to be thrown. If there are multiple failures, they will be collected and returned in the MappingException thrown to the caller. To illustrate this default behavior, consider the following source object type: And the following target object type: Now mapped in the following service method: In this example, the number, name, and address properties are automatically mapped since they are present on both the source and target objects. The AccountDto's address property is a JavaBean, so its nested properties are also recursively mapped. Recursively, the street and zip properties are automatically mapped since they are both present on the nested AddressDto and Address objects. Nothing is mapped to the Address's city and state properties since these properties do not exist on the AddressDto source.
Registering Explicit Mappings When default mapping rules are not sufficient, explicit mapping rules can be registered by obtaining a MapperBuilder and using it to construct a Mapper. Explicit mapping rules always override the default rule. The MapperBuilder provides a fluent API for registering object-to-object Mapping rules: mapper = MappingFactory.mappingBuilder(PersonDto.class, Person.class) .addMapping(...) .addMapping(...) .getMapper(); ]]>
Mapping between two fields with different names Suppose you need to map AccountDto.name to Account.fullName. Since these two field names are not the same, the default auto-mapping rule would not apply. Handle a requirement like this by explicitly registering a mapping rule: In the example above, the name field will be mapped to the fullName field when the mapper is executed. No default mapping will be performed for name since an explicit mapping rule has been configured for this field.
Mapping a single field to multiple fields Suppose you need to map PersonDto.name to Person.firstName and Person.lastName. Handle a field-to-multi-field requirement like this by explicitly registering a mapping rule: () { public Person map(String name, Person person) { String[] names = name.split(" "); person.setFirstName(names[0]); person.setLastName(names[1]); return person; } });]]> In the example above, the first part of the name field will be mapped to the firstName field and the second part will be mapped to the lastName field. No default mapping will be performed for name since an explicit mapping rule has been configured for this field.
Mapping multiple fields to a single field Suppose you need to map CreateAccountDto.activationDay and CreateAccountDto.activationTime to Account.activationDateTime. Handle a multi-field-to-field requirement like this by explicitly registering a mapping rule: () { public Account map(CreateAccountDto dto, Account account) { DateTime dateTime = ISODateTimeFormat.dateTime().parseDateTime( dto.getActivationDay() + "T" + dto.getActivationTime()); account.setActivationDateTime(dateTime); return account; } });]]> In the example above, the activationDay and activationTime fields are mapped to the single activationDateTime field. No default mapping is performed for activationDay or activationTime since an explicit mapping rule has been configured for these fields.
Mapping conditionally Suppose you need to map Map.countryCode to PhoneNumber.countryCode only if the source Map contains a international phone number. Handle conditional mapping requirements like this by explicitly registering a mapping rule: In the example above, the countryCode field will only be mapped if the international field is 'true'. international == 'true' is a boolean expression that must evaluate to true for the mapping to be executed. No default mapping is performed for countryCode since an explicit mapping rule has been configured for this field.
Forcing Explicit Mappings You can force that all mapping rules be explicitly defined by disabling the "auto mapping" feature:
Registering Custom Mapping Converters Sometimes you need to apply field specific type conversion or data transformation logic when mapping a value. Do this by registering a converter with a Mapping: () { public String convert(String value) { // do transformation // return transformed value } });]]>
Ignoring Fields Sometimes you need to exclude a specific field on a source object from being mapped. Do this by marking one or more source fields as excluded:
Registering Custom Type Converters You may also register custom Converters to convert values between mapped fields of different types: () { public Date convert(String value) { // do conversion // return transformed value } });]]> The example Converter above will be invoked anytime a String field is mapped to a Date field.
Registering Custom Nested Mappers When mapping between two object graphs, you may find you need to register explicit mapping rules for nested bean properties. Do this by adding a nested Mapper: () { public Address map(AddressDto source, Address target) { // do target bean mapping here return target; } });]]> The example Mapper above will map nested AddressDto properties to nested Address properties. This particular nested Mapper is "hand-coded", but it could have easily been another Mapper instance built by a MapperBuilder.
Further Reading Consult the JavaDocs of MapperFactory and MapperBuilder in the org.springframework.mapping.support package for more information on the available configuration options. Dozer is another general-purpose object mapper available in the open source Java community. Check it out at dozer.sourceforge.net.