From aff628f1775fb320666830d5e0949097f38e92ef Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Wed, 2 Sep 2009 23:34:01 +0000 Subject: [PATCH] converter / formatter docs initial commit git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1798 50f2f4bb-b051-0410-bef5-90022cba6387 --- spring-framework-reference/src/validation.xml | 333 +++++++++++++++++- 1 file changed, 324 insertions(+), 9 deletions(-) diff --git a/spring-framework-reference/src/validation.xml b/spring-framework-reference/src/validation.xml index 8049b8b7d72..0fae35b2dd7 100644 --- a/spring-framework-reference/src/validation.xml +++ b/spring-framework-reference/src/validation.xml @@ -26,17 +26,16 @@ The BeanWrapper is a fundamental concept in the Spring Framework and is used in a lot of places. However, you probably - will not ever have the need to use the BeanWrapper directly. Because this + 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're explaining the BeanWrapper in this chapter since if you were - going to use it at all, you would probably do so when trying to bind - data to objects, which is strongly related to the BeanWrapper. + 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 uses PropertyEditors all over the place. The concept of a - PropertyEditor is part of the JavaBeans specification. Just as the - BeanWrapper, it's best to explain the use of PropertyEditors in this - chapter as well, since it's closely related to the BeanWrapper and the - DataBinder. + 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. +
@@ -749,4 +748,320 @@ public final class CustomPropertyEditorRegistrar implements PropertyEditorRegist
+
+ Spring 3 Type Conversion + + Spring 3 introduces a core.convert package that provides a general type conversion system. + The system defines a SPI to implement type conversion logic, as well as a 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 coersion is needed. + +
+ Converter SPI + + The SPI to implement type conversion logic is simple and strongly typed: + + { + T convert(S source) throws Exception; +}]]> + + + To create your own Converter, simply implement the Converter interface. + 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 is often thrown to report an invalid source value. + Take special 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 to from String to Numbers and other common types. + Note StringToInteger as an example Converter implementation: + + { + public Integer convert(String source) { + return Integer.valueOf(source); + } +}]]> + +
+
+ ConversionService API + + The ConversionService defines a public API for executing type conversion logic at runtime. + Converters are always executed behind this API. + User code should not depend on the Converter SPI. + + sourceType, Class targetType); + + T convert(Object source, Class targetType); + +}]]> + + + Most ConversionService implementations also implement ConverterRegistry, which provides a SPI for registering converters. + Internally, a ConversionService implementation delegates to its registered Converters 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 on 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 converter set 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 any other bean: + + + +
+
+ +
+ Spring 3 UI Field Formatting + + The core.convert is a simple, general-purpose type conversion system. + It addresses one-way conversion from one type to another, and is not limited to just converting Strings. + As discussed in the previous section, a Spring Container can be configured to use this system when binding bean property values. + In addition, the Spring Expression Language (SpEL) uses this system to coerce Expression values. + For example, when SpEL needs to coerse a Short to a Long to fullfill a expression.setValue attempt, the core.convert system performs the coersion. + + + Now consider the type conversion requirements of a typical UI environment such as a web or desktop application. + In such environments, you typically convert from String to support the postback process, as well as back to String to support the rendering process. + The more general core.convert system does not address this specific scenario directly. + To directly address this, Spring 3 introduces a new ui.format system that provides a simple and robust alternative to PropertyEditors in a UI environment. + + + In general, use Converters when you need implement general-purpose type conversion logic; logic that may be invoked by the Spring Container, SpEL, or your own code as part of a one-way binding process. + Use Formatters when you're working in a UI environment such as a HTML form of a web application, and need to apply two-way parsing, formatting, and localization logic to form field values. + +
+ Formatter SPI + + The SPI to implement UI formatting logic is simple and strongly typed: + + { + String format(T object, Locale locale); + + T parse(String formatted, Locale locale) throws ParseException; +}]]> + + + To create your own Formatter, simply implement the Formatter interface above. + Parameterize T to be the type of Object you are formatting; for example, java.lang.BigDecimal. + Implement the format operation to format 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 if a parse attempt fails. + Take special care to ensure your Formatter implementation is thread safe. + + + Several Formatter implementations are provided in subpackages of ui.format as a convenience. + The date package provides a DateFormatter to format java.util.Date objects with a java.text.DateFormat. + The number package provides a DecimalFormatter, IntegerFormatter, CurrencyFormatter, and PercentFormatter for formatting java.lang.Number objects using a java.text.NumberFormat. + Note DateFormatter as an example Formatter implementation: + + { + + private String pattern; + + public DateFormatter(String pattern) { + this.pattern = pattern; + } + + public String format(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; + } + +}]]> + +
+
+ @Formatted Annotation + + The @Formatted annotation allows you to easily configure the Formatter implementation to use for one or more of your model classes. + To use this feature, simply annotate your class as @Formatted and specify the Formatter implementation to use as the annotation value: + + + + + The example above says "Money objects should be formatted by MoneyFormatter". + With this configuation, whenever a field binds to a Money property, the MoneyFormatter implementation will format the field value. + When referenced by a @Formatted annotation, a Formatter implementation must declare a public default constructor. + +
+
+ Custom Format Annotations + + The presence of field or method annotations on properties of your model objects can also trigger field-specific formatting logic. + The binding between a custom annotation and a specific Formatter instance is made by implementing a custom AnnotationFormatterFactory: + + { + Formatter getFormatter(A annotation); +} +]]> + + + The example implementation below binds a custom @DecimalFormat annotation to a Number Formatter instance. + The annotation allows the format pattern to be configured as its value. + + { + + Formatter getFormatter(DecimalFormat annotation) { + DecimalFormatter formatter = DecimalFormatter(); + formatter.setPattern(annotation.value()); + return formatter; + } + +} +]]> + + + Then, to trigger somewhere in your model: + + + +
+
+ FormatterRegistry SPI + + Formatters are often registered in a FormatterRegistry. + A DataBinder uses this registry to resolve the Formatter to use for a specific field. + This allows you to configure default Formatting rules centrally, rather than duplicating such configuration across your UI 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 field formatting is needed. + + + Review the FormatterRegistry SPI below: + + type, Formatter targetFormatter); + + void add(AnnotationFormatterFactory factory); +}]]> + + + As shown above, Formatters may be registered by field type or annotation. + GenericFormatterRegistry is the implementation suitable for use in most UI binding environments. + This implementation may be configured programatically or declatively as a Spring bean. + +
+
+ Configuring a FormatterRegistry + + + + + + +
+
+ Registering field-specific Formatters + + + + + + +
+
+