polishing

This commit is contained in:
Juergen Hoeller 2009-12-09 17:54:02 +00:00
parent 8334a03e03
commit 2ce5090d00
5 changed files with 134 additions and 160 deletions

View File

@ -31,21 +31,7 @@ public interface FormatterRegistry extends ConverterRegistry {
/** /**
* Adds a Formatter to format fields of a specific type. * Adds a Formatter to format fields of a specific type.
* The Formatter will delegate to the specified <code>printer</code> for printing and the specified <code>parser</code> for parsing. * <p>On print, if the Formatter's type T is declared and <code>fieldType</code> is not assignable to T,
* <p>
* On print, if the Printer's type T is declared and <code>fieldType</code> is not assignable to T,
* a coersion to T will be attempted before delegating to <code>printer</code> to print a field value.
* On parse, if the object returned by the Parser is not assignable to the runtime field type,
* a coersion to the field type will be attempted before returning the parsed field value.
* @param fieldType the field type to format
* @param formatter the formatter to add
*/
void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);
/**
* Adds a Formatter to format fields of a specific type.
* <p>
* On print, if the Formatter's type T is declared and <code>fieldType</code> is not assignable to T,
* a coersion to T will be attempted before delegating to <code>formatter</code> to print a field value. * a coersion to T will be attempted before delegating to <code>formatter</code> to print a field value.
* On parse, if the parsed object returned by <code>formatter</code> is not assignable to the runtime field type, * On parse, if the parsed object returned by <code>formatter</code> is not assignable to the runtime field type,
* a coersion to the field type will be attempted before returning the parsed field value. * a coersion to the field type will be attempted before returning the parsed field value.
@ -54,6 +40,20 @@ public interface FormatterRegistry extends ConverterRegistry {
*/ */
void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter); void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);
/**
* Adds a Printer/Parser pair to format fields of a specific type.
* The formatter will delegate to the specified <code>printer</code> for printing
* and the specified <code>parser</code> for parsing.
* <p>On print, if the Printer's type T is declared and <code>fieldType</code> is not assignable to T,
* a coersion to T will be attempted before delegating to <code>printer</code> to print a field value.
* On parse, if the object returned by the Parser is not assignable to the runtime field type,
* a coersion to the field type will be attempted before returning the parsed field value.
* @param fieldType the field type to format
* @param printer the printing part of the formatter
* @param parser the parsing part of the formatter
*/
void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);
/** /**
* Adds a Formatter to format fields annotated with a specific format annotation. * Adds a Formatter to format fields annotated with a specific format annotation.
* @param annotationFormatterFactory the annotation formatter factory to add * @param annotationFormatterFactory the annotation formatter factory to add

View File

@ -17,6 +17,7 @@
package org.springframework.format.support; package org.springframework.format.support;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.Set; import java.util.Set;
import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.context.i18n.LocaleContextHolder;
@ -41,19 +42,18 @@ import org.springframework.format.Printer;
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 3.0 * @since 3.0
*/ */
public class FormattingConversionService extends GenericConversionService public class FormattingConversionService extends GenericConversionService implements FormatterRegistry {
implements FormatterRegistry {
public void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser) {
addGenericConverter(new PrinterConverter(fieldType, printer, this));
addGenericConverter(new ParserConverter(fieldType, parser, this));
}
public void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter) { public void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter) {
addGenericConverter(new PrinterConverter(fieldType, formatter, this)); addGenericConverter(new PrinterConverter(fieldType, formatter, this));
addGenericConverter(new ParserConverter(fieldType, formatter, this)); addGenericConverter(new ParserConverter(fieldType, formatter, this));
} }
public void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser) {
addGenericConverter(new PrinterConverter(fieldType, printer, this));
addGenericConverter(new ParserConverter(fieldType, parser, this));
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void addFormatterForFieldAnnotation(final AnnotationFormatterFactory annotationFormatterFactory) { public void addFormatterForFieldAnnotation(final AnnotationFormatterFactory annotationFormatterFactory) {
final Class<? extends Annotation> annotationType = (Class<? extends Annotation>) final Class<? extends Annotation> annotationType = (Class<? extends Annotation>)
@ -68,8 +68,8 @@ public class FormattingConversionService extends GenericConversionService
for (final Class<?> fieldType : fieldTypes) { for (final Class<?> fieldType : fieldTypes) {
addGenericConverter(new ConditionalGenericConverter() { addGenericConverter(new ConditionalGenericConverter() {
public Class<?>[][] getConvertibleTypes() { public Set<ConvertiblePair> getConvertibleTypes() {
return new Class<?>[][] {{fieldType, String.class}}; return Collections.singleton(new ConvertiblePair(fieldType, String.class));
} }
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return (sourceType.getAnnotation(annotationType) != null); return (sourceType.getAnnotation(annotationType) != null);
@ -84,8 +84,8 @@ public class FormattingConversionService extends GenericConversionService
} }
}); });
addGenericConverter(new ConditionalGenericConverter() { addGenericConverter(new ConditionalGenericConverter() {
public Class<?>[][] getConvertibleTypes() { public Set<ConvertiblePair> getConvertibleTypes() {
return new Class<?>[][] {{String.class, fieldType}}; return Collections.singleton(new ConvertiblePair(String.class, fieldType));
} }
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
return (targetType.getAnnotation(annotationType) != null); return (targetType.getAnnotation(annotationType) != null);
@ -121,8 +121,8 @@ public class FormattingConversionService extends GenericConversionService
this.conversionService = conversionService; this.conversionService = conversionService;
} }
public Class<?>[][] getConvertibleTypes() { public Set<ConvertiblePair> getConvertibleTypes() {
return new Class<?>[][] { { this.fieldType, String.class } }; return Collections.singleton(new ConvertiblePair(this.fieldType, String.class));
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -130,7 +130,7 @@ public class FormattingConversionService extends GenericConversionService
if (!sourceType.isAssignableTo(this.printerObjectType)) { if (!sourceType.isAssignableTo(this.printerObjectType)) {
source = this.conversionService.convert(source, sourceType, this.printerObjectType); source = this.conversionService.convert(source, sourceType, this.printerObjectType);
} }
return source != null ? this.printer.print(source, LocaleContextHolder.getLocale()) : ""; return (source != null ? this.printer.print(source, LocaleContextHolder.getLocale()) : "");
} }
private Class<?> resolvePrinterObjectType(Printer<?> printer) { private Class<?> resolvePrinterObjectType(Printer<?> printer) {
@ -157,8 +157,8 @@ public class FormattingConversionService extends GenericConversionService
this.conversionService = conversionService; this.conversionService = conversionService;
} }
public Class<?>[][] getConvertibleTypes() { public Set<ConvertiblePair> getConvertibleTypes() {
return new Class<?>[][] { { String.class, this.fieldType } }; return Collections.singleton(new ConvertiblePair(String.class, this.fieldType));
} }
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {

View File

@ -4,6 +4,7 @@ import static org.junit.Assert.assertTrue;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.Collections;
import org.junit.Test; import org.junit.Test;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
@ -41,8 +42,8 @@ public class ConversionServiceFactoryBeanTests {
} }
}); });
converters.add(new GenericConverter() { converters.add(new GenericConverter() {
public Class<?>[][] getConvertibleTypes() { public Set<ConvertiblePair> getConvertibleTypes() {
return new Class[][] { { String.class, Baz.class } }; return Collections.singleton(new ConvertiblePair(String.class, Baz.class));
} }
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return new Baz(); return new Baz();

View File

@ -26,19 +26,16 @@ import org.springframework.core.BridgeMethodResolver;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* General utility methods for working with annotations, handling bridge methods * General utility methods for working with annotations, handling bridge methods (which the compiler
* (which the compiler generates for generic declarations) as well as super * generates for generic declarations) as well as super methods (for optional &quot;annotation inheritance&quot;).
* methods (for optional &quot;annotation inheritance&quot;). Note that none of * Note that none of this is provided by the JDK's introspection facilities themselves.
* this is provided by the JDK's introspection facilities themselves.
* *
* <p>As a general rule for runtime-retained annotations (e.g. for transaction * <p>As a general rule for runtime-retained annotations (e.g. for transaction control, authorization or service
* control, authorization or service exposure), always use the lookup methods on * exposure), always use the lookup methods on this class (e.g., {@link #findAnnotation(Method, Class)}, {@link
* this class (e.g., {@link #findAnnotation(Method, Class)}, * #getAnnotation(Method, Class)}, and {@link #getAnnotations(Method)}) instead of the plain annotation lookup
* {@link #getAnnotation(Method, Class)}, and {@link #getAnnotations(Method)}) * methods in the JDK. You can still explicitly choose between lookup on the given class level only ({@link
* instead of the plain annotation lookup methods in the JDK. You can still * #getAnnotation(Method, Class)}) and lookup in the entire inheritance hierarchy of the given method ({@link
* explicitly choose between lookup on the given class level only * #findAnnotation(Method, Class)}).
* ({@link #getAnnotation(Method, Class)}) and lookup in the entire inheritance
* hierarchy of the given method ({@link #findAnnotation(Method, Class)}).
* *
* @author Rob Harrop * @author Rob Harrop
* @author Juergen Hoeller * @author Juergen Hoeller
@ -51,8 +48,7 @@ import org.springframework.util.Assert;
public abstract class AnnotationUtils { public abstract class AnnotationUtils {
/** The attribute name for annotations with a single element */ /** The attribute name for annotations with a single element */
static final String VALUE = "value"; static final String VALUE = "value";
/** /**
* Get all {@link Annotation Annotations} from the supplied {@link Method}. * Get all {@link Annotation Annotations} from the supplied {@link Method}.
@ -66,8 +62,7 @@ public abstract class AnnotationUtils {
} }
/** /**
* Get a single {@link Annotation} of <code>annotationType</code> from the * Get a single {@link Annotation} of <code>annotationType</code> from the supplied {@link Method}.
* supplied {@link Method}.
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler. * <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
* @param method the method to look for annotations on * @param method the method to look for annotations on
* @param annotationType the annotation class to look for * @param annotationType the annotation class to look for
@ -89,11 +84,9 @@ public abstract class AnnotationUtils {
} }
/** /**
* Get a single {@link Annotation} of <code>annotationType</code> from the * Get a single {@link Annotation} of <code>annotationType</code> from the supplied {@link Method},
* supplied {@link Method}, traversing its super methods if no annotation * traversing its super methods if no annotation can be found on the given method itself.
* can be found on the given method itself. * <p>Annotations on methods are not inherited by default, so we need to handle this explicitly.
* <p>Annotations on methods are not inherited by default, so we need to handle
* this explicitly.
* @param method the method to look for annotations on * @param method the method to look for annotations on
* @param annotationType the annotation class to look for * @param annotationType the annotation class to look for
* @return the annotation found, or <code>null</code> if none found * @return the annotation found, or <code>null</code> if none found
@ -101,8 +94,8 @@ public abstract class AnnotationUtils {
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) { public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
A annotation = getAnnotation(method, annotationType); A annotation = getAnnotation(method, annotationType);
Class<?> cl = method.getDeclaringClass(); Class<?> cl = method.getDeclaringClass();
if(annotation == null) { if (annotation == null) {
annotation = searchForAnnotationOnInterfaces(method, annotationType, cl.getInterfaces()); annotation = searchOnInterfaces(method, annotationType, cl.getInterfaces());
} }
while (annotation == null) { while (annotation == null) {
cl = cl.getSuperclass(); cl = cl.getSuperclass();
@ -112,8 +105,8 @@ public abstract class AnnotationUtils {
try { try {
Method equivalentMethod = cl.getDeclaredMethod(method.getName(), method.getParameterTypes()); Method equivalentMethod = cl.getDeclaredMethod(method.getName(), method.getParameterTypes());
annotation = getAnnotation(equivalentMethod, annotationType); annotation = getAnnotation(equivalentMethod, annotationType);
if(annotation == null) { if (annotation == null) {
annotation = searchForAnnotationOnInterfaces(method, annotationType, cl.getInterfaces()); annotation = searchOnInterfaces(method, annotationType, cl.getInterfaces());
} }
} }
catch (NoSuchMethodException ex) { catch (NoSuchMethodException ex) {
@ -123,9 +116,9 @@ public abstract class AnnotationUtils {
return annotation; return annotation;
} }
private static <A extends Annotation> A searchForAnnotationOnInterfaces(Method method, Class<A> annotationType, Class[] ifaces) { private static <A extends Annotation> A searchOnInterfaces(Method method, Class<A> annotationType, Class[] ifcs) {
A annotation = null; A annotation = null;
for (Class<?> iface : ifaces) { for (Class<?> iface : ifcs) {
Method equivalentMethod = null; Method equivalentMethod = null;
try { try {
equivalentMethod = iface.getDeclaredMethod(method.getName(), method.getParameterTypes()); equivalentMethod = iface.getDeclaredMethod(method.getName(), method.getParameterTypes());
@ -142,19 +135,14 @@ public abstract class AnnotationUtils {
} }
/** /**
* Find a single {@link Annotation} of <code>annotationType</code> from the * Find a single {@link Annotation} of <code>annotationType</code> from the supplied {@link Class}, traversing its
* supplied {@link Class}, traversing its interfaces and super classes * interfaces and super classes if no annotation can be found on the given class itself. <p>This method explicitly
* if no annotation can be found on the given class itself. * handles class-level annotations which are not declared as {@link java.lang.annotation.Inherited inherited} <i>as
* <p>This method explicitly handles class-level annotations which are * well as annotations on interfaces</i>. <p>The algorithm operates as follows: Searches for an annotation on the given
* not declared as {@link java.lang.annotation.Inherited inherited} * class and returns it if found. Else searches all interfaces that the given class declares, returning the annotation
* <i>as well as annotations on interfaces</i>. * from the first matching candidate, if any. Else proceeds with introspection of the superclass of the given class,
* <p>The algorithm operates as follows: Searches for an annotation on the given * checking the superclass itself; if no annotation found there, proceeds with the interfaces that the superclass
* class and returns it if found. Else searches all interfaces that the given * declares. Recursing up through the entire superclass hierarchy if no match is found.
* class declares, returning the annotation from the first matching candidate,
* if any. Else proceeds with introspection of the superclass of the given class,
* checking the superclass itself; if no annotation found there, proceeds with
* the interfaces that the superclass declares. Recursing up through the entire
* superclass hierarchy if no match is found.
* @param clazz the class to look for annotations on * @param clazz the class to look for annotations on
* @param annotationType the annotation class to look for * @param annotationType the annotation class to look for
* @return the annotation found, or <code>null</code> if none found * @return the annotation found, or <code>null</code> if none found
@ -187,24 +175,18 @@ public abstract class AnnotationUtils {
} }
/** /**
* Find the first {@link Class} in the inheritance hierarchy of the * Find the first {@link Class} in the inheritance hierarchy of the specified <code>clazz</code> (including the
* specified <code>clazz</code> (including the specified * specified <code>clazz</code> itself) which declares an annotation for the specified <code>annotationType</code>, or
* <code>clazz</code> itself) which declares an annotation for the * <code>null</code> if not found. If the supplied <code>clazz</code> is <code>null</code>, <code>null</code> will be
* specified <code>annotationType</code>, or <code>null</code> if not * returned. <p>If the supplied <code>clazz</code> is an interface, only the interface itself will be checked; the
* found. If the supplied <code>clazz</code> is <code>null</code>, * inheritance hierarchy for interfaces will not be traversed. <p>The standard {@link Class} API does not provide a
* <code>null</code> will be returned. * mechanism for determining which class in an inheritance hierarchy actually declares an {@link Annotation}, so we
* <p>If the supplied <code>clazz</code> is an interface, only the interface * need to handle this explicitly.
* itself will be checked; the inheritance hierarchy for interfaces will not
* be traversed.
* <p>The standard {@link Class} API does not provide a mechanism for
* determining which class in an inheritance hierarchy actually declares an
* {@link Annotation}, so we need to handle this explicitly.
* @param annotationType the Class object corresponding to the annotation type * @param annotationType the Class object corresponding to the annotation type
* @param clazz the Class object corresponding to the class on which to * @param clazz the Class object corresponding to the class on which to check for the annotation, or
* check for the annotation, or <code>null</code>. * <code>null</code>.
* @return the first {@link Class} in the inheritance hierarchy of the * @return the first {@link Class} in the inheritance hierarchy of the specified <code>clazz</code> which
* specified <code>clazz</code> which declares an annotation for the specified * declares an annotation for the specified <code>annotationType</code>, or <code>null</code> if not found.
* <code>annotationType</code>, or <code>null</code> if not found.
* @see Class#isAnnotationPresent(Class) * @see Class#isAnnotationPresent(Class)
* @see Class#getDeclaredAnnotations() * @see Class#getDeclaredAnnotations()
*/ */
@ -213,23 +195,21 @@ public abstract class AnnotationUtils {
if (clazz == null || clazz.equals(Object.class)) { if (clazz == null || clazz.equals(Object.class)) {
return null; return null;
} }
return (isAnnotationDeclaredLocally(annotationType, clazz)) ? return (isAnnotationDeclaredLocally(annotationType, clazz)) ? clazz :
clazz : findAnnotationDeclaringClass(annotationType, clazz.getSuperclass()); findAnnotationDeclaringClass(annotationType, clazz.getSuperclass());
} }
/** /**
* Determine whether an annotation for the specified <code>annotationType</code> * Determine whether an annotation for the specified <code>annotationType</code> is
* is declared locally on the supplied <code>clazz</code>. * declared locally on the supplied <code>clazz</code>. The supplied {@link Class}
* The supplied {@link Class} object may represent any type. * may represent any type.
* <p>Note: This method does <strong>not</strong> determine if the annotation * <p>Note: This method does <strong>not</strong> determine if the annotation is
* is {@link java.lang.annotation.Inherited inherited}. For greater clarity * {@link java.lang.annotation.Inherited inherited}. For greater clarity regarding inherited
* regarding inherited annotations, consider using * annotations, consider using {@link #isAnnotationInherited(Class, Class)} instead.
* {@link #isAnnotationInherited(Class, Class)} instead.
* @param annotationType the Class object corresponding to the annotation type * @param annotationType the Class object corresponding to the annotation type
* @param clazz the Class object corresponding to the class on which to * @param clazz the Class object corresponding to the class on which to check for the annotation
* check for the annotation * @return <code>true</code> if an annotation for the specified <code>annotationType</code>
* @return <code>true</code> if an annotation for the specified * is declared locally on the supplied <code>clazz</code>
* <code>annotationType</code> is declared locally on the supplied <code>clazz</code>
* @see Class#getDeclaredAnnotations() * @see Class#getDeclaredAnnotations()
* @see #isAnnotationInherited(Class, Class) * @see #isAnnotationInherited(Class, Class)
*/ */
@ -247,22 +227,17 @@ public abstract class AnnotationUtils {
} }
/** /**
* Determine whether an annotation for the specified <code>annotationType</code> * Determine whether an annotation for the specified <code>annotationType</code> is present
* is present on the supplied <code>clazz</code> and is * on the supplied <code>clazz</code> and is {@link java.lang.annotation.Inherited inherited}
* {@link java.lang.annotation.Inherited inherited} * i.e., not declared locally for the class).
* (i.e., not declared locally for the class). * <p>If the supplied <code>clazz</code> is an interface, only the interface itself will be checked.
* <p>If the supplied <code>clazz</code> is an interface, only the interface * In accordance with standard meta-annotation semantics, the inheritance hierarchy for interfaces
* itself will be checked. In accord with standard meta-annotation * will not be traversed. See the {@link java.lang.annotation.Inherited JavaDoc} for the
* semantics, the inheritance hierarchy for interfaces will not be * &#064;Inherited meta-annotation for further details regarding annotation inheritance.
* traversed. See the {@link java.lang.annotation.Inherited JavaDoc} for the
* &#064;Inherited meta-annotation for further details regarding annotation
* inheritance.
* @param annotationType the Class object corresponding to the annotation type * @param annotationType the Class object corresponding to the annotation type
* @param clazz the Class object corresponding to the class on which to * @param clazz the Class object corresponding to the class on which to check for the annotation
* check for the annotation * @return <code>true</code> if an annotation for the specified <code>annotationType</code> is present
* @return <code>true</code> if an annotation for the specified * on the supplied <code>clazz</code> and is {@link java.lang.annotation.Inherited inherited}
* <code>annotationType</code> is present on the supplied <code>clazz</code>
* and is {@link java.lang.annotation.Inherited inherited}
* @see Class#isAnnotationPresent(Class) * @see Class#isAnnotationPresent(Class)
* @see #isAnnotationDeclaredLocally(Class, Class) * @see #isAnnotationDeclaredLocally(Class, Class)
*/ */
@ -273,11 +248,10 @@ public abstract class AnnotationUtils {
} }
/** /**
* Retrieve the given annotation's attributes as a Map, * Retrieve the given annotation's attributes as a Map, preserving all attribute types as-is.
* preserving all attribute types as-is.
* @param annotation the annotation to retrieve the attributes for * @param annotation the annotation to retrieve the attributes for
* @return the Map of annotation attributes, with attribute names as keys * @return the Map of annotation attributes, with attribute names as keys and
* and corresponding attribute values as values * corresponding attribute values as values
*/ */
public static Map<String, Object> getAnnotationAttributes(Annotation annotation) { public static Map<String, Object> getAnnotationAttributes(Annotation annotation) {
return getAnnotationAttributes(annotation, false); return getAnnotationAttributes(annotation, false);
@ -286,11 +260,10 @@ public abstract class AnnotationUtils {
/** /**
* Retrieve the given annotation's attributes as a Map. * Retrieve the given annotation's attributes as a Map.
* @param annotation the annotation to retrieve the attributes for * @param annotation the annotation to retrieve the attributes for
* @param classValuesAsString whether to turn Class references into Strings * @param classValuesAsString whether to turn Class references into Strings (for compatibility with
* (for compatibility with {@link org.springframework.core.type.AnnotationMetadata} * {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as Class references
* or to preserve them as Class references * @return the Map of annotation attributes, with attribute names as keys and
* @return the Map of annotation attributes, with attribute names as keys * corresponding attribute values as values
* and corresponding attribute values as values
*/ */
public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean classValuesAsString) { public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean classValuesAsString) {
Map<String, Object> attrs = new HashMap<String, Object>(); Map<String, Object> attrs = new HashMap<String, Object>();
@ -323,8 +296,8 @@ public abstract class AnnotationUtils {
} }
/** /**
* Retrieve the <em>value</em> of the <code>&quot;value&quot;</code> * Retrieve the <em>value</em> of the <code>&quot;value&quot;</code> attribute of a
* attribute of a single-element Annotation, given an annotation instance. * single-element Annotation, given an annotation instance.
* @param annotation the annotation instance from which to retrieve the value * @param annotation the annotation instance from which to retrieve the value
* @return the attribute value, or <code>null</code> if not found * @return the attribute value, or <code>null</code> if not found
* @see #getValue(Annotation, String) * @see #getValue(Annotation, String)
@ -334,12 +307,11 @@ public abstract class AnnotationUtils {
} }
/** /**
* Retrieve the <em>value</em> of a named Annotation attribute, given an * Retrieve the <em>value</em> of a named Annotation attribute, given an annotation instance.
* annotation instance.
* @see #getValue(Annotation)
* @param annotation the annotation instance from which to retrieve the value * @param annotation the annotation instance from which to retrieve the value
* @param attributeName the name of the attribute value to retrieve * @param attributeName the name of the attribute value to retrieve
* @return the attribute value, or <code>null</code> if not found * @return the attribute value, or <code>null</code> if not found
* @see #getValue(Annotation)
*/ */
public static Object getValue(Annotation annotation, String attributeName) { public static Object getValue(Annotation annotation, String attributeName) {
try { try {
@ -352,11 +324,9 @@ public abstract class AnnotationUtils {
} }
/** /**
* Retrieve the <em>default value</em> of the * Retrieve the <em>default value</em> of the <code>&quot;value&quot;</code> attribute
* <code>&quot;value&quot;</code> attribute of a single-element * of a single-element Annotation, given an annotation instance.
* Annotation, given an annotation instance. * @param annotation the annotation instance from which to retrieve the default value
* @param annotation the annotation instance from which to retrieve
* the default value
* @return the default value, or <code>null</code> if not found * @return the default value, or <code>null</code> if not found
* @see #getDefaultValue(Annotation, String) * @see #getDefaultValue(Annotation, String)
*/ */
@ -365,13 +335,10 @@ public abstract class AnnotationUtils {
} }
/** /**
* Retrieve the <em>default value</em> of a named Annotation attribute, * Retrieve the <em>default value</em> of a named Annotation attribute, given an annotation instance.
* given an annotation instance. * @param annotation the annotation instance from which to retrieve the default value
* @param annotation the annotation instance from which to retrieve
* the default value
* @param attributeName the name of the attribute value to retrieve * @param attributeName the name of the attribute value to retrieve
* @return the default value of the named attribute, or <code>null</code> * @return the default value of the named attribute, or <code>null</code> if not found.
* if not found.
* @see #getDefaultValue(Class, String) * @see #getDefaultValue(Class, String)
*/ */
public static Object getDefaultValue(Annotation annotation, String attributeName) { public static Object getDefaultValue(Annotation annotation, String attributeName) {
@ -379,11 +346,9 @@ public abstract class AnnotationUtils {
} }
/** /**
* Retrieve the <em>default value</em> of the * Retrieve the <em>default value</em> of the <code>&quot;value&quot;</code> attribute
* <code>&quot;value&quot;</code> attribute of a single-element * of a single-element Annotation, given the {@link Class annotation type}.
* Annotation, given the {@link Class annotation type}. * @param annotationType the <em>annotation type</em> for which the default value should be retrieved
* @param annotationType the <em>annotation type</em> for which the
* default value should be retrieved
* @return the default value, or <code>null</code> if not found * @return the default value, or <code>null</code> if not found
* @see #getDefaultValue(Class, String) * @see #getDefaultValue(Class, String)
*/ */
@ -392,13 +357,10 @@ public abstract class AnnotationUtils {
} }
/** /**
* Retrieve the <em>default value</em> of a named Annotation attribute, * Retrieve the <em>default value</em> of a named Annotation attribute, given the {@link Class annotation type}.
* given the {@link Class annotation type}. * @param annotationType the <em>annotation type</em> for which the default value should be retrieved
* @param annotationType the <em>annotation type</em> for which the
* default value should be retrieved
* @param attributeName the name of the attribute value to retrieve. * @param attributeName the name of the attribute value to retrieve.
* @return the default value of the named attribute, or <code>null</code> * @return the default value of the named attribute, or <code>null</code> if not found
* if not found
* @see #getDefaultValue(Annotation, String) * @see #getDefaultValue(Annotation, String)
*/ */
public static Object getDefaultValue(Class<? extends Annotation> annotationType, String attributeName) { public static Object getDefaultValue(Class<? extends Annotation> annotationType, String attributeName) {

View File

@ -20,17 +20,28 @@ import org.springframework.core.convert.TypeDescriptor;
/** /**
* A generic converter that conditionally executes. * A generic converter that conditionally executes.
* Applies a rule that determines if a converter between a set of {@link #getConvertibleTypes() convertible types} matches given a client request to convert between a source field of convertible type S and a target field of convertible type T. *
* Often used to selectively match custom conversion logic based on the presence of a field or class-level characteristic, such as an annotation or method. * <p>Applies a rule that determines if a converter between a set of
* For example, when converting from a String field to a Date field, an implementation might return true if the target field has also been annotated with <code>@DateTimeFormat</code>. * {@link #getConvertibleTypes() convertible types} matches given a client request to
* As another example, when converting from a String field to an Account field, an implementation might return true if the target Account class defines a public static findAccount(String) method. * convert between a source field of convertible type S and a target field of convertible type T.
*
* <p>Often used to selectively match custom conversion logic based on the presence of
* a field or class-level characteristic, such as an annotation or method. For example,
* when converting from a String field to a Date field, an implementation might return
* <code>true</code> if the target field has also been annotated with <code>@DateTimeFormat</code>.
*
* <p>As another example, when converting from a String field to an Account field,
* an implementation might return true if the target Account class defines a
* <code>public static findAccount(String)</code> method.
*
* @author Keith Donald * @author Keith Donald
* @since 3.0 * @since 3.0
*/ */
public interface ConditionalGenericConverter extends GenericConverter { public interface ConditionalGenericConverter extends GenericConverter {
/** /**
* Should the Converter from <code>sourceType</code> to <code>targetType</code> currently under consideration be selected? * Should the converter from <code>sourceType</code> to <code>targetType</code>
* currently under consideration be selected?
* @param sourceType the type descriptor of the field we are converting from * @param sourceType the type descriptor of the field we are converting from
* @param targetType the type descriptor of the field we are converting to * @param targetType the type descriptor of the field we are converting to
* @return true if conversion should be performed, false otherwise * @return true if conversion should be performed, false otherwise