Added helper methods to access method parameter annotations.
This commit is contained in:
parent
4a0c2f8879
commit
a383633630
|
|
@ -18,8 +18,10 @@ package org.springframework.core.annotation;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.core.BridgeMethodResolver;
|
import org.springframework.core.BridgeMethodResolver;
|
||||||
|
|
@ -41,6 +43,7 @@ import org.springframework.util.Assert;
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @author Mark Fisher
|
* @author Mark Fisher
|
||||||
|
* @author Oliver Gierke
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @see java.lang.reflect.Method#getAnnotations()
|
* @see java.lang.reflect.Method#getAnnotations()
|
||||||
* @see java.lang.reflect.Method#getAnnotation(Class)
|
* @see java.lang.reflect.Method#getAnnotation(Class)
|
||||||
|
|
@ -373,4 +376,201 @@ public abstract class AnnotationUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link ParameterAnnotation} instance for the first parameter with the given annotation.
|
||||||
|
* @param <T>
|
||||||
|
* @param method the {@link Method} whose parameters shall be inspected
|
||||||
|
* @param annotationType the annotation typed the parameter shall carry
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T extends Annotation> ParameterAnnotation<T> getParameterAnnotation(Method method,
|
||||||
|
Class<T> annotationType) {
|
||||||
|
|
||||||
|
List<ParameterAnnotation<T>> annotations = getParameterAnnotations(method, annotationType);
|
||||||
|
return annotations.isEmpty() ? null : annotations.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all {@link ParameterAnnotation}s for parameters with the given annotation.
|
||||||
|
* @param <T>
|
||||||
|
* @param method the {@link Method} whose parameters shall be scanned for annotations
|
||||||
|
* @param annotationType the annotation type the paramter shall carry
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T extends Annotation> List<ParameterAnnotation<T>> getParameterAnnotations(Method method,
|
||||||
|
Class<T> annotationType) {
|
||||||
|
|
||||||
|
return getParameterAnnotations(method, new AnnotationTypeFilter<T>(annotationType));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link ParameterAnnotation} for a parameter of the given type that carries an annotation of the given
|
||||||
|
* type.
|
||||||
|
* @param <T>
|
||||||
|
* @param method the {@link Method} that shall be scanned for parameters carrying the annotation
|
||||||
|
* @param annotationType the annotation type that shall be discovered
|
||||||
|
* @param parameterType the parameter type that shall be considered
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T extends Annotation> ParameterAnnotation<T> getParameterAnnotation(Method method,
|
||||||
|
Class<T> annotationType, final Class<?> parameterType) {
|
||||||
|
|
||||||
|
List<ParameterAnnotation<T>> annotations = getParameterAnnotations(method, annotationType, parameterType);
|
||||||
|
return annotations.isEmpty() ? null : annotations.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all {@link ParameterAnnotation}s for parameters of the given type that carry an annotation of the given
|
||||||
|
* type.
|
||||||
|
* @param <T>
|
||||||
|
* @param method the {@link Method} that shall be scanned for parameters carrying the annotation
|
||||||
|
* @param annotationType the annotation type that shall be discovered
|
||||||
|
* @param parameterType the parameter type that shall be considered
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T extends Annotation> List<ParameterAnnotation<T>> getParameterAnnotations(Method method,
|
||||||
|
Class<T> annotationType, final Class<?> parameterType) {
|
||||||
|
|
||||||
|
return getParameterAnnotations(method, new AnnotationTypeFilter<T>(annotationType) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(ParameterAnnotation<?> parameterAnnotation) {
|
||||||
|
return super.matches(parameterAnnotation)
|
||||||
|
&& parameterType.equals(parameterAnnotation.getParameterType());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all {@link ParameterAnnotation}s for parameters of the given method that match the given
|
||||||
|
* {@link ParameterAnnotationFilter}.
|
||||||
|
* @see ParameterAnnotationFilter
|
||||||
|
* @param <T>
|
||||||
|
* @param method the {@link Method} that shall be scanned for annotated parameters
|
||||||
|
* @param filter a {@link ParameterAnnotationFilter} to apply criterias on the {@link ParameterAnnotation}s to be
|
||||||
|
* returned
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends Annotation> List<ParameterAnnotation<T>> getParameterAnnotations(Method method,
|
||||||
|
ParameterAnnotationFilter filter) {
|
||||||
|
|
||||||
|
List<ParameterAnnotation<T>> result = new ArrayList<ParameterAnnotation<T>>();
|
||||||
|
|
||||||
|
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
|
||||||
|
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||||
|
|
||||||
|
for (int i = 0; i < parameterAnnotations.length; i++) {
|
||||||
|
for (Annotation annotation : parameterAnnotations[i]) {
|
||||||
|
|
||||||
|
ParameterAnnotation<T> parameterAnnotation = new ParameterAnnotation<T>((T) annotation, i,
|
||||||
|
parameterTypes[i]);
|
||||||
|
|
||||||
|
if (filter.matches(parameterAnnotation)) {
|
||||||
|
result.add(parameterAnnotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows filtering {@link ParameterAnnotation} instances.
|
||||||
|
* @see AnnotationUtils#getParameterAnnotations(Method, ParameterAnnotationFilter)
|
||||||
|
*/
|
||||||
|
public interface ParameterAnnotationFilter {
|
||||||
|
boolean matches(ParameterAnnotation<?> annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ParameterAnnotationFilter} that matches all {@link ParameterAnnotation}s that have the given annotation
|
||||||
|
* type.
|
||||||
|
*/
|
||||||
|
public static class AnnotationTypeFilter<T extends Annotation> implements ParameterAnnotationFilter {
|
||||||
|
|
||||||
|
private final Class<T> annotationType;
|
||||||
|
|
||||||
|
public AnnotationTypeFilter(Class<T> annotationType) {
|
||||||
|
this.annotationType = annotationType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matches(ParameterAnnotation<?> parameterAnnotation) {
|
||||||
|
return annotationType.equals(parameterAnnotation.getAnnotation().annotationType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Captures an annotation for a method parameter as well as some meta information about the parameter.
|
||||||
|
*/
|
||||||
|
public static class ParameterAnnotation<T extends Annotation> {
|
||||||
|
|
||||||
|
private final T annotation;
|
||||||
|
private final int parameterIndex;
|
||||||
|
private final Class<?> parameterType;
|
||||||
|
|
||||||
|
ParameterAnnotation(T annotation, int parameterIndex, Class<?> parameterType) {
|
||||||
|
Assert.notNull(annotation);
|
||||||
|
Assert.notNull(parameterType);
|
||||||
|
this.annotation = annotation;
|
||||||
|
this.parameterIndex = parameterIndex;
|
||||||
|
this.parameterType = parameterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the annotation bound to the parameter.
|
||||||
|
* @return the annotation
|
||||||
|
*/
|
||||||
|
public T getAnnotation() {
|
||||||
|
return annotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the method parameter index in the list of parameters.
|
||||||
|
* @return the parameterIndex
|
||||||
|
*/
|
||||||
|
public int getParameterIndex() {
|
||||||
|
return parameterIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of the method parameter the annotation is bound to.
|
||||||
|
* @return the parameterType
|
||||||
|
*/
|
||||||
|
public Class<?> getParameterType() {
|
||||||
|
return parameterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(obj instanceof ParameterAnnotation<?>)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParameterAnnotation<?> that = (ParameterAnnotation<?>) obj;
|
||||||
|
return this.annotation.equals(that.annotation) && this.parameterType.equals(that.parameterType)
|
||||||
|
&& this.parameterIndex == that.parameterIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + annotation.hashCode();
|
||||||
|
result = 31 * result + parameterType.hashCode();
|
||||||
|
return 31 * result + (parameterIndex ^ parameterIndex >>> 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,45 @@ public class AnnotationUtilsTests {
|
||||||
assertNotNull(order);
|
assertNotNull(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDetectsParameterAnnotation() throws Exception {
|
||||||
|
|
||||||
|
Method method = InterfaceWithAnnotatedMethodParameters.class.getMethod("foo", String.class, Long.class);
|
||||||
|
ParameterAnnotation<MyAnnotation> parameterAnnotation = getParameterAnnotation(method, MyAnnotation.class);
|
||||||
|
assertParameterAnnotationWith(parameterAnnotation, "foo", 1, Long.class);
|
||||||
|
|
||||||
|
List<ParameterAnnotation<MyAnnotation>> parameterAnnotations = getParameterAnnotations(method,
|
||||||
|
MyAnnotation.class);
|
||||||
|
assertNotNull(parameterAnnotations);
|
||||||
|
assertEquals(1, parameterAnnotations.size());
|
||||||
|
assertEquals(parameterAnnotation, parameterAnnotations.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDetectsFirstParameterAnnotationForMultipleOnes() throws Exception {
|
||||||
|
|
||||||
|
Method method = InterfaceWithAnnotatedMethodParameters.class.getMethod("bar", String.class, String.class,
|
||||||
|
Serializable.class);
|
||||||
|
ParameterAnnotation<MyAnnotation> parameterAnnotation = getParameterAnnotation(method, MyAnnotation.class);
|
||||||
|
assertParameterAnnotationWith(parameterAnnotation, "first", 0, String.class);
|
||||||
|
|
||||||
|
List<ParameterAnnotation<MyAnnotation>> parameterAnnotations = getParameterAnnotations(method,
|
||||||
|
MyAnnotation.class);
|
||||||
|
assertNotNull(parameterAnnotations);
|
||||||
|
assertEquals(2, parameterAnnotations.size());
|
||||||
|
assertEquals(parameterAnnotation, parameterAnnotations.get(0));
|
||||||
|
assertParameterAnnotationWith(parameterAnnotations.get(1), "third", 2, Serializable.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertParameterAnnotationWith(ParameterAnnotation<MyAnnotation> parameterAnnotation, String value,
|
||||||
|
int index, Class<?> parameterType) {
|
||||||
|
assertNotNull(parameterAnnotation);
|
||||||
|
assertEquals(index, parameterAnnotation.getParameterIndex());
|
||||||
|
assertNotNull(parameterAnnotation.getAnnotation());
|
||||||
|
assertEquals(value, parameterAnnotation.getAnnotation().value());
|
||||||
|
assertEquals(parameterType, parameterAnnotation.getParameterType());
|
||||||
|
}
|
||||||
|
|
||||||
public static interface AnnotatedInterface {
|
public static interface AnnotatedInterface {
|
||||||
|
|
||||||
@Order(0)
|
@Order(0)
|
||||||
|
|
@ -321,10 +360,23 @@ public class AnnotationUtilsTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static interface InterfaceWithAnnotatedMethodParameters {
|
||||||
|
|
||||||
|
void foo(String foo, @MyAnnotation("foo") Long bar);
|
||||||
|
|
||||||
|
void bar(@MyAnnotation("first") String first, String second, @MyAnnotation("third") Serializable third);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Inherited
|
@Inherited
|
||||||
@interface Transactional {
|
@interface Transactional {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.PARAMETER)
|
||||||
|
@interface MyAnnotation {
|
||||||
|
|
||||||
|
String value() default "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue