Spring 3 Field Formatting - Java-Springs

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:

package org.springframework.format;
public interface Formatter<T> extends Printer<T>, Parser<T> {
}

Where Formatter extends from the Printer and Parser building-block interfaces:

public interface Printer<T> {
String print(T fieldValue, Locale locale);
}
import java.text.ParseException;
public interface Parser<T> {
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 Illegal Argument Exception 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 Number Formatter, Currency Formatter, and Percent Formatter to format java.lang.Number objects using a java.text. Number Format. The datetime package provides a Date Formatter to format java.util.Date objects with a java.text.Date Format. The datetime.joda package provides comprehensive datetime formatting support based on the Joda Time library.

Consider DateFormatter as an example Formatter implementation:

package org.springframework.format.datetime;
public final class DateFormatter implements Formatter<Date> {
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;
}
}

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 Annotation Formatter Factory:

package org.springframework.format;
public interface AnnotationFormatterFactory<A extends Annotation> {
Set<Class<?>> 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.spring framework.format.annotation. Date Time Format.Have get Field Types() 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 get Parser() return a Parser to parse a clientValue for an annotated field.

The example Annotation Formatter Factory implementation below binds the @Number Format Annotation to a formatter. This annotation allows either a number style or pattern to be specified:

public final class NumberFormatAnnotationFormatterFactory
implements AnnotationFormatterFactory<NumberFormat> {
public Set<Class<?>> getFieldTypes() {
return new HashSet<Class<?>>(asList(new Class<?>[] {
Short.class, Integer.class, Long.class, Float.class,
Double.class, BigDecimal.class, BigInteger.class }));
}
public Printer<Number> getPrinter
(NumberFormat annotation,Class<?> fieldType) {
return configureFormatterFrom(annotation, fieldType);
}
public Parser<Number> getParser
(NumberFormat annotation,Class<?> fieldType) {
return configureFormatterFrom(annotation, fieldType);
}
private Formatter<Number>
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:

public class MyModel {
@NumberFormat(style=Style.CURRENCY)
private BigDecimal decimal;
}

Format Annotation API

A portable format annotation API exists in the org.spring frame work.format.annotation package. Use @Number Format 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 @Date Time Format to format a java.util.Date as a ISO Date (yyyy-MM-dd):

public class MyModel {
@DateTimeFormat(iso=ISO.DATE)
private Date date;
}

FormatterRegistry SPI

At runtime, Formatters are registered in a Formatter Registry. The Formatter Registry 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:

package org.springframework.format;
public interface FormatterRegistry {
void addFormatterForFieldType
(Class<?> 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.

Formatting Conversion Service is the implementation of Formatter Registry suitable for most environments.This implementation may be configured programatically, or declaratively as a Spring bean using Formatting Conversion Service Factory Bean.Because this implemementation also implements Conversion Service, it can be directly configured for use with Spring's Data Binder and the Spring Expression Language (SpEL).

Configuring Formatting in Spring MVC

In a Spring MVC application, you may configure a custom Conversion Service 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.

With this one-line of configuation, default formatters for Numbers and Date types will be installed, including support for the @Number Format and @DateTimeFormat annotations.Full support for the Joda Time formatting library is also installed if Joda Time is present on the classpath.

A custom Conversion Service instance is often constructed by a Factory Bean that internally registers custom Formatters and Converters programatically before the Conversion Service is returned.See Formatting Conversion Service Factory Bean for an example.


All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Java-Springs Topics