SPR-7912 Introduce FormatterRegistrar interface and FormattingConversionServiceFactoryBean enhancements.
This commit is contained in:
parent
9dd6f467b9
commit
149348c907
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.format;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
/**
|
||||
* Registers {@link Converter Converters} and {@link Formatter Formatters} with
|
||||
* a FormattingConversionService through the {@link FormatterRegistry} SPI.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface FormatterRegistrar {
|
||||
|
||||
/**
|
||||
* Register Formatters and Converters with a FormattingConversionService
|
||||
* through a FormatterRegistry SPI.
|
||||
* @param registry the FormatterRegistry instance to use.
|
||||
*/
|
||||
void registerFormatters(FormatterRegistry registry);
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -13,7 +13,6 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.format.datetime.joda;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
|
@ -27,7 +26,7 @@ import org.joda.time.ReadableInstant;
|
|||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
|
||||
import org.springframework.format.FormatterRegistrar;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.Parser;
|
||||
import org.springframework.format.Printer;
|
||||
|
|
@ -37,14 +36,14 @@ import org.springframework.format.Printer;
|
|||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @since 3.1
|
||||
* @see #setDateStyle
|
||||
* @see #setTimeStyle
|
||||
* @see #setDateTimeStyle
|
||||
* @see #setUseIsoFormat
|
||||
* @see #installJodaTimeFormatting
|
||||
*/
|
||||
public class JodaTimeFormattingConfigurer {
|
||||
public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
private String dateStyle;
|
||||
|
||||
|
|
@ -54,7 +53,6 @@ public class JodaTimeFormattingConfigurer {
|
|||
|
||||
private boolean useIsoFormat;
|
||||
|
||||
|
||||
/**
|
||||
* Set the default format style of Joda {@link LocalDate} objects.
|
||||
* Default is {@link DateTimeFormat#shortDate()}.
|
||||
|
|
@ -89,33 +87,28 @@ public class JodaTimeFormattingConfigurer {
|
|||
this.useIsoFormat = useIsoFormat;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Install Joda Time formatters given the current configuration of this {@link JodaTimeFormattingConfigurer}.
|
||||
*/
|
||||
public void installJodaTimeFormatting(FormatterRegistry formatterRegistry) {
|
||||
JodaTimeConverters.registerConverters(formatterRegistry);
|
||||
public void registerFormatters(FormatterRegistry registry) {
|
||||
JodaTimeConverters.registerConverters(registry);
|
||||
|
||||
DateTimeFormatter jodaDateFormatter = getJodaDateFormatter();
|
||||
formatterRegistry.addFormatterForFieldType(LocalDate.class,
|
||||
new ReadablePartialPrinter(jodaDateFormatter), new DateTimeParser(jodaDateFormatter));
|
||||
registry.addFormatterForFieldType(LocalDate.class, new ReadablePartialPrinter(jodaDateFormatter),
|
||||
new DateTimeParser(jodaDateFormatter));
|
||||
|
||||
DateTimeFormatter jodaTimeFormatter = getJodaTimeFormatter();
|
||||
formatterRegistry.addFormatterForFieldType(LocalTime.class,
|
||||
new ReadablePartialPrinter(jodaTimeFormatter), new DateTimeParser(jodaTimeFormatter));
|
||||
registry.addFormatterForFieldType(LocalTime.class, new ReadablePartialPrinter(jodaTimeFormatter),
|
||||
new DateTimeParser(jodaTimeFormatter));
|
||||
|
||||
DateTimeFormatter jodaDateTimeFormatter = getJodaDateTimeFormatter();
|
||||
Parser<DateTime> dateTimeParser = new DateTimeParser(jodaDateTimeFormatter);
|
||||
formatterRegistry.addFormatterForFieldType(LocalDateTime.class,
|
||||
new ReadablePartialPrinter(jodaDateTimeFormatter), dateTimeParser);
|
||||
registry.addFormatterForFieldType(LocalDateTime.class, new ReadablePartialPrinter(jodaDateTimeFormatter),
|
||||
dateTimeParser);
|
||||
|
||||
Printer<ReadableInstant> readableInstantPrinter = new ReadableInstantPrinter(jodaDateTimeFormatter);
|
||||
formatterRegistry.addFormatterForFieldType(ReadableInstant.class, readableInstantPrinter, dateTimeParser);
|
||||
registry.addFormatterForFieldType(ReadableInstant.class, readableInstantPrinter, dateTimeParser);
|
||||
|
||||
formatterRegistry.addFormatterForFieldAnnotation(new JodaDateTimeFormatAnnotationFormatterFactory());
|
||||
registry.addFormatterForFieldAnnotation(new JodaDateTimeFormatAnnotationFormatterFactory());
|
||||
}
|
||||
|
||||
|
||||
// internal helpers
|
||||
|
||||
private DateTimeFormatter getJodaDateFormatter() {
|
||||
|
|
@ -125,8 +118,7 @@ public class JodaTimeFormattingConfigurer {
|
|||
if (this.dateStyle != null) {
|
||||
return DateTimeFormat.forStyle(this.dateStyle + "-");
|
||||
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return DateTimeFormat.shortDate();
|
||||
}
|
||||
}
|
||||
|
|
@ -137,8 +129,7 @@ public class JodaTimeFormattingConfigurer {
|
|||
}
|
||||
if (this.timeStyle != null) {
|
||||
return DateTimeFormat.forStyle("-" + this.timeStyle);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return DateTimeFormat.shortTime();
|
||||
}
|
||||
}
|
||||
|
|
@ -149,8 +140,7 @@ public class JodaTimeFormattingConfigurer {
|
|||
}
|
||||
if (this.dateTimeStyle != null) {
|
||||
return DateTimeFormat.forStyle(this.dateTimeStyle);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return DateTimeFormat.shortDateTime();
|
||||
}
|
||||
}
|
||||
|
|
@ -28,22 +28,34 @@ import org.springframework.context.EmbeddedValueResolverAware;
|
|||
import org.springframework.core.convert.support.ConversionServiceFactory;
|
||||
import org.springframework.format.AnnotationFormatterFactory;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.format.FormatterRegistrar;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.Parser;
|
||||
import org.springframework.format.Printer;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.format.datetime.joda.JodaTimeFormattingConfigurer;
|
||||
import org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar;
|
||||
import org.springframework.format.number.NumberFormatAnnotationFormatterFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
/**
|
||||
* A factory for a {@link FormattingConversionService} that installs default
|
||||
* and custom converters and formatters for common types such as numbers
|
||||
* and datetimes .
|
||||
*
|
||||
* <p>A factory for a {@link FormattingConversionService} that installs default
|
||||
* converters and formatters for common types such as numbers and datetimes.
|
||||
*
|
||||
* <p>Converters and formatters can be registered declaratively through
|
||||
* {@link #setConverters(Set)} and {@link #setFormatters(Set)}. Another option
|
||||
* is to register converters and formatters in code by implementing the
|
||||
* {@link FormatterRegistrar} interface. You can then configure provide the set
|
||||
* of registrars to use through {@link #setFormatterRegistrars(Set)}.
|
||||
*
|
||||
* <p>A good example for registering converters and formatters in code is
|
||||
* <code>JodaTimeFormatterRegistrar</code>, which registers a number of
|
||||
* date-related formatters and converters. For a more detailed list of cases
|
||||
* see {@link #setFormatterRegistrars(Set)}
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.0
|
||||
*/
|
||||
public class FormattingConversionServiceFactoryBean
|
||||
|
|
@ -56,15 +68,19 @@ public class FormattingConversionServiceFactoryBean
|
|||
|
||||
private Set<?> formatters;
|
||||
|
||||
private Set<FormatterRegistrar> formatterRegistrars;
|
||||
|
||||
private StringValueResolver embeddedValueResolver;
|
||||
|
||||
private FormattingConversionService conversionService;
|
||||
|
||||
private boolean registerDefaultFormatters = true;
|
||||
|
||||
/**
|
||||
* Configure the set of custom converter objects that should be added.
|
||||
* @param converters instances of
|
||||
* @param converters instances of any of the following:
|
||||
* {@link org.springframework.core.convert.converter.Converter},
|
||||
* {@link org.springframework.core.convert.converter.ConverterFactory} or
|
||||
* {@link org.springframework.core.convert.converter.ConverterFactory},
|
||||
* {@link org.springframework.core.convert.converter.GenericConverter}.
|
||||
*/
|
||||
public void setConverters(Set<?> converters) {
|
||||
|
|
@ -73,22 +89,53 @@ public class FormattingConversionServiceFactoryBean
|
|||
|
||||
/**
|
||||
* Configure the set of custom formatter objects that should be added.
|
||||
* @param formatters instances of {@link Formatter} or {@link AnnotationFormatterFactory}.
|
||||
* @param formatters instances of {@link Formatter} or
|
||||
* {@link AnnotationFormatterFactory}.
|
||||
*/
|
||||
public void setFormatters(Set<?> formatters) {
|
||||
this.formatters = formatters;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Configure the set of FormatterRegistrars to invoke to register
|
||||
* Converters and Formatters in addition to those added declaratively
|
||||
* via {@link #setConverters(Set)} and {@link #setFormatters(Set)}.
|
||||
* <p>FormatterRegistrars are useful when registering multiple related
|
||||
* converters and formatters for a formatting category, such as Date
|
||||
* formatting. All types related needed to support the formatting
|
||||
* category can be registered from one place.
|
||||
* <p>FormatterRegistrars can also be used to register Formatters
|
||||
* indexed under a specific field type different from its own <T>,
|
||||
* or when registering a Formatter from a Printer/Parser pair.
|
||||
* @see FormatterRegistry#addFormatterForFieldType(Class, Formatter)
|
||||
* @see FormatterRegistry#addFormatterForFieldType(Class, Printer, Parser)
|
||||
*/
|
||||
public void setFormatterRegistrars(Set<FormatterRegistrar> formatterRegistrars) {
|
||||
this.formatterRegistrars = formatterRegistrars;
|
||||
}
|
||||
|
||||
public void setEmbeddedValueResolver(StringValueResolver embeddedValueResolver) {
|
||||
this.embeddedValueResolver = embeddedValueResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether default formatters should be registered or not. By
|
||||
* default built-in formatters are registered. This flag can be used to
|
||||
* turn that off and rely on explicitly registered formatters only.
|
||||
* @see #setFormatters(Set)
|
||||
* @see #setFormatterRegistrars(Set)
|
||||
*/
|
||||
public void setRegisterDefaultFormatters(boolean registerDefaultFormatters) {
|
||||
this.registerDefaultFormatters = registerDefaultFormatters;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
this.conversionService = new FormattingConversionService();
|
||||
this.conversionService.setEmbeddedValueResolver(this.embeddedValueResolver);
|
||||
ConversionServiceFactory.addDefaultConverters(this.conversionService);
|
||||
ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
|
||||
installFormatters(this.conversionService);
|
||||
addDefaultFormatters();
|
||||
registerFormatters();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -110,17 +157,30 @@ public class FormattingConversionServiceFactoryBean
|
|||
// subclassing hooks
|
||||
|
||||
/**
|
||||
* Install Formatters and Converters into the new FormattingConversionService using the FormatterRegistry SPI.
|
||||
* Subclasses may override to customize the set of formatters and/or converters that are installed.
|
||||
* Subclasses may override this method to register formatters and/or converters.
|
||||
* Starting with Spring 3.1 however the recommended way of doing that is to
|
||||
* through FormatterRegistrars.
|
||||
* @see #setFormatters(Set)
|
||||
* @see #setFormatterRegistrars(Set)
|
||||
*/
|
||||
protected void installFormatters(FormatterRegistry registry) {
|
||||
registry.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
|
||||
if (jodaTimePresent) {
|
||||
new JodaTimeFormattingConfigurer().installJodaTimeFormatting(registry);
|
||||
}
|
||||
else {
|
||||
registry.addFormatterForFieldAnnotation(new NoJodaDateTimeFormatAnnotationFormatterFactory());
|
||||
}
|
||||
|
||||
// private helper methods
|
||||
|
||||
private void addDefaultFormatters() {
|
||||
if (registerDefaultFormatters) {
|
||||
this.conversionService.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
|
||||
if (jodaTimePresent) {
|
||||
new JodaTimeFormatterRegistrar().registerFormatters(this.conversionService);
|
||||
} else {
|
||||
this.conversionService
|
||||
.addFormatterForFieldAnnotation(new NoJodaDateTimeFormatAnnotationFormatterFactory());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerFormatters() {
|
||||
if (this.formatters != null) {
|
||||
for (Object formatter : this.formatters) {
|
||||
if (formatter instanceof Formatter<?>) {
|
||||
|
|
@ -133,9 +193,14 @@ public class FormattingConversionServiceFactoryBean
|
|||
}
|
||||
}
|
||||
}
|
||||
if (this.formatterRegistrars != null) {
|
||||
for (FormatterRegistrar registrar : this.formatterRegistrars) {
|
||||
registrar.registerFormatters(this.conversionService);
|
||||
}
|
||||
}
|
||||
installFormatters(this.conversionService);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dummy AnnotationFormatterFactory that simply fails if @DateTimeFormat is being used
|
||||
* without the JodaTime library being present.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.format.datetime.joda;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
|
@ -28,10 +30,8 @@ import org.joda.time.LocalDate;
|
|||
import org.joda.time.LocalDateTime;
|
||||
import org.joda.time.LocalTime;
|
||||
import org.junit.After;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.core.convert.support.ConversionServiceFactory;
|
||||
|
|
@ -54,8 +54,8 @@ public class JodaTimeFormattingTests {
|
|||
public void setUp() {
|
||||
ConversionServiceFactory.addDefaultConverters(conversionService);
|
||||
|
||||
JodaTimeFormattingConfigurer configurer = new JodaTimeFormattingConfigurer();
|
||||
configurer.installJodaTimeFormatting(conversionService);
|
||||
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
|
||||
registrar.registerFormatters(conversionService);
|
||||
|
||||
JodaTimeBean bean = new JodaTimeBean();
|
||||
bean.getChildren().add(new JodaTimeBean());
|
||||
|
|
|
|||
Loading…
Reference in New Issue