@ -91,8 +91,9 @@ public abstract class AnnotationUtils {
@@ -91,8 +91,9 @@ public abstract class AnnotationUtils {
* Get a single { @link Annotation } of { @code annotationType } from the supplied
* annotation : either the given annotation itself or a direct meta - annotation
* thereof .
* < p > Note that this method does < em > not < / em > support arbitrary levels of
* meta - annotations .
* < p > Note that this method supports only a single level of meta - annotations .
* For support for arbitrary levels of meta - annotations , use one of the
* { @code find * ( ) } methods instead .
* @param ann the Annotation to check
* @param annotationType the annotation type to look for , both locally and as a meta - annotation
* @return the matching annotation , or { @code null } if not found
@ -115,9 +116,11 @@ public abstract class AnnotationUtils {
@@ -115,9 +116,11 @@ public abstract class AnnotationUtils {
/ * *
* Get a single { @link Annotation } of { @code annotationType } from the supplied
* { @link AnnotatedElement } .
* < p > Meta - annotations will be searched if the annotation is not
* < em > directly present < / em > on the supplied element .
* { @link AnnotatedElement } , where the { @code AnnotatedElement } is either
* directly annotated or meta - annotated with the { @code annotationType } .
* < p > Note that this method supports only a single level of meta - annotations .
* For support for arbitrary levels of meta - annotations , use
* { @link # findAnnotation ( AnnotatedElement , Class ) } instead .
* @param annotatedElement the { @code AnnotatedElement } from which to get the annotation
* @param annotationType the annotation type to look for , both locally and as a meta - annotation
* @return the matching annotation , or { @code null } if not found
@ -144,10 +147,13 @@ public abstract class AnnotationUtils {
@@ -144,10 +147,13 @@ public abstract class AnnotationUtils {
}
/ * *
* Get a single { @link Annotation } of { @code annotationType } from the supplied { @link Method } .
* Get a single { @link Annotation } of { @code annotationType } from the
* supplied { @link Method } , where the method is either directly annotated
* or meta - annotated with the { @code annotationType } .
* < p > Correctly handles bridge { @link Method Methods } generated by the compiler .
* < p > Meta - annotations will be searched if the annotation is not
* < em > directly present < / em > on the supplied method .
* < p > Note that this method supports only a single level of meta - annotations .
* For support for arbitrary levels of meta - annotations , use
* { @link # findAnnotation ( Method , Class ) } instead .
* @param method the method to look for annotations on
* @param annotationType the annotation type to look for
* @return the matching annotation , or { @code null } if not found
@ -256,26 +262,91 @@ public abstract class AnnotationUtils {
@@ -256,26 +262,91 @@ public abstract class AnnotationUtils {
}
/ * *
* Find a single { @link Annotation } of { @code annotationType } from the supplied
* Find a single { @link Annotation } of { @code annotationType } on the
* supplied { @link AnnotatedElement } .
* < p > Meta - annotations will be searched if the annotation is not
* < em > directly present < / em > on the supplied element .
* < p > < strong > Warning < / strong > : this method operates generically on
* annotated elements . In other words , this method does not execute
* specialized search algorithms for classes or methods . If you require
* the more specific semantics of { @link # findAnnotation ( Class , Class ) }
* or { @link # findAnnotation ( Method , Class ) } , invoke one of those methods
* instead .
* @param annotatedElement the { @code AnnotatedElement } on which to find the annotation
* @param annotationType the annotation type to look for , both locally and as a meta - annotation
* @return the matching annotation , or { @code null } if not found
* @since 4 . 2
* /
public static < A extends Annotation > A findAnnotation ( AnnotatedElement annotatedElement , Class < A > annotationType ) {
// Do NOT store result in the findAnnotationCache since doing so could break
// findAnnotation(Class, Class) and findAnnotation(Method, Class).
return findAnnotation ( annotatedElement , annotationType , new HashSet < Annotation > ( ) ) ;
}
/ * *
* Perform the search algorithm for { @link # findAnnotation ( AnnotatedElement , Class ) }
* avoiding endless recursion by tracking which annotations have already
* been < em > visited < / em > .
* @param annotatedElement the { @code AnnotatedElement } on which to find the annotation
* @param annotationType the annotation type to look for , both locally and as a meta - annotation
* @param visited the set of annotations that have already been visited
* @return the matching annotation , or { @code null } if not found
* @since 4 . 2
* /
@SuppressWarnings ( "unchecked" )
private static < T extends Annotation > T findAnnotation ( AnnotatedElement annotatedElement , Class < T > annotationType , Set < Annotation > visited ) {
Assert . notNull ( annotatedElement , "AnnotatedElement must not be null" ) ;
try {
Annotation [ ] anns = annotatedElement . getDeclaredAnnotations ( ) ;
for ( Annotation ann : anns ) {
if ( ann . annotationType ( ) . equals ( annotationType ) ) {
return ( T ) ann ;
}
}
for ( Annotation ann : anns ) {
if ( ! isInJavaLangAnnotationPackage ( ann ) & & visited . add ( ann ) ) {
T annotation = findAnnotation ( ( AnnotatedElement ) ann . annotationType ( ) , annotationType , visited ) ;
if ( annotation ! = null ) {
return annotation ;
}
}
}
}
catch ( Exception ex ) {
// Assuming nested Class values not resolvable within annotation attributes...
logIntrospectionFailure ( annotatedElement , ex ) ;
}
return null ;
}
/ * *
* Find a single { @link Annotation } of { @code annotationType } on the supplied
* { @link Method } , traversing its super methods ( i . e . , from superclasses and
* interfaces ) if no annotation can be found on the given method itself .
* < p > Correctly handles bridge { @link Method Methods } generated by the compiler .
* < p > Meta - annotations will be searched if the annotation is not
* < em > directly present < / em > on the method .
* < p > Annotations on methods are not inherited by default , so we need to handle
* this explicitly .
* < p > Meta - annotations will < em > not < / em > be searched .
* @param method the method to look for annotations on
* @param annotationType the annotation type to look for
* @return the matching annotation , or { @code null } if not found
* @see # getAnnotation ( Method , Class )
* /
@SuppressWarnings ( "unchecked" )
public static < A extends Annotation > A findAnnotation ( Method method , Class < A > annotationType ) {
AnnotationCacheKey cacheKey = new AnnotationCacheKey ( method , annotationType ) ;
A result = ( A ) findAnnotationCache . get ( cacheKey ) ;
if ( result = = null ) {
result = getAnnotation ( method , annotationType ) ;
Class < ? > clazz = method . getDeclaringClass ( ) ;
Method resolvedMethod = BridgeMethodResolver . findBridgedMethod ( method ) ;
result = findAnnotation ( ( AnnotatedElement ) resolvedMethod , annotationType ) ;
if ( result = = null ) {
result = searchOnInterfaces ( method , annotationType , clazz . getInterfaces ( ) ) ;
result = searchOnInterfaces ( method , annotationType , method . getDeclaringClass ( ) . getInterfaces ( ) ) ;
}
Class < ? > clazz = method . getDeclaringClass ( ) ;
while ( result = = null ) {
clazz = clazz . getSuperclass ( ) ;
if ( clazz = = null | | clazz . equals ( Object . class ) ) {
@ -283,7 +354,8 @@ public abstract class AnnotationUtils {
@@ -283,7 +354,8 @@ public abstract class AnnotationUtils {
}
try {
Method equivalentMethod = clazz . getDeclaredMethod ( method . getName ( ) , method . getParameterTypes ( ) ) ;
result = getAnnotation ( equivalentMethod , annotationType ) ;
Method resolvedEquivalentMethod = BridgeMethodResolver . findBridgedMethod ( equivalentMethod ) ;
result = findAnnotation ( ( AnnotatedElement ) resolvedEquivalentMethod , annotationType ) ;
}
catch ( NoSuchMethodException ex ) {
// No equivalent method found
@ -292,9 +364,10 @@ public abstract class AnnotationUtils {
@@ -292,9 +364,10 @@ public abstract class AnnotationUtils {
result = searchOnInterfaces ( method , annotationType , clazz . getInterfaces ( ) ) ;
}
}
if ( result ! = null ) {
findAnnotationCache . put ( cacheKey , result ) ;
}
}
if ( result ! = null ) {
findAnnotationCache . put ( cacheKey , result ) ;
}
return result ;
}
@ -680,7 +753,7 @@ public abstract class AnnotationUtils {
@@ -680,7 +753,7 @@ public abstract class AnnotationUtils {
}
/ * *
* Retrieve the < em > value < / em > of the { @code & quot ; value & quot ; } attribute of a
* Retrieve the < em > value < / em > of the { @code value } 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 } if not found
@ -712,7 +785,7 @@ public abstract class AnnotationUtils {
@@ -712,7 +785,7 @@ public abstract class AnnotationUtils {
}
/ * *
* Retrieve the < em > default value < / em > of the { @code & quot ; value & quot ; } attribute
* Retrieve the < em > default value < / em > of the { @code value } 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 } if not found
@ -737,7 +810,7 @@ public abstract class AnnotationUtils {
@@ -737,7 +810,7 @@ public abstract class AnnotationUtils {
}
/ * *
* Retrieve the < em > default value < / em > of the { @code & quot ; value & quot ; } attribute
* Retrieve the < em > default value < / em > of the { @code value } 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 } if not found