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