|
|
|
@ -17,6 +17,8 @@ |
|
|
|
package org.springframework.ui.format.support; |
|
|
|
package org.springframework.ui.format.support; |
|
|
|
|
|
|
|
|
|
|
|
import java.lang.annotation.Annotation; |
|
|
|
import java.lang.annotation.Annotation; |
|
|
|
|
|
|
|
import java.lang.reflect.Method; |
|
|
|
|
|
|
|
import java.lang.reflect.Modifier; |
|
|
|
import java.text.ParseException; |
|
|
|
import java.text.ParseException; |
|
|
|
import java.util.LinkedList; |
|
|
|
import java.util.LinkedList; |
|
|
|
import java.util.Locale; |
|
|
|
import java.util.Locale; |
|
|
|
@ -38,6 +40,7 @@ import org.springframework.ui.format.Formatted; |
|
|
|
import org.springframework.ui.format.Formatter; |
|
|
|
import org.springframework.ui.format.Formatter; |
|
|
|
import org.springframework.ui.format.FormatterRegistry; |
|
|
|
import org.springframework.ui.format.FormatterRegistry; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
|
|
|
|
import org.springframework.util.ReflectionUtils; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* A generic implementation of {@link org.springframework.ui.format.FormatterRegistry} |
|
|
|
* A generic implementation of {@link org.springframework.ui.format.FormatterRegistry} |
|
|
|
@ -46,25 +49,28 @@ import org.springframework.util.Assert; |
|
|
|
* @author Keith Donald |
|
|
|
* @author Keith Donald |
|
|
|
* @author Juergen Hoeller |
|
|
|
* @author Juergen Hoeller |
|
|
|
* @since 3.0 |
|
|
|
* @since 3.0 |
|
|
|
|
|
|
|
* @see #setFormatters(Set) |
|
|
|
|
|
|
|
* @see #setFormatterMap(Map) |
|
|
|
|
|
|
|
* @see #setAnnotationFormatterMap(Map) |
|
|
|
|
|
|
|
* @see #setAnnotationFormatterFactories(Set) |
|
|
|
* @see #setConversionService(ConversionService) |
|
|
|
* @see #setConversionService(ConversionService) |
|
|
|
* @see #add(org.springframework.ui.format.Formatter) |
|
|
|
* @see #addFormatterByType(Formatter) |
|
|
|
* @see #add(Class, org.springframework.ui.format.Formatter) |
|
|
|
* @see #addFormatterByType(Class, Formatter) |
|
|
|
* @see #add(org.springframework.ui.format.AnnotationFormatterFactory) |
|
|
|
* @see #addFormatterByAnnotation(Class, Formatter) |
|
|
|
|
|
|
|
* @see #addFormatterByAnnotation(AnnotationFormatterFactory) |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class GenericFormatterRegistry implements FormatterRegistry, ApplicationContextAware, Cloneable { |
|
|
|
public class GenericFormatterRegistry implements FormatterRegistry, ApplicationContextAware, Cloneable { |
|
|
|
|
|
|
|
|
|
|
|
private final Map<Class, Formatter> typeFormatters = new ConcurrentHashMap<Class, Formatter>(); |
|
|
|
private final Map<Class, FormatterHolder> typeFormatters = new ConcurrentHashMap<Class, FormatterHolder>(); |
|
|
|
|
|
|
|
|
|
|
|
private final Map<Class, AnnotationFormatterFactory> annotationFormatters = |
|
|
|
private final Map<Class, AnnotationFormatterFactoryHolder> annotationFormatters = new ConcurrentHashMap<Class, AnnotationFormatterFactoryHolder>(); |
|
|
|
new ConcurrentHashMap<Class, AnnotationFormatterFactory>(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private ConversionService conversionService = new DefaultConversionService(); |
|
|
|
private ConversionService conversionService; |
|
|
|
|
|
|
|
|
|
|
|
private ApplicationContext applicationContext; |
|
|
|
private ApplicationContext applicationContext; |
|
|
|
|
|
|
|
|
|
|
|
private boolean shared = true; |
|
|
|
private boolean shared = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Registers the formatters in the set provided. |
|
|
|
* Registers the formatters in the set provided. |
|
|
|
* JavaBean-friendly alternative to calling {@link #addFormatterByType(Formatter)}. |
|
|
|
* JavaBean-friendly alternative to calling {@link #addFormatterByType(Formatter)}. |
|
|
|
@ -130,15 +136,14 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC |
|
|
|
* Take the context's default ConversionService if none specified locally. |
|
|
|
* Take the context's default ConversionService if none specified locally. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public void setApplicationContext(ApplicationContext context) { |
|
|
|
public void setApplicationContext(ApplicationContext context) { |
|
|
|
if (this.conversionService == null && |
|
|
|
if (this.conversionService == null |
|
|
|
context.containsBean(ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME)) { |
|
|
|
&& context.containsBean(ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME)) { |
|
|
|
this.conversionService = context.getBean( |
|
|
|
this.conversionService = context.getBean(ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME, |
|
|
|
ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME, ConversionService.class); |
|
|
|
ConversionService.class); |
|
|
|
} |
|
|
|
} |
|
|
|
this.applicationContext = context; |
|
|
|
this.applicationContext = context; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// cloning support
|
|
|
|
// cloning support
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -175,98 +180,120 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC |
|
|
|
return clone; |
|
|
|
return clone; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// implementing FormatterRegistry
|
|
|
|
// implementing FormatterRegistry
|
|
|
|
|
|
|
|
|
|
|
|
public void addFormatterByType(Class<?> type, Formatter<?> formatter) { |
|
|
|
public void addFormatterByType(Class<?> type, Formatter<?> formatter) { |
|
|
|
Class<?> formattedObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class); |
|
|
|
Class<?> formattedObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class); |
|
|
|
if (!this.conversionService.canConvert(formattedObjectType, type)) { |
|
|
|
if (formattedObjectType != null && !type.isAssignableFrom(formattedObjectType)) { |
|
|
|
throw new IllegalArgumentException("Unable to register Formatter " + formatter + " for type [" + |
|
|
|
if (this.conversionService == null) { |
|
|
|
type.getName() + "]; not able to convert from [" + formattedObjectType.getName() + "] to parse"); |
|
|
|
throw new IllegalStateException("Unable to index Formatter " + formatter + " under type [" |
|
|
|
} |
|
|
|
+ type.getName() + "]; unable to convert from [" + formattedObjectType.getName() |
|
|
|
if (!this.conversionService.canConvert(type, formattedObjectType)) { |
|
|
|
+ "] parsed by Formatter because this.conversionService is null"); |
|
|
|
throw new IllegalArgumentException("Unable to register Formatter " + formatter + " for type [" + |
|
|
|
} |
|
|
|
type.getName() + "]; not able to convert to [" + formattedObjectType.getName() + "] to format"); |
|
|
|
if (!this.conversionService.canConvert(formattedObjectType, type)) { |
|
|
|
} |
|
|
|
throw new IllegalArgumentException("Unable to index Formatter " + formatter + " under type [" |
|
|
|
this.typeFormatters.put(type, formatter); |
|
|
|
+ type.getName() + "]; not able to convert from [" + formattedObjectType.getName() |
|
|
|
|
|
|
|
+ "] to parse"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!this.conversionService.canConvert(type, formattedObjectType)) { |
|
|
|
|
|
|
|
throw new IllegalArgumentException("Unable to index Formatter " + formatter + " under type [" |
|
|
|
|
|
|
|
+ type.getName() + "]; not able to convert to [" + formattedObjectType.getName() |
|
|
|
|
|
|
|
+ "] to format"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this.typeFormatters.put(type, new FormatterHolder(formattedObjectType, formatter)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public <T> void addFormatterByType(Formatter<T> formatter) { |
|
|
|
public void addFormatterByType(Formatter<?> formatter) { |
|
|
|
Class<?> formattedObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class); |
|
|
|
Class<?> formattedObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class); |
|
|
|
this.typeFormatters.put(formattedObjectType, formatter); |
|
|
|
if (formattedObjectType == null) { |
|
|
|
|
|
|
|
throw new IllegalArgumentException("Unable to register Formatter " + formatter |
|
|
|
|
|
|
|
+ "; cannot determine parameterized object type <T>"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this.typeFormatters.put(formattedObjectType, new FormatterHolder(formattedObjectType, formatter)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void addFormatterByAnnotation(Class<? extends Annotation> annotationType, Formatter<?> formatter) { |
|
|
|
public void addFormatterByAnnotation(Class<? extends Annotation> annotationType, Formatter<?> formatter) { |
|
|
|
this.annotationFormatters.put(annotationType, new SimpleAnnotationFormatterFactory(formatter)); |
|
|
|
Class<?> formattedObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class); |
|
|
|
|
|
|
|
SimpleAnnotationFormatterFactory factory = new SimpleAnnotationFormatterFactory(formatter); |
|
|
|
|
|
|
|
this.annotationFormatters.put(annotationType, |
|
|
|
|
|
|
|
new AnnotationFormatterFactoryHolder(formattedObjectType, factory)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public <A extends Annotation, T> void addFormatterByAnnotation(AnnotationFormatterFactory<A, T> factory) { |
|
|
|
public void addFormatterByAnnotation(AnnotationFormatterFactory<?, ?> factory) { |
|
|
|
Class[] typeArgs = GenericTypeResolver.resolveTypeArguments(factory.getClass(), AnnotationFormatterFactory.class); |
|
|
|
Class[] typeArgs = GenericTypeResolver.resolveTypeArguments(factory.getClass(), |
|
|
|
if (typeArgs == null) { |
|
|
|
AnnotationFormatterFactory.class); |
|
|
|
|
|
|
|
if (typeArgs == null || typeArgs.length != 2) { |
|
|
|
throw new IllegalArgumentException( |
|
|
|
throw new IllegalArgumentException( |
|
|
|
"Unable to extract Annotation type A argument from AnnotationFormatterFactory [" + |
|
|
|
"Unable to extract parameterized type arguments from AnnotationFormatterFactory [" |
|
|
|
factory.getClass().getName() + "]; does the factory parameterize the <A> generic type?"); |
|
|
|
+ factory.getClass().getName() |
|
|
|
|
|
|
|
+ "]; does the factory parameterize the <A> and <T> generic types?"); |
|
|
|
} |
|
|
|
} |
|
|
|
this.annotationFormatters.put(typeArgs[0], factory); |
|
|
|
this.annotationFormatters.put(typeArgs[0], new AnnotationFormatterFactoryHolder(typeArgs[1], factory)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
|
|
|
|
public <T> Formatter<T> getFormatter(Class<T> targetType) { |
|
|
|
|
|
|
|
return (Formatter<T>) getFormatter(TypeDescriptor.valueOf(targetType)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
|
|
|
|
public Formatter<Object> getFormatter(TypeDescriptor type) { |
|
|
|
public Formatter<Object> getFormatter(TypeDescriptor type) { |
|
|
|
Assert.notNull(type, "TypeDescriptor is required"); |
|
|
|
Assert.notNull(type, "TypeDescriptor is required"); |
|
|
|
Formatter<Object> formatter = getAnnotationFormatter(type); |
|
|
|
FormatterHolder holder = findFormatterHolderForAnnotatedProperty(type.getAnnotations()); |
|
|
|
if (formatter == null) { |
|
|
|
if (holder == null) { |
|
|
|
formatter = getTypeFormatter(type.getType()); |
|
|
|
holder = findFormatterHolderForType(type.getType()); |
|
|
|
} |
|
|
|
} |
|
|
|
if (formatter != null) { |
|
|
|
if (holder == null) { |
|
|
|
Class<?> formattedObjectType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class); |
|
|
|
holder = getDefaultFormatterHolder(type); |
|
|
|
if (!type.getType().isAssignableFrom(formattedObjectType)) { |
|
|
|
} |
|
|
|
return new ConvertingFormatter(type.getType(), formattedObjectType, formatter); |
|
|
|
if (holder == null) { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Class formattedObjectType = holder.getFormattedObjectType(); |
|
|
|
|
|
|
|
if (formattedObjectType != null && !type.getType().isAssignableFrom(formattedObjectType)) { |
|
|
|
|
|
|
|
if (this.conversionService != null) { |
|
|
|
|
|
|
|
return new ConvertingFormatter(type, holder); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return holder.getFormatter(); |
|
|
|
} |
|
|
|
} |
|
|
|
return formatter; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// internal helpers
|
|
|
|
// internal helpers
|
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
private FormatterHolder findFormatterHolderForAnnotatedProperty(Annotation[] annotations) { |
|
|
|
private Formatter getAnnotationFormatter(TypeDescriptor type) { |
|
|
|
for (Annotation annotation : annotations) { |
|
|
|
Annotation[] annotations = type.getAnnotations(); |
|
|
|
FormatterHolder holder = findFormatterHolderForAnnotation(annotation); |
|
|
|
for (Annotation ann : annotations) { |
|
|
|
if (holder != null) { |
|
|
|
AnnotationFormatterFactory factory = this.annotationFormatters.get(ann.annotationType()); |
|
|
|
return holder; |
|
|
|
if (factory != null) { |
|
|
|
|
|
|
|
return factory.getFormatter(ann); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
Formatted formattedAnnotation = ann.annotationType().getAnnotation(Formatted.class); |
|
|
|
|
|
|
|
if (formattedAnnotation != null) { |
|
|
|
|
|
|
|
Formatter formatter = createFormatter(formattedAnnotation.value()); |
|
|
|
|
|
|
|
this.annotationFormatters.put(ann.annotationType(), new SimpleAnnotationFormatterFactory(formatter)); |
|
|
|
|
|
|
|
return formatter; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Formatter getTypeFormatter(Class<?> type) { |
|
|
|
private FormatterHolder findFormatterHolderForAnnotation(Annotation annotation) { |
|
|
|
Formatter formatter = findFormatter(type); |
|
|
|
Class<? extends Annotation> annotationType = annotation.annotationType(); |
|
|
|
return (formatter != null ? formatter : getDefaultFormatter(type)); |
|
|
|
AnnotationFormatterFactoryHolder factory = this.annotationFormatters.get(annotationType); |
|
|
|
|
|
|
|
if (factory != null) { |
|
|
|
|
|
|
|
return factory.getFormatterHolder(annotation); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
Formatted formattedAnnotation = annotationType.getAnnotation(Formatted.class); |
|
|
|
|
|
|
|
if (formattedAnnotation != null) { |
|
|
|
|
|
|
|
// annotation has @Formatted meta-annotation
|
|
|
|
|
|
|
|
Formatter formatter = createFormatter(formattedAnnotation.value()); |
|
|
|
|
|
|
|
addFormatterByAnnotation(annotationType, formatter); |
|
|
|
|
|
|
|
return findFormatterHolderForAnnotation(annotation); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Formatter<?> findFormatter(Class<?> type) { |
|
|
|
private FormatterHolder findFormatterHolderForType(Class type) { |
|
|
|
LinkedList<Class> classQueue = new LinkedList<Class>(); |
|
|
|
LinkedList<Class> classQueue = new LinkedList<Class>(); |
|
|
|
classQueue.addFirst(type); |
|
|
|
classQueue.addFirst(type); |
|
|
|
while (!classQueue.isEmpty()) { |
|
|
|
while (!classQueue.isEmpty()) { |
|
|
|
Class currentClass = classQueue.removeLast(); |
|
|
|
Class currentClass = classQueue.removeLast(); |
|
|
|
Formatter<?> formatter = this.typeFormatters.get(currentClass); |
|
|
|
FormatterHolder holder = this.typeFormatters.get(currentClass); |
|
|
|
if (formatter != null) { |
|
|
|
if (holder != null) { |
|
|
|
return formatter; |
|
|
|
return holder; |
|
|
|
} |
|
|
|
} |
|
|
|
if (currentClass.getSuperclass() != null) { |
|
|
|
if (currentClass.getSuperclass() != null) { |
|
|
|
classQueue.addFirst(currentClass.getSuperclass()); |
|
|
|
classQueue.addFirst(currentClass.getSuperclass()); |
|
|
|
@ -279,52 +306,98 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Formatter<?> getDefaultFormatter(Class<?> type) { |
|
|
|
private FormatterHolder getDefaultFormatterHolder(TypeDescriptor typeDescriptor) { |
|
|
|
|
|
|
|
Class type = typeDescriptor.getType(); |
|
|
|
Formatted formatted = AnnotationUtils.findAnnotation(type, Formatted.class); |
|
|
|
Formatted formatted = AnnotationUtils.findAnnotation(type, Formatted.class); |
|
|
|
if (formatted != null) { |
|
|
|
if (formatted != null) { |
|
|
|
Formatter formatter = createFormatter(formatted.value()); |
|
|
|
Formatter formatter = createFormatter(formatted.value()); |
|
|
|
this.typeFormatters.put(type, formatter); |
|
|
|
addFormatterByType(type, formatter); |
|
|
|
return formatter; |
|
|
|
return findFormatterHolderForType(type); |
|
|
|
} |
|
|
|
} else { |
|
|
|
else { |
|
|
|
Method valueOfMethod = getValueOfMethod(type); |
|
|
|
return null; |
|
|
|
if (valueOfMethod != null) { |
|
|
|
|
|
|
|
Formatter formatter = createFormatter(valueOfMethod); |
|
|
|
|
|
|
|
addFormatterByType(type, formatter); |
|
|
|
|
|
|
|
return findFormatterHolderForType(type); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Formatter<?> createFormatter(Class<? extends Formatter> formatterClass) { |
|
|
|
private Formatter createFormatter(Class<? extends Formatter> formatterClass) { |
|
|
|
return (this.applicationContext != null ? |
|
|
|
return (this.applicationContext != null ? this.applicationContext.getAutowireCapableBeanFactory().createBean( |
|
|
|
this.applicationContext.getAutowireCapableBeanFactory().createBean(formatterClass) : |
|
|
|
formatterClass) : BeanUtils.instantiate(formatterClass)); |
|
|
|
BeanUtils.instantiate(formatterClass)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Method getValueOfMethod(Class type) { |
|
|
|
|
|
|
|
Method[] methods = type.getDeclaredMethods(); |
|
|
|
|
|
|
|
for (int i = 0; i < methods.length; i++) { |
|
|
|
|
|
|
|
Method method = methods[i]; |
|
|
|
|
|
|
|
if ("valueOf".equals(method.getName()) && acceptsSingleStringParameterType(method) |
|
|
|
|
|
|
|
&& Modifier.isPublic(method.getModifiers()) && Modifier.isStatic(method.getModifiers())) { |
|
|
|
|
|
|
|
return method; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private class ConvertingFormatter implements Formatter { |
|
|
|
private boolean acceptsSingleStringParameterType(Method method) { |
|
|
|
|
|
|
|
Class[] paramTypes = method.getParameterTypes(); |
|
|
|
|
|
|
|
if (paramTypes == null) { |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return paramTypes.length == 1 && paramTypes[0] == String.class; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private final Class<?> type; |
|
|
|
private Formatter createFormatter(Method valueOfMethod) { |
|
|
|
|
|
|
|
return new ValueOfMethodFormatter(valueOfMethod); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private final Class<?> formattedObjectType; |
|
|
|
private abstract static class AbstractFormatterHolder { |
|
|
|
|
|
|
|
|
|
|
|
private final Formatter targetFormatter; |
|
|
|
private Class formattedObjectType; |
|
|
|
|
|
|
|
|
|
|
|
public ConvertingFormatter(Class<?> type, Class<?> formattedObjectType, Formatter targetFormatter) { |
|
|
|
public AbstractFormatterHolder(Class formattedObjectType) { |
|
|
|
this.type = type; |
|
|
|
|
|
|
|
this.formattedObjectType = formattedObjectType; |
|
|
|
this.formattedObjectType = formattedObjectType; |
|
|
|
this.targetFormatter = targetFormatter; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
public Class<?> getFormattedObjectType() { |
|
|
|
public String format(Object object, Locale locale) { |
|
|
|
return formattedObjectType; |
|
|
|
object = conversionService.convert(object, this.formattedObjectType); |
|
|
|
|
|
|
|
return this.targetFormatter.format(object, locale); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public Object parse(String formatted, Locale locale) throws ParseException { |
|
|
|
} |
|
|
|
Object parsed = this.targetFormatter.parse(formatted, locale); |
|
|
|
|
|
|
|
parsed = conversionService.convert(parsed, this.type); |
|
|
|
private static class FormatterHolder extends AbstractFormatterHolder { |
|
|
|
return parsed; |
|
|
|
|
|
|
|
|
|
|
|
private Formatter formatter; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public FormatterHolder(Class formattedObjectType, Formatter formatter) { |
|
|
|
|
|
|
|
super(formattedObjectType); |
|
|
|
|
|
|
|
this.formatter = formatter; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Formatter getFormatter() { |
|
|
|
|
|
|
|
return this.formatter; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static class AnnotationFormatterFactoryHolder extends AbstractFormatterHolder { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private AnnotationFormatterFactory factory; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public AnnotationFormatterFactoryHolder(Class formattedObjectType, AnnotationFormatterFactory factory) { |
|
|
|
|
|
|
|
super(formattedObjectType); |
|
|
|
|
|
|
|
this.factory = factory; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public FormatterHolder getFormatterHolder(Annotation annotation) { |
|
|
|
|
|
|
|
return new FormatterHolder(getFormattedObjectType(), this.factory.getFormatter(annotation)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static class SimpleAnnotationFormatterFactory implements AnnotationFormatterFactory { |
|
|
|
private static class SimpleAnnotationFormatterFactory implements AnnotationFormatterFactory { |
|
|
|
|
|
|
|
|
|
|
|
@ -339,4 +412,51 @@ public class GenericFormatterRegistry implements FormatterRegistry, ApplicationC |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static class ValueOfMethodFormatter implements Formatter { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Method valueOfMethod; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ValueOfMethodFormatter(Method valueOfMethod) { |
|
|
|
|
|
|
|
this.valueOfMethod = valueOfMethod; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public String format(Object object, Locale locale) { |
|
|
|
|
|
|
|
if (object == null) { |
|
|
|
|
|
|
|
return ""; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
return object.toString(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Object parse(String formatted, Locale locale) throws ParseException { |
|
|
|
|
|
|
|
return ReflectionUtils.invokeMethod(valueOfMethod, null, formatted); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private class ConvertingFormatter implements Formatter { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final TypeDescriptor type; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final FormatterHolder formatterHolder; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public ConvertingFormatter(TypeDescriptor type, FormatterHolder formatterHolder) { |
|
|
|
|
|
|
|
this.type = type; |
|
|
|
|
|
|
|
this.formatterHolder = formatterHolder; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public String format(Object object, Locale locale) { |
|
|
|
|
|
|
|
object = GenericFormatterRegistry.this.conversionService.convert(object, this.formatterHolder |
|
|
|
|
|
|
|
.getFormattedObjectType()); |
|
|
|
|
|
|
|
return this.formatterHolder.getFormatter().format(object, locale); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Object parse(String formatted, Locale locale) throws ParseException { |
|
|
|
|
|
|
|
Object parsed = this.formatterHolder.getFormatter().parse(formatted, locale); |
|
|
|
|
|
|
|
parsed = GenericFormatterRegistry.this.conversionService.convert(parsed, TypeDescriptor |
|
|
|
|
|
|
|
.valueOf(this.formatterHolder.getFormattedObjectType()), this.type); |
|
|
|
|
|
|
|
return parsed; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|