<linklinkend="core.convert"><filename>core.convert</filename></link> is a simple, general-purpose type conversion system.
It provides a strongly-typed Converter SPI for implementing <emphasis>one-way</emphasis>conversion logic from one type to another and is not limited to just converting Strings.
<linklinkend="core.convert"><filename>core.convert</filename></link> is a general-purpose type conversion system.
It provides a strongly-typed Converter SPI for implementing conversion logic 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 to bind bean property values.
In addition, both the Spring Expression Language (SpEL) and DataBinder can use this system to coerce values.
In addition, both the Spring Expression Language (SpEL) and DataBinder can use this system to bind values.
For example, when SpEL needs to coerce a <classname>Short</classname> to a <classname>Long</classname> to complete an <function>expression.setValue(Object bean, Object value)</function> attempt, the core.convert system performs the coercion.
</para>
<para>
Now consider the type conversion requirements of a typical client environment such as a web or desktop application.
In such environments, you typically convert <emphasis>from String</emphasis> to support the client postback process, as well as back <emphasis>to String</emphasis> to support the rendering process.
The more general <emphasis>core.convert</emphasis> Converter SPI does not address this specific common scenario directly.
To directly address this, Spring 3 introduces a conveient <emphasis>format</emphasis> SPI that provides a simple and robust alternative to PropertyEditors in a client environment.
In such environments, you typically convert <emphasis>from String</emphasis> to support the client postback process, as well as back <emphasis>to String</emphasis> to support the view rendering process.
The more general <emphasis>core.convert</emphasis> Converter SPI does not address this scenario directly.
To directly address this, Spring 3 introduces a conveient <emphasis>format</emphasis> SPI that provides a simple and robust alternative to PropertyEditors for client environments.
</para>
<para>
In general, use the Converter SPI when you need to implement general-purpose type conversion logic.
Use Formatters when you're working in a client environment, such as an HTML form of a web application and need to apply String parsing, printing, and localization logic to form field values.
Use Formatters when you're working in a client environment, such as a web application, and need to apply String parsing, printing, and localization logic to form field values.
</para>
<sectionid="ui-format-Formatter-SPI">
<sectionid="format-Formatter-SPI">
<title>Formatter SPI</title>
<para>
The <literal>org.springframework.format</literal> SPI to implement field formatting logic is simple and strongly typed:
Several Formatter implementations are provided in <filename>format</filename>subpackages as a convenience.
The <filename>datetime</filename> package provides a DateFormatter to format java.util.Date objects with a java.text.DateFormat.
The <filename>number</filename> package provides a DecimalFormatter, IntegerFormatter, CurrencyFormatter, and PercentFormatter to format java.lang.Number objects using a java.text.NumberFormat.
The <filename>number</filename> package provides a NumberFormatter, CurrencyFormatter, and PercentFormatter to format java.lang.Number objects using a java.text.NumberFormat.
The <filename>datetime.joda</filename> package provides comprehensive datetime formatting support based on the <ulinkurl="http://joda-time.sourceforge.net">Joda Time library</ulink>.
</para>
<para>
...
...
@@ -1002,13 +1002,13 @@ public final class DateFormatter implements Formatter<Date> {
The Spring team welcomes community-driven Formatter contributions; see <ulinkurl="http://jira.springframework.org">http://jira.springframework.org</ulink> to contribute.
</para>
</section>
<sectionid="ui-format-CustomFormatAnnotations">
<sectionid="format-CustomFormatAnnotations">
<title>Custom Format Annotations</title>
<para>
Field formatting can be triggered by annotating model properties.
To bind a custom annotation to a Formatter instance, implement AnnotationFormatterFactory:
</para>
<programlistinglanguage="java"><![CDATA[
<programlistinglanguage="java"><![CDATA[
package org.springframework.format;
public interface AnnotationFormatterFactory<A extends Annotation> {
...
...
@@ -1019,45 +1019,91 @@ public interface AnnotationFormatterFactory<A extends Annotation> {
Parameterize A to be the field annotationType you wish to associate formatting logic with, for example <code>org.springframework.format.annotation.DateTimeFormat</code>.
Implement the <methodname>getFieldTypes</methodname> operation return the types of fields the annotation may be used on.
Implement the <methodname>getPrinter</methodname> operation to return the Printer to print the value of an annotated field.
Implement the <methodname>getParser</methodname> operation to return the Parser to parse the value of an annotated field.
Take care to ensure your AnnotationFormatterFactory implementation is thread-safe.
</para>
<para>
The example implementation below binds a @DecimalFormat instance to a Formatter instance.
This particular annotation allows the NumberFormat pattern to be configured.
</para>
<programlistinglanguage="java"><![CDATA[
public class DecimalAnnotationFormatterFactory implements AnnotationFormatterFactory<DecimalFormat, Number> {
Then, to trigger formatting, simply annotate a property with @DecimalFormat in your model:
</para>
<programlistinglanguage="java"><![CDATA[
}]]>
</programlisting>
<para>
Parameterize A to be the field annotationType you wish to associate formatting logic with, for example <code>org.springframework.format.annotation.DateTimeFormat</code>.
Implement the <methodname>getFieldTypes</methodname> operation return the types of fields the annotation may be used on.
Implement the <methodname>getPrinter</methodname> operation to return the Printer to print the value of an annotated field.
Implement the <methodname>getParser</methodname> operation to return the Parser to parse the value of an annotated field.
Take care to ensure your AnnotationFormatterFactory implementation is thread-safe.
</para>
<para>
The example implementation below binds a @NumberFormat instance to a Formatter instance.
This particular annotation allows the NumberFormat style or pattern to be specified:
</para>
<programlistinglanguage="java"><![CDATA[
public final class NumberFormatAnnotationFormatterFactory implements AnnotationFormatterFactory<NumberFormat> {
public Set<Class<?>> getFieldTypes() {
Set<Class<?>> fieldTypes = new HashSet<Class<?>>(7);
fieldTypes.add(Short.class);
fieldTypes.add(Integer.class);
fieldTypes.add(Long.class);
fieldTypes.add(Float.class);
fieldTypes.add(Double.class);
fieldTypes.add(BigDecimal.class);
fieldTypes.add(BigInteger.class);
return fieldTypes;
}
public Printer<Number> getPrinter(NumberFormat annotation, Class<?> fieldType) {
Then, to trigger formatting, simply annotate a property with @NumberFormat in your model:
</para>
<programlistinglanguage="java"><![CDATA[
public class MyModel {
@DecimalFormat("#,###")
@NumberFormat(style=Style.CURRENCY)
private BigDecimal decimal;
}]]></programlisting>
</section>
}]]>
</programlisting>
<para>
A format annotation API exists in the <filename>org.springframework.format.annotation</filename> package.
Use the NumberFormat annotation to apply formatting to java.lang.Number fields.
Use the DateTimeFormat annotation to apply formatting to java.util.Date, java.util.Calendar, java.util.Long, or Joda Time fields.
</para>
<para>
The example below shows use of the DateTimeFormat annotation to format a java.util.Date as a ISO Date (yyyy-MM-dd):
</para>
<programlistinglanguage="java"><![CDATA[
public class MyModel {
@DateTimeFormat(iso=ISO.DATE)
private Date date;
}]]>
</programlisting>
</section>
<sectionid="ui-format-FormatterRegistry-SPI">
<sectionid="format-FormatterRegistry-SPI">
<title>FormatterRegistry SPI</title>
<para>
Formatters can be 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.
When installed, Formatters are registered in a FormatterRegistry.
A FormatterRegistry 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.
As shown above, Formatters may be registered by field type or annotation.
<classname>GenericFormatterRegistry</classname> is the implementation suitable for use in most UI binding environments.
This implementation may be configured programatically or declaratively as a Spring bean.
As shown above, Formatters can be registered by fieldType or annotation.
<classname>FormattingConversionService</classname> is the implementation of <classname>FormatterRegistry</classname> suitable for most environments.
This implementation may be configured programatically or declaratively as a Spring bean with <classname>FormattingConversionServiceFactoryBean</classname>.
Because it also implements <classname>ConversionService</classname>, it can be configured for use with Spring's DataBinder as well as SpEL.
<title>Configuring Formatting in Spring MVC</title>
<para>
A FormatterRegistry is designed to be instantiated at application startup, then shared between multiple threads.
In a Spring MVC application, you configure a FormatterRegistry as a property of the WebBindingInitializer.
The FormatterRegistry will then be configured whenever a DataBinder is created by Spring MVC to bind and render model properties.
In a Spring MVC application, you can configure a ConversionService instance explicity as an attribute of the <literal>annotation-driven</literal> element of the MVC namespace.
This ConversionService will then be used any time type conversion is needed during Controller model binding.
If not configured explicitly, Spring MVC will configure a FormattingConversionService instance that registers default formatters for number and date types.
</para>
<note>
<para>
If no FormatterRegistry is configured, the original PropertyEditor-based system is used.
</para>
</note>
<para>
To register a FormatterRegistry with Spring MVC, simply configure it as a property of a custom WebBindingInitializer injected into the
Spring MVC AnnotationMethodHandlerAdapter:
To rely on default formatting rules, no explicit 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.
This also includes full support for the Joda Time formatting library if Joda Time is present on the classpath.
</para>
<para>
To inject a ConversionService instance with custom formatters/converters registered, set the conversion-service attribute:
When using the @Formatted annotation, no explicit Formatter or AnnotationFormatterFactory registration is required.
See the JavaDocs for GenericFormatterRegistry for more configuration options.
A custom ConversionService instance is often constructed by a FactoryBean, which internally registers custom Formatters and Converters programatically before the ConversionService is returned.
See FormatingConversionServiceFactoryBean for an example.