FormatterRegistry extends ConverterRegistry now; FormattingConversionService extends GenericConversionService
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.format;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
@@ -23,9 +24,10 @@ import org.springframework.core.convert.converter.ConverterRegistry;
|
||||
* A registry of field formatting logic.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface FormatterRegistry {
|
||||
public interface FormatterRegistry extends ConverterRegistry {
|
||||
|
||||
/**
|
||||
* Adds a Formatter to format fields of a specific type.
|
||||
@@ -57,14 +59,5 @@ public interface FormatterRegistry {
|
||||
* @param annotationFormatterFactory the annotation formatter factory to add
|
||||
*/
|
||||
void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);
|
||||
|
||||
/**
|
||||
* Returns the registry of Converters that coerse field values to types required by Formatters.
|
||||
* Allows clients to register their own custom converters directly.
|
||||
* For example, a date/time formatting configuration might expect a java.util.Date field value to be coersed to a Long for formatting.
|
||||
* Registering a simpler DateToLongConverter allievates the need to register multiple formatters for closely related types.
|
||||
* @return the converter registry, allowing new Converters to be registered
|
||||
*/
|
||||
ConverterRegistry getConverterRegistry();
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.format.support;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
@@ -21,13 +22,13 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.core.convert.support.ConversionServiceFactory;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.format.AnnotationFormatterFactory;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
@@ -35,29 +36,30 @@ import org.springframework.format.Parser;
|
||||
import org.springframework.format.Printer;
|
||||
|
||||
/**
|
||||
* A ConversionService implementation designed to be configured as a {@link FormatterRegistry}..
|
||||
* A {@link org.springframework.core.convert.ConversionService} implementation
|
||||
* designed to be configured as a {@link FormatterRegistry}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public class FormattingConversionService implements FormatterRegistry, ConversionService {
|
||||
public class FormattingConversionService extends GenericConversionService
|
||||
implements FormatterRegistry {
|
||||
|
||||
private ConversionService conversionService = ConversionServiceFactory.createDefaultConversionService();
|
||||
|
||||
// implementing FormattingRegistry
|
||||
|
||||
public void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser) {
|
||||
getConverterRegistry().addGenericConverter(new PrinterConverter(fieldType, printer, this.conversionService));
|
||||
getConverterRegistry().addGenericConverter(new ParserConverter(fieldType, parser, this.conversionService));
|
||||
addGenericConverter(new PrinterConverter(fieldType, printer, this));
|
||||
addGenericConverter(new ParserConverter(fieldType, parser, this));
|
||||
}
|
||||
|
||||
public void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter) {
|
||||
getConverterRegistry().addGenericConverter(new PrinterConverter(fieldType, formatter, this.conversionService));
|
||||
getConverterRegistry().addGenericConverter(new ParserConverter(fieldType, formatter, this.conversionService));
|
||||
addGenericConverter(new PrinterConverter(fieldType, formatter, this));
|
||||
addGenericConverter(new ParserConverter(fieldType, formatter, this));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void addFormatterForFieldAnnotation(final AnnotationFormatterFactory annotationFormatterFactory) {
|
||||
final Class<? extends Annotation> annotationType = resolveAnnotationType(annotationFormatterFactory);
|
||||
final Class<? extends Annotation> annotationType = (Class<? extends Annotation>)
|
||||
GenericTypeResolver.resolveTypeArgument(annotationFormatterFactory.getClass(), AnnotationFormatterFactory.class);
|
||||
if (annotationType == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to extract parameterized Annotation type argument from AnnotationFormatterFactory ["
|
||||
@@ -65,74 +67,44 @@ public class FormattingConversionService implements FormatterRegistry, Conversio
|
||||
+ "]; does the factory parameterize the <A extends Annotation> generic type?");
|
||||
}
|
||||
Set<Class<?>> fieldTypes = annotationFormatterFactory.getFieldTypes();
|
||||
|
||||
for (final Class<?> fieldType : fieldTypes) {
|
||||
getConverterRegistry().addGenericConverter(new ConditionalGenericConverter() {
|
||||
addGenericConverter(new ConditionalGenericConverter() {
|
||||
public Class<?>[][] getConvertibleTypes() {
|
||||
return new Class<?>[][] { { fieldType, String.class } };
|
||||
return new Class<?>[][] {{fieldType, String.class}};
|
||||
}
|
||||
public boolean matches(TypeDescriptor sourceFieldType, TypeDescriptor targetFieldType) {
|
||||
return sourceFieldType.getAnnotation(annotationType) != null;
|
||||
return (sourceFieldType.getAnnotation(annotationType) != null);
|
||||
}
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
Printer<?> printer = annotationFormatterFactory.getPrinter(sourceType.getAnnotation(annotationType), sourceType.getType());
|
||||
return new PrinterConverter(fieldType, printer, conversionService).convert(source, sourceType, targetType);
|
||||
return new PrinterConverter(fieldType, printer, FormattingConversionService.this).convert(source, sourceType, targetType);
|
||||
}
|
||||
public String toString() {
|
||||
return "@" + annotationType.getName() + " " + fieldType.getName() + " -> " + String.class.getName() + " : " + annotationFormatterFactory;
|
||||
return "@" + annotationType.getName() + " " + fieldType.getName() + " -> " +
|
||||
String.class.getName() + ": " + annotationFormatterFactory;
|
||||
}
|
||||
});
|
||||
getConverterRegistry().addGenericConverter(new ConditionalGenericConverter() {
|
||||
addGenericConverter(new ConditionalGenericConverter() {
|
||||
public Class<?>[][] getConvertibleTypes() {
|
||||
return new Class<?>[][] { { String.class, fieldType } };
|
||||
return new Class<?>[][] {{String.class, fieldType}};
|
||||
}
|
||||
public boolean matches(TypeDescriptor sourceFieldType, TypeDescriptor targetFieldType) {
|
||||
return targetFieldType.getAnnotation(annotationType) != null;
|
||||
return (targetFieldType.getAnnotation(annotationType) != null);
|
||||
}
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
Parser<?> parser = annotationFormatterFactory.getParser(targetType.getAnnotation(annotationType), targetType.getType());
|
||||
return new ParserConverter(fieldType, parser, conversionService).convert(source, sourceType, targetType);
|
||||
return new ParserConverter(fieldType, parser, FormattingConversionService.this).convert(source, sourceType, targetType);
|
||||
}
|
||||
public String toString() {
|
||||
return String.class.getName() + " -> @" + annotationType.getName() + " " + fieldType.getName() + " : " + annotationFormatterFactory;
|
||||
return String.class.getName() + " -> @" + annotationType.getName() + " " +
|
||||
fieldType.getName() + ": " + annotationFormatterFactory;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public ConverterRegistry getConverterRegistry() {
|
||||
return (ConverterRegistry) this.conversionService;
|
||||
}
|
||||
|
||||
// implementing ConverisonService
|
||||
|
||||
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
|
||||
return canConvert(TypeDescriptor.valueOf(sourceType), TypeDescriptor.valueOf(targetType));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T convert(Object source, Class<T> targetType) {
|
||||
return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
|
||||
}
|
||||
|
||||
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.conversionService.canConvert(sourceType, targetType);
|
||||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.conversionService.convert(source, sourceType, targetType);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.conversionService.toString();
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class<? extends Annotation> resolveAnnotationType(AnnotationFormatterFactory<?> annotationFormatterFactory) {
|
||||
return (Class<? extends Annotation>) GenericTypeResolver.resolveTypeArgument(annotationFormatterFactory.getClass(), AnnotationFormatterFactory.class);
|
||||
}
|
||||
|
||||
private static class PrinterConverter implements GenericConverter {
|
||||
|
||||
private Class<?> fieldType;
|
||||
@@ -172,6 +144,7 @@ public class FormattingConversionService implements FormatterRegistry, Conversio
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class ParserConverter implements GenericConverter {
|
||||
|
||||
private Class<?> fieldType;
|
||||
@@ -198,22 +171,24 @@ public class FormattingConversionService implements FormatterRegistry, Conversio
|
||||
Object parsedValue;
|
||||
try {
|
||||
parsedValue = this.parser.parse(submittedValue, LocaleContextHolder.getLocale());
|
||||
} catch (ParseException e) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, e);
|
||||
}
|
||||
catch (ParseException ex) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, ex);
|
||||
}
|
||||
TypeDescriptor parsedObjectType = TypeDescriptor.valueOf(parsedValue.getClass());
|
||||
if (!parsedObjectType.isAssignableTo(targetType)) {
|
||||
try {
|
||||
parsedValue = this.conversionService.convert(parsedValue, parsedObjectType, targetType);
|
||||
} catch (ConversionFailedException e) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, e);
|
||||
}
|
||||
catch (ConversionException ex) {
|
||||
throw new ConversionFailedException(sourceType, targetType, source, ex);
|
||||
}
|
||||
}
|
||||
return parsedValue;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return String.class.getName() + " -> " + this.fieldType.getName() + " : " + this.parser;
|
||||
return String.class.getName() + " -> " + this.fieldType.getName() + ": " + this.parser;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,11 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.format.support;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.ConversionServiceFactory;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.datetime.joda.JodaTimeFormattingConfigurer;
|
||||
import org.springframework.format.number.NumberFormatAnnotationFormatterFactory;
|
||||
@@ -25,40 +26,47 @@ import org.springframework.format.number.NumberFormatter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* A factory for a FormattingConversionService that installs default formatters for common types such as numbers and datetimes.
|
||||
* Subclasses may override {@link #installFormatters(FormatterRegistry)} to register custom formatters.
|
||||
* A factory for a {@link FormattingConversionService} that installs default
|
||||
* formatters for common types such as numbers and datetimes.
|
||||
*
|
||||
* <p>Subclasses may override {@link #installFormatters(FormatterRegistry)}
|
||||
* to register custom formatters.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public class FormattingConversionServiceFactoryBean implements FactoryBean<ConversionService>, InitializingBean {
|
||||
public class FormattingConversionServiceFactoryBean
|
||||
implements FactoryBean<FormattingConversionService>, InitializingBean {
|
||||
|
||||
private static final boolean jodaTimePresent = ClassUtils.isPresent(
|
||||
"org.joda.time.DateTime", FormattingConversionService.class.getClassLoader());
|
||||
|
||||
private FormattingConversionService conversionService;
|
||||
|
||||
// implementing InitializingBean
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
this.conversionService = new FormattingConversionService();
|
||||
ConversionServiceFactory.addDefaultConverters(this.conversionService);
|
||||
installFormatters(this.conversionService);
|
||||
}
|
||||
|
||||
// implementing FactoryBean
|
||||
|
||||
public ConversionService getObject() {
|
||||
public FormattingConversionService getObject() {
|
||||
return this.conversionService;
|
||||
}
|
||||
|
||||
public Class<ConversionService> getObjectType() {
|
||||
return ConversionService.class;
|
||||
public Class<? extends FormattingConversionService> getObjectType() {
|
||||
return FormattingConversionService.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
// subclassing hooks
|
||||
|
||||
/**
|
||||
* Install Formatters and Converters into the new FormattingConversionService using the FormatterRegistry SPI.
|
||||
@@ -72,4 +80,4 @@ public class FormattingConversionServiceFactoryBean implements FactoryBean<Conve
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user