Extend AnnotationMetadata and MethodMetadata
Update AnnotationMetadata and MethodMetadata to extend from a new AnnotatedTypeMetadata base interface containing the methods that are common to both. Also introduce new getAllAnnotationAttributes methods providing MultiValueMap access to both annotation and meta-annotation attributes. Existing classreading and standard implementations have been refactored to support the new interface.
This commit is contained in:
parent
eb1776e79d
commit
8e445f3a21
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.type;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Internal utility class used to collect all annotation values including those declared
|
||||
* on meta-annotations.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
*/
|
||||
class AnnotatedElementUtils {
|
||||
|
||||
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element,
|
||||
String annotationType) {
|
||||
final Set<String> types = new LinkedHashSet<String>();
|
||||
process(element, annotationType, new Processor<Object>() {
|
||||
public Object process(Annotation annotation, int depth) {
|
||||
if (depth > 0) {
|
||||
types.add(annotation.annotationType().getName());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return (types.size() == 0 ? null : types);
|
||||
}
|
||||
|
||||
public static boolean hasMetaAnnotationTypes(AnnotatedElement element,
|
||||
String annotationType) {
|
||||
return Boolean.TRUE.equals(
|
||||
process(element, annotationType, new Processor<Boolean>() {
|
||||
public Boolean process(Annotation annotation, int depth) {
|
||||
if (depth > 0) {
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public static boolean isAnnotated(AnnotatedElement element, String annotationType) {
|
||||
return Boolean.TRUE.equals(
|
||||
process(element, annotationType, new Processor<Boolean>() {
|
||||
public Boolean process(Annotation annotation, int depth) {
|
||||
return true;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public static Map<String, Object> getAnnotationAttributes(AnnotatedElement element,
|
||||
String annotationType, final boolean classValuesAsString,
|
||||
final boolean nestedAnnotationsAsMap) {
|
||||
return process(element, annotationType, new Processor<Map<String, Object>>() {
|
||||
public Map<String, Object> process(Annotation annotation, int depth) {
|
||||
return AnnotationUtils.getAnnotationAttributes(annotation,
|
||||
classValuesAsString, nestedAnnotationsAsMap);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static MultiValueMap<String, Object> getAllAnnotationAttributes(
|
||||
AnnotatedElement element, final String annotationType,
|
||||
final boolean classValuesAsString, final boolean nestedAnnotationsAsMap) {
|
||||
final MultiValueMap<String, Object> attributes = new LinkedMultiValueMap<String, Object>();
|
||||
process(element, annotationType, new Processor<Object>() {
|
||||
public Object process(Annotation annotation, int depth) {
|
||||
if (annotation.annotationType().getName().equals(annotationType)) {
|
||||
for (Map.Entry<String, Object> entry : AnnotationUtils.getAnnotationAttributes(
|
||||
annotation, classValuesAsString, nestedAnnotationsAsMap).entrySet()) {
|
||||
attributes.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
return (attributes.size() == 0 ? null : attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all annotations of the specified annotation type and recursively all
|
||||
* meta-annotations on the specified type.
|
||||
* @param element the annotated element
|
||||
* @param annotationType the annotation type to find. Only items of the specified type
|
||||
* or meta-annotations of the specified type will be processed
|
||||
* @param processor the processor
|
||||
* @return the result of the processor
|
||||
*/
|
||||
private static <T> T process(AnnotatedElement element, String annotationType,
|
||||
Processor<T> processor) {
|
||||
return recursivelyProcess(element, annotationType, processor,
|
||||
new HashSet<AnnotatedElement>(), 0);
|
||||
}
|
||||
|
||||
private static <T> T recursivelyProcess(AnnotatedElement element,
|
||||
String annotationType, Processor<T> processor, Set<AnnotatedElement> visited,
|
||||
int depth) {
|
||||
T result = null;
|
||||
if (visited.add(element)) {
|
||||
for (Annotation annotation : element.getAnnotations()) {
|
||||
if (annotation.annotationType().getName().equals(annotationType) || depth > 0) {
|
||||
result = result != null ? result :
|
||||
processor.process(annotation, depth);
|
||||
result = result != null ? result :
|
||||
recursivelyProcess(annotation.annotationType(), annotationType,
|
||||
processor, visited, depth + 1);
|
||||
}
|
||||
}
|
||||
for (Annotation annotation : element.getAnnotations()) {
|
||||
result = result != null ? result :
|
||||
recursivelyProcess(annotation.annotationType(), annotationType,
|
||||
processor, visited, depth);
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface used to process an annotation.
|
||||
* @param <T> the result type
|
||||
*/
|
||||
private static interface Processor<T> {
|
||||
|
||||
/**
|
||||
* Called to process the annotation.
|
||||
* @param annotation the annotation to process
|
||||
* @param depth the depth of the annotation relative to the initial match. For
|
||||
* example a matched annotation will have a depth of 0, a meta-annotation 1
|
||||
* and a meta-meta-annotation 2
|
||||
* @return the result of the processing or {@code null} to continue
|
||||
*/
|
||||
T process(Annotation annotation, int depth);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.type;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Defines access to the annotations of a specific type ({@link AnnotationMetadata class}
|
||||
* or {@link MethodMetadata method}), in a form that does not necessarily require the
|
||||
* class-loading.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @author Mark Pollack
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
* @see AnnotationMetadata
|
||||
* @see MethodMetadata
|
||||
*/
|
||||
public interface AnnotatedTypeMetadata {
|
||||
|
||||
/**
|
||||
* Determine whether the underlying type has an annotation or
|
||||
* meta-annotation of the given type defined.
|
||||
* <p>If this method returns {@code true}, then
|
||||
* {@link #getAnnotationAttributes} will return a non-null Map.
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return whether a matching annotation is defined
|
||||
*/
|
||||
boolean isAnnotated(String annotationType);
|
||||
|
||||
/**
|
||||
* Retrieve the attributes of the annotation of the given type,
|
||||
* if any (i.e. if defined on the underlying class, as direct
|
||||
* annotation or as meta-annotation).
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return a Map of attributes, with the attribute name as key (e.g. "value")
|
||||
* and the defined attribute value as Map value. This return value will be
|
||||
* {@code null} if no matching annotation is defined.
|
||||
*/
|
||||
Map<String, Object> getAnnotationAttributes(String annotationType);
|
||||
|
||||
/**
|
||||
* Retrieve the attributes of the annotation of the given type,
|
||||
* if any (i.e. if defined on the underlying class, as direct
|
||||
* annotation or as meta-annotation).
|
||||
* @param annotationType the annotation type to look for
|
||||
* @param classValuesAsString whether to convert class references to String
|
||||
* class names for exposure as values in the returned Map, instead of Class
|
||||
* references which might potentially have to be loaded first
|
||||
* @return a Map of attributes, with the attribute name as key (e.g. "value")
|
||||
* and the defined attribute value as Map value. This return value will be
|
||||
* {@code null} if no matching annotation is defined.
|
||||
*/
|
||||
Map<String, Object> getAnnotationAttributes(String annotationType, boolean classValuesAsString);
|
||||
|
||||
/**
|
||||
* Retrieve all attributes of all annotations of the given type, if any (i.e. if
|
||||
* defined on the underlying method, as direct annotation or as meta-annotation).
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return a MultiMap of attributes, with the attribute name as key (e.g. "value") and
|
||||
* a list of the defined attribute values as Map value. This return value will
|
||||
* be {@code null} if no matching annotation is defined.
|
||||
*/
|
||||
MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType);
|
||||
|
||||
/**
|
||||
* Retrieve all attributes of all annotations of the given type, if any (i.e. if
|
||||
* defined on the underlying method, as direct annotation or as meta-annotation).
|
||||
* @param annotationType the annotation type to look for
|
||||
* @param classValuesAsString whether to convert class references to String
|
||||
* @return a MultiMap of attributes, with the attribute name as key (e.g. "value") and
|
||||
* a list of the defined attribute values as Map value. This return value will
|
||||
* be {@code null} if no matching annotation is defined.
|
||||
* @see #getAllAnnotationAttributes(String)
|
||||
*/
|
||||
MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType,
|
||||
boolean classValuesAsString);
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.core.type;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
|
@ -25,11 +24,13 @@ import java.util.Set;
|
|||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @author Phillip Webb
|
||||
* @since 2.5
|
||||
* @see StandardAnnotationMetadata
|
||||
* @see org.springframework.core.type.classreading.MetadataReader#getAnnotationMetadata()
|
||||
* @see AnnotatedTypeMetadata
|
||||
*/
|
||||
public interface AnnotationMetadata extends ClassMetadata {
|
||||
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
|
||||
|
||||
/**
|
||||
* Return the names of all annotation types defined on the underlying class.
|
||||
|
|
@ -61,42 +62,6 @@ public interface AnnotationMetadata extends ClassMetadata {
|
|||
*/
|
||||
boolean hasMetaAnnotation(String metaAnnotationType);
|
||||
|
||||
/**
|
||||
* Determine whether the underlying class has an annotation or
|
||||
* meta-annotation of the given type defined.
|
||||
* <p>This is equivalent to a "hasAnnotation || hasMetaAnnotation"
|
||||
* check. If this method returns {@code true}, then
|
||||
* {@link #getAnnotationAttributes} will return a non-null Map.
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return whether a matching annotation is defined
|
||||
*/
|
||||
boolean isAnnotated(String annotationType);
|
||||
|
||||
/**
|
||||
* Retrieve the attributes of the annotation of the given type,
|
||||
* if any (i.e. if defined on the underlying class, as direct
|
||||
* annotation or as meta-annotation).
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return a Map of attributes, with the attribute name as key (e.g. "value")
|
||||
* and the defined attribute value as Map value. This return value will be
|
||||
* {@code null} if no matching annotation is defined.
|
||||
*/
|
||||
Map<String, Object> getAnnotationAttributes(String annotationType);
|
||||
|
||||
/**
|
||||
* Retrieve the attributes of the annotation of the given type,
|
||||
* if any (i.e. if defined on the underlying class, as direct
|
||||
* annotation or as meta-annotation).
|
||||
* @param annotationType the annotation type to look for
|
||||
* @param classValuesAsString whether to convert class references to String
|
||||
* class names for exposure as values in the returned Map, instead of Class
|
||||
* references which might potentially have to be loaded first
|
||||
* @return a Map of attributes, with the attribute name as key (e.g. "value")
|
||||
* and the defined attribute value as Map value. This return value will be
|
||||
* {@code null} if no matching annotation is defined.
|
||||
*/
|
||||
Map<String, Object> getAnnotationAttributes(String annotationType, boolean classValuesAsString);
|
||||
|
||||
/**
|
||||
* Determine whether the underlying class has any methods that are
|
||||
* annotated (or meta-annotated) with the given annotation type.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.core.type;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface that defines abstract access to the annotations of a specific
|
||||
* class, in a form that does not require that class to be loaded yet.
|
||||
|
|
@ -25,11 +23,13 @@ import java.util.Map;
|
|||
* @author Juergen Hoeller
|
||||
* @author Mark Pollack
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @since 3.0
|
||||
* @see StandardMethodMetadata
|
||||
* @see AnnotationMetadata#getAnnotatedMethods
|
||||
* @see AnnotatedTypeMetadata
|
||||
*/
|
||||
public interface MethodMetadata {
|
||||
public interface MethodMetadata extends AnnotatedTypeMetadata {
|
||||
|
||||
/**
|
||||
* Return the name of the method.
|
||||
|
|
@ -57,23 +57,4 @@ public interface MethodMetadata {
|
|||
*/
|
||||
boolean isOverridable();
|
||||
|
||||
/**
|
||||
* Determine whether the underlying method has an annotation or
|
||||
* meta-annotation of the given type defined.
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return whether a matching annotation is defined
|
||||
*/
|
||||
boolean isAnnotated(String annotationType);
|
||||
|
||||
/**
|
||||
* Retrieve the attributes of the annotation of the given type,
|
||||
* if any (i.e. if defined on the underlying method, as direct
|
||||
* annotation or as meta-annotation).
|
||||
* @param annotationType the annotation type to look for
|
||||
* @return a Map of attributes, with the attribute name as key (e.g. "value")
|
||||
* and the defined attribute value as Map value. This return value will be
|
||||
* {@code null} if no matching annotation is defined.
|
||||
*/
|
||||
Map<String, Object> getAnnotationAttributes(String annotationType);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* {@link AnnotationMetadata} implementation that uses standard reflection
|
||||
|
|
@ -32,6 +32,7 @@ import org.springframework.core.annotation.AnnotationUtils;
|
|||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @since 2.5
|
||||
*/
|
||||
public class StandardAnnotationMetadata extends StandardClassMetadata implements AnnotationMetadata {
|
||||
|
|
@ -74,21 +75,7 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
|||
}
|
||||
|
||||
public Set<String> getMetaAnnotationTypes(String annotationType) {
|
||||
Annotation[] anns = getIntrospectedClass().getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType().getName().equals(annotationType)) {
|
||||
Set<String> types = new LinkedHashSet<String>();
|
||||
Annotation[] metaAnns = ann.annotationType().getAnnotations();
|
||||
for (Annotation metaAnn : metaAnns) {
|
||||
types.add(metaAnn.annotationType().getName());
|
||||
for (Annotation metaMetaAnn : metaAnn.annotationType().getAnnotations()) {
|
||||
types.add(metaMetaAnn.annotationType().getName());
|
||||
}
|
||||
}
|
||||
return types;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return AnnotatedElementUtils.getMetaAnnotationTypes(getIntrospectedClass(), annotationType);
|
||||
}
|
||||
|
||||
public boolean hasAnnotation(String annotationType) {
|
||||
|
|
@ -102,76 +89,39 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
|||
}
|
||||
|
||||
public boolean hasMetaAnnotation(String annotationType) {
|
||||
Annotation[] anns = getIntrospectedClass().getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
Annotation[] metaAnns = ann.annotationType().getAnnotations();
|
||||
for (Annotation metaAnn : metaAnns) {
|
||||
if (metaAnn.annotationType().getName().equals(annotationType)) {
|
||||
return true;
|
||||
}
|
||||
for (Annotation metaMetaAnn : metaAnn.annotationType().getAnnotations()) {
|
||||
if (metaMetaAnn.annotationType().getName().equals(annotationType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return AnnotatedElementUtils.hasMetaAnnotationTypes(getIntrospectedClass(), annotationType);
|
||||
}
|
||||
|
||||
public boolean isAnnotated(String annotationType) {
|
||||
Annotation[] anns = getIntrospectedClass().getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType().getName().equals(annotationType)) {
|
||||
return true;
|
||||
}
|
||||
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
|
||||
if (metaAnn.annotationType().getName().equals(annotationType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return AnnotatedElementUtils.isAnnotated(getIntrospectedClass(), annotationType);
|
||||
}
|
||||
|
||||
public Map<String, Object> getAnnotationAttributes(String annotationType) {
|
||||
return this.getAnnotationAttributes(annotationType, false);
|
||||
}
|
||||
|
||||
public Map<String, Object> getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
|
||||
Annotation[] anns = getIntrospectedClass().getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType().getName().equals(annotationType)) {
|
||||
return AnnotationUtils.getAnnotationAttributes(
|
||||
ann, classValuesAsString, this.nestedAnnotationsAsMap);
|
||||
public Map<String, Object> getAnnotationAttributes(String annotationType,
|
||||
boolean classValuesAsString) {
|
||||
return AnnotatedElementUtils.getAnnotationAttributes(getIntrospectedClass(),
|
||||
annotationType, classValuesAsString, this.nestedAnnotationsAsMap);
|
||||
}
|
||||
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType) {
|
||||
return getAllAnnotationAttributes(annotationType, false);
|
||||
}
|
||||
for (Annotation ann : anns) {
|
||||
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
|
||||
if (metaAnn.annotationType().getName().equals(annotationType)) {
|
||||
return AnnotationUtils.getAnnotationAttributes(
|
||||
metaAnn, classValuesAsString, this.nestedAnnotationsAsMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(
|
||||
String annotationType, boolean classValuesAsString) {
|
||||
return AnnotatedElementUtils.getAllAnnotationAttributes(getIntrospectedClass(),
|
||||
annotationType, classValuesAsString, this.nestedAnnotationsAsMap);
|
||||
}
|
||||
|
||||
public boolean hasAnnotatedMethods(String annotationType) {
|
||||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
for (Annotation ann : method.getAnnotations()) {
|
||||
if (ann.annotationType().getName().equals(annotationType)) {
|
||||
if (AnnotatedElementUtils.isAnnotated(method, annotationType)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
|
||||
if (metaAnn.annotationType().getName().equals(annotationType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -180,19 +130,9 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
|||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
|
||||
for (Method method : methods) {
|
||||
for (Annotation ann : method.getAnnotations()) {
|
||||
if (ann.annotationType().getName().equals(annotationType)) {
|
||||
annotatedMethods.add(new StandardMethodMetadata(method, this.nestedAnnotationsAsMap));
|
||||
break;
|
||||
}
|
||||
else {
|
||||
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
|
||||
if (metaAnn.annotationType().getName().equals(annotationType)) {
|
||||
annotatedMethods.add(new StandardMethodMetadata(method, this.nestedAnnotationsAsMap));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AnnotatedElementUtils.isAnnotated(method, annotationType)) {
|
||||
annotatedMethods.add(new StandardMethodMetadata(method,
|
||||
this.nestedAnnotationsAsMap));
|
||||
}
|
||||
}
|
||||
return annotatedMethods;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -16,13 +16,12 @@
|
|||
|
||||
package org.springframework.core.type;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* {@link MethodMetadata} implementation that uses standard reflection
|
||||
|
|
@ -31,6 +30,7 @@ import org.springframework.util.Assert;
|
|||
* @author Juergen Hoeller
|
||||
* @author Mark Pollack
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @since 3.0
|
||||
*/
|
||||
public class StandardMethodMetadata implements MethodMetadata {
|
||||
|
|
@ -89,35 +89,26 @@ public class StandardMethodMetadata implements MethodMetadata {
|
|||
}
|
||||
|
||||
public boolean isAnnotated(String annotationType) {
|
||||
Annotation[] anns = this.introspectedMethod.getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType().getName().equals(annotationType)) {
|
||||
return true;
|
||||
}
|
||||
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
|
||||
if (metaAnn.annotationType().getName().equals(annotationType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return AnnotatedElementUtils.isAnnotated(this.introspectedMethod, annotationType);
|
||||
}
|
||||
|
||||
public Map<String, Object> getAnnotationAttributes(String annotationType) {
|
||||
Annotation[] anns = this.introspectedMethod.getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.annotationType().getName().equals(annotationType)) {
|
||||
return AnnotationUtils.getAnnotationAttributes(
|
||||
ann, true, nestedAnnotationsAsMap);
|
||||
return getAnnotationAttributes(annotationType, false);
|
||||
}
|
||||
for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
|
||||
if (metaAnn.annotationType().getName().equals(annotationType)) {
|
||||
return AnnotationUtils.getAnnotationAttributes(
|
||||
metaAnn, true, this.nestedAnnotationsAsMap);
|
||||
|
||||
public Map<String, Object> getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
|
||||
return AnnotatedElementUtils.getAnnotationAttributes(this.introspectedMethod,
|
||||
annotationType, classValuesAsString, this.nestedAnnotationsAsMap);
|
||||
}
|
||||
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType) {
|
||||
return getAllAnnotationAttributes(annotationType, false);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(
|
||||
String annotationType, boolean classValuesAsString) {
|
||||
return AnnotatedElementUtils.getAllAnnotationAttributes(this.introspectedMethod,
|
||||
annotationType, classValuesAsString, this.nestedAnnotationsAsMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,13 +34,14 @@ import org.springframework.asm.SpringAsmInfo;
|
|||
import org.springframework.asm.Type;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
|
||||
/**
|
||||
* @author Chris Beams
|
||||
* @author Juergen Hoeller
|
||||
* @author Phillip Webb
|
||||
* @since 3.1.1
|
||||
*/
|
||||
abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor {
|
||||
|
|
@ -51,12 +52,14 @@ abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor {
|
|||
|
||||
protected final ClassLoader classLoader;
|
||||
|
||||
|
||||
public AbstractRecursiveAnnotationVisitor(ClassLoader classLoader, AnnotationAttributes attributes) {
|
||||
super(SpringAsmInfo.ASM_VERSION);
|
||||
this.classLoader = classLoader;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
|
||||
public void visit(String attributeName, Object attributeValue) {
|
||||
this.attributes.put(attributeName, attributeValue);
|
||||
}
|
||||
|
|
@ -108,12 +111,14 @@ final class RecursiveAnnotationArrayVisitor extends AbstractRecursiveAnnotationV
|
|||
|
||||
private final List<AnnotationAttributes> allNestedAttributes = new ArrayList<AnnotationAttributes>();
|
||||
|
||||
|
||||
public RecursiveAnnotationArrayVisitor(
|
||||
String attributeName, AnnotationAttributes attributes, ClassLoader classLoader) {
|
||||
super(classLoader, attributes);
|
||||
this.attributeName = attributeName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visit(String attributeName, Object attributeValue) {
|
||||
Object newValue = attributeValue;
|
||||
|
|
@ -155,12 +160,14 @@ class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVi
|
|||
|
||||
private final String annotationType;
|
||||
|
||||
|
||||
public RecursiveAnnotationAttributesVisitor(
|
||||
String annotationType, AnnotationAttributes attributes, ClassLoader classLoader) {
|
||||
super(classLoader, attributes);
|
||||
this.annotationType = annotationType;
|
||||
}
|
||||
|
||||
|
||||
public final void visitEnd() {
|
||||
try {
|
||||
Class<?> annotationClass = this.classLoader.loadClass(this.annotationType);
|
||||
|
|
@ -214,18 +221,20 @@ class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVi
|
|||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @since 3.0
|
||||
*/
|
||||
final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttributesVisitor {
|
||||
|
||||
private final String annotationType;
|
||||
|
||||
private final Map<String, AnnotationAttributes> attributesMap;
|
||||
private final MultiValueMap<String, AnnotationAttributes> attributesMap;
|
||||
|
||||
private final Map<String, Set<String>> metaAnnotationMap;
|
||||
|
||||
|
||||
public AnnotationAttributesReadingVisitor(
|
||||
String annotationType, Map<String, AnnotationAttributes> attributesMap,
|
||||
String annotationType, MultiValueMap<String, AnnotationAttributes> attributesMap,
|
||||
Map<String, Set<String>> metaAnnotationMap, ClassLoader classLoader) {
|
||||
|
||||
super(annotationType, new AnnotationAttributes(), classLoader);
|
||||
|
|
@ -234,29 +243,33 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib
|
|||
this.metaAnnotationMap = metaAnnotationMap;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void doVisitEnd(Class<?> annotationClass) {
|
||||
super.doVisitEnd(annotationClass);
|
||||
this.attributesMap.put(this.annotationType, this.attributes);
|
||||
registerMetaAnnotations(annotationClass);
|
||||
List<AnnotationAttributes> attributes = this.attributesMap.get(this.annotationType);
|
||||
if (attributes == null) {
|
||||
this.attributesMap.add(this.annotationType, this.attributes);
|
||||
}
|
||||
else {
|
||||
attributes.add(0, this.attributes);
|
||||
}
|
||||
|
||||
private void registerMetaAnnotations(Class<?> annotationClass) {
|
||||
// Register annotations that the annotation type is annotated with.
|
||||
Set<String> metaAnnotationTypeNames = new LinkedHashSet<String>();
|
||||
for (Annotation metaAnnotation : annotationClass.getAnnotations()) {
|
||||
metaAnnotationTypeNames.add(metaAnnotation.annotationType().getName());
|
||||
if (!this.attributesMap.containsKey(metaAnnotation.annotationType().getName())) {
|
||||
this.attributesMap.put(metaAnnotation.annotationType().getName(),
|
||||
AnnotationUtils.getAnnotationAttributes(metaAnnotation, true, true));
|
||||
}
|
||||
for (Annotation metaMetaAnnotation : metaAnnotation.annotationType().getAnnotations()) {
|
||||
metaAnnotationTypeNames.add(metaMetaAnnotation.annotationType().getName());
|
||||
}
|
||||
recusivelyCollectMetaAnnotations(metaAnnotationTypeNames, metaAnnotation);
|
||||
}
|
||||
if (this.metaAnnotationMap != null) {
|
||||
this.metaAnnotationMap.put(annotationClass.getName(), metaAnnotationTypeNames);
|
||||
}
|
||||
}
|
||||
|
||||
private void recusivelyCollectMetaAnnotations(Set<String> visited, Annotation annotation) {
|
||||
if (visited.add(annotation.annotationType().getName())) {
|
||||
this.attributesMap.add(annotation.annotationType().getName(),
|
||||
AnnotationUtils.getAnnotationAttributes(annotation, true, true));
|
||||
for (Annotation metaMetaAnnotation : annotation.annotationType().getAnnotations()) {
|
||||
recusivelyCollectMetaAnnotations(visited, metaMetaAnnotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import org.springframework.util.MultiValueMap;
|
|||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @author Costin Leau
|
||||
* @author Phillip Webb
|
||||
* @since 2.5
|
||||
*/
|
||||
public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
|
||||
|
|
@ -51,7 +52,7 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
|||
|
||||
protected final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<String, Set<String>>(4);
|
||||
|
||||
protected final Map<String, AnnotationAttributes> attributeMap = new LinkedHashMap<String, AnnotationAttributes>(4);
|
||||
protected final MultiValueMap<String, AnnotationAttributes> attributeMap = new LinkedMultiValueMap<String, AnnotationAttributes>(4);
|
||||
|
||||
protected final MultiValueMap<String, MethodMetadata> methodMetadataMap = new LinkedMultiValueMap<String, MethodMetadata>();
|
||||
|
||||
|
|
@ -105,60 +106,30 @@ public class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisito
|
|||
}
|
||||
|
||||
public AnnotationAttributes getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
|
||||
AnnotationAttributes raw = this.attributeMap.get(annotationType);
|
||||
return convertClassValues(raw, classValuesAsString);
|
||||
List<AnnotationAttributes> attributes = this.attributeMap.get(annotationType);
|
||||
AnnotationAttributes raw = (attributes == null ? null : attributes.get(0));
|
||||
return AnnotationReadingVisitorUtils.convertClassValues(this.classLoader, raw,
|
||||
classValuesAsString);
|
||||
}
|
||||
|
||||
private AnnotationAttributes convertClassValues(AnnotationAttributes original, boolean classValuesAsString) {
|
||||
if (original == null) {
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType) {
|
||||
return getAllAnnotationAttributes(annotationType, false);
|
||||
}
|
||||
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(
|
||||
String annotationType, boolean classValuesAsString) {
|
||||
MultiValueMap<String, Object> allAttributes = new LinkedMultiValueMap<String, Object>();
|
||||
List<AnnotationAttributes> attributes = this.attributeMap.get(annotationType);
|
||||
if (attributes == null) {
|
||||
return null;
|
||||
}
|
||||
AnnotationAttributes result = new AnnotationAttributes(original.size());
|
||||
for (Map.Entry<String, Object> entry : original.entrySet()) {
|
||||
try {
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof AnnotationAttributes) {
|
||||
value = convertClassValues((AnnotationAttributes) value, classValuesAsString);
|
||||
}
|
||||
else if (value instanceof AnnotationAttributes[]) {
|
||||
AnnotationAttributes[] values = (AnnotationAttributes[])value;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = convertClassValues(values[i], classValuesAsString);
|
||||
for (AnnotationAttributes raw : attributes) {
|
||||
for (Map.Entry<String, Object> entry : AnnotationReadingVisitorUtils.convertClassValues(
|
||||
this.classLoader, raw, classValuesAsString).entrySet()) {
|
||||
allAttributes.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
else if (value instanceof Type) {
|
||||
value = (classValuesAsString ? ((Type) value).getClassName() :
|
||||
this.classLoader.loadClass(((Type) value).getClassName()));
|
||||
}
|
||||
else if (value instanceof Type[]) {
|
||||
Type[] array = (Type[]) value;
|
||||
Object[] convArray = (classValuesAsString ? new String[array.length] : new Class[array.length]);
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
convArray[i] = (classValuesAsString ? array[i].getClassName() :
|
||||
this.classLoader.loadClass(array[i].getClassName()));
|
||||
}
|
||||
value = convArray;
|
||||
}
|
||||
else if (classValuesAsString) {
|
||||
if (value instanceof Class) {
|
||||
value = ((Class<?>) value).getName();
|
||||
}
|
||||
else if (value instanceof Class[]) {
|
||||
Class<?>[] clazzArray = (Class[]) value;
|
||||
String[] newValue = new String[clazzArray.length];
|
||||
for (int i = 0; i < clazzArray.length; i++) {
|
||||
newValue[i] = clazzArray[i].getName();
|
||||
}
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
result.put(entry.getKey(), value);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Class not found - can't resolve class reference in annotation attribute.
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return allAttributes;
|
||||
}
|
||||
|
||||
public boolean hasAnnotatedMethods(String annotationType) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.type.classreading;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
|
||||
/**
|
||||
* Internal utility class used when reading annotations.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Mark Fisher
|
||||
* @author Costin Leau
|
||||
* @author Phillip Webb
|
||||
* @since 4.0
|
||||
*/
|
||||
abstract class AnnotationReadingVisitorUtils {
|
||||
|
||||
public static AnnotationAttributes convertClassValues(ClassLoader classLoader,
|
||||
AnnotationAttributes original, boolean classValuesAsString) {
|
||||
|
||||
if (original == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AnnotationAttributes result = new AnnotationAttributes(original.size());
|
||||
for (Map.Entry<String, Object> entry : original.entrySet()) {
|
||||
try {
|
||||
Object value = entry.getValue();
|
||||
if (value instanceof AnnotationAttributes) {
|
||||
value = convertClassValues(classLoader, (AnnotationAttributes) value,
|
||||
classValuesAsString);
|
||||
}
|
||||
else if (value instanceof AnnotationAttributes[]) {
|
||||
AnnotationAttributes[] values = (AnnotationAttributes[])value;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = convertClassValues(classLoader, values[i],
|
||||
classValuesAsString);
|
||||
}
|
||||
}
|
||||
else if (value instanceof Type) {
|
||||
value = (classValuesAsString ? ((Type) value).getClassName() :
|
||||
classLoader.loadClass(((Type) value).getClassName()));
|
||||
}
|
||||
else if (value instanceof Type[]) {
|
||||
Type[] array = (Type[]) value;
|
||||
Object[] convArray = (classValuesAsString ? new String[array.length] : new Class[array.length]);
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
convArray[i] = (classValuesAsString ? array[i].getClassName() :
|
||||
classLoader.loadClass(array[i].getClassName()));
|
||||
}
|
||||
value = convArray;
|
||||
}
|
||||
else if (classValuesAsString) {
|
||||
if (value instanceof Class) {
|
||||
value = ((Class<?>) value).getName();
|
||||
}
|
||||
else if (value instanceof Class[]) {
|
||||
Class<?>[] clazzArray = (Class[]) value;
|
||||
String[] newValue = new String[clazzArray.length];
|
||||
for (int i = 0; i < clazzArray.length; i++) {
|
||||
newValue[i] = clazzArray[i].getName();
|
||||
}
|
||||
value = newValue;
|
||||
}
|
||||
}
|
||||
result.put(entry.getKey(), value);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Class not found - can't resolve class reference in annotation attribute.
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.springframework.core.type.classreading;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.asm.AnnotationVisitor;
|
||||
|
|
@ -26,6 +26,7 @@ import org.springframework.asm.SpringAsmInfo;
|
|||
import org.springframework.asm.Type;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
|
|
@ -37,6 +38,7 @@ import org.springframework.util.MultiValueMap;
|
|||
* @author Mark Pollack
|
||||
* @author Costin Leau
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
* @since 3.0
|
||||
*/
|
||||
public class MethodMetadataReadingVisitor extends MethodVisitor implements MethodMetadata {
|
||||
|
|
@ -51,7 +53,7 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho
|
|||
|
||||
protected final MultiValueMap<String, MethodMetadata> methodMetadataMap;
|
||||
|
||||
protected final Map<String, AnnotationAttributes> attributeMap = new LinkedHashMap<String, AnnotationAttributes>(2);
|
||||
protected final MultiValueMap<String, AnnotationAttributes> attributeMap = new LinkedMultiValueMap<String, AnnotationAttributes>(2);
|
||||
|
||||
|
||||
public MethodMetadataReadingVisitor(String name, int access, String declaringClassName, ClassLoader classLoader,
|
||||
|
|
@ -93,8 +95,34 @@ public class MethodMetadataReadingVisitor extends MethodVisitor implements Metho
|
|||
return this.attributeMap.containsKey(annotationType);
|
||||
}
|
||||
|
||||
public AnnotationAttributes getAnnotationAttributes(String annotationType) {
|
||||
return this.attributeMap.get(annotationType);
|
||||
public Map<String, Object> getAnnotationAttributes(String annotationType) {
|
||||
return getAnnotationAttributes(annotationType, false);
|
||||
}
|
||||
|
||||
public Map<String, Object> getAnnotationAttributes(String annotationType,
|
||||
boolean classValuesAsString) {
|
||||
List<AnnotationAttributes> attributes = this.attributeMap.get(annotationType);
|
||||
return (attributes == null ? null : AnnotationReadingVisitorUtils.convertClassValues(
|
||||
this.classLoader, attributes.get(0), classValuesAsString));
|
||||
}
|
||||
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType) {
|
||||
return getAllAnnotationAttributes(annotationType, false);
|
||||
}
|
||||
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(
|
||||
String annotationType, boolean classValuesAsString) {
|
||||
if(!this.attributeMap.containsKey(annotationType)) {
|
||||
return null;
|
||||
}
|
||||
MultiValueMap<String, Object> allAttributes = new LinkedMultiValueMap<String, Object>();
|
||||
for (AnnotationAttributes annotationAttributes : this.attributeMap.get(annotationType)) {
|
||||
for (Map.Entry<String, Object> entry : AnnotationReadingVisitorUtils.convertClassValues(
|
||||
this.classLoader, annotationAttributes, classValuesAsString).entrySet()) {
|
||||
allAttributes.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return allAttributes;
|
||||
}
|
||||
|
||||
public String getDeclaringClassName() {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ package org.springframework.core.type;
|
|||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
|
@ -29,10 +31,12 @@ import java.lang.annotation.ElementType;
|
|||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
|
|
@ -45,6 +49,7 @@ import org.springframework.stereotype.Component;
|
|||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class AnnotationMetadataTests {
|
||||
|
||||
|
|
@ -93,7 +98,7 @@ public class AnnotationMetadataTests {
|
|||
assertThat(metadata.hasAnnotation(Component.class.getName()), is(true));
|
||||
assertThat(metadata.hasAnnotation(Scope.class.getName()), is(true));
|
||||
assertThat(metadata.hasAnnotation(SpecialAttr.class.getName()), is(true));
|
||||
assertThat(metadata.getAnnotationTypes().size(), is(3));
|
||||
assertThat(metadata.getAnnotationTypes().size(), is(5));
|
||||
assertThat(metadata.getAnnotationTypes().contains(Component.class.getName()), is(true));
|
||||
assertThat(metadata.getAnnotationTypes().contains(Scope.class.getName()), is(true));
|
||||
assertThat(metadata.getAnnotationTypes().contains(SpecialAttr.class.getName()), is(true));
|
||||
|
|
@ -104,6 +109,15 @@ public class AnnotationMetadataTests {
|
|||
AnnotationAttributes scopeAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(Scope.class.getName());
|
||||
assertThat(scopeAttrs.size(), is(1));
|
||||
assertThat(scopeAttrs.getString("value"), is("myScope"));
|
||||
|
||||
Set<MethodMetadata> methods = metadata.getAnnotatedMethods(DirectAnnotation.class.getName());
|
||||
MethodMetadata method = methods.iterator().next();
|
||||
assertEquals("direct", method.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"));
|
||||
List<Object> allMeta = method.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value");
|
||||
assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta")))));
|
||||
|
||||
assertTrue(metadata.isAnnotated(IsAnnotatedAnnotation.class.getName()));
|
||||
|
||||
{ // perform tests with classValuesAsString = false (the default)
|
||||
AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(SpecialAttr.class.getName());
|
||||
assertThat(specialAttrs.size(), is(6));
|
||||
|
|
@ -137,6 +151,10 @@ public class AnnotationMetadataTests {
|
|||
assertTrue(optionalArray[0].getEnum("anEnum").equals(SomeEnum.DEFAULT));
|
||||
assertArrayEquals(new Class[]{Void.class}, (Class[])optionalArray[0].get("classArray"));
|
||||
assertArrayEquals(new Class[]{Void.class}, optionalArray[0].getClassArray("classArray"));
|
||||
|
||||
assertEquals("direct", metadata.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"));
|
||||
allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value");
|
||||
assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta")))));
|
||||
}
|
||||
{ // perform tests with classValuesAsString = true
|
||||
AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(SpecialAttr.class.getName(), true);
|
||||
|
|
@ -161,6 +179,10 @@ public class AnnotationMetadataTests {
|
|||
AnnotationAttributes[] optionalArray = specialAttrs.getAnnotationArray("optionalArray");
|
||||
assertArrayEquals(new String[]{Void.class.getName()}, (String[])optionalArray[0].get("classArray"));
|
||||
assertArrayEquals(new String[]{Void.class.getName()}, optionalArray[0].getStringArray("classArray"));
|
||||
|
||||
assertEquals(metadata.getAnnotationAttributes(DirectAnnotation.class.getName()).get("value"), "direct");
|
||||
allMeta = metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()).get("value");
|
||||
assertThat(new HashSet<Object>(allMeta), is(equalTo(new HashSet<Object>(Arrays.asList("direct", "meta")))));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -201,6 +223,29 @@ public class AnnotationMetadataTests {
|
|||
NestedAnno[] optionalArray() default {@NestedAnno(value="optional", anEnum=SomeEnum.DEFAULT, classArray=Void.class)};
|
||||
}
|
||||
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DirectAnnotation {
|
||||
String value();
|
||||
}
|
||||
|
||||
@Target({ ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface IsAnnotatedAnnotation {
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@DirectAnnotation("meta")
|
||||
@IsAnnotatedAnnotation
|
||||
public @interface MetaAnnotation {
|
||||
}
|
||||
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@MetaAnnotation
|
||||
public @interface MetaMetaAnnotation {
|
||||
}
|
||||
|
||||
@Component("myName")
|
||||
@Scope("myScope")
|
||||
|
|
@ -211,6 +256,8 @@ public class AnnotationMetadataTests {
|
|||
@NestedAnno(value = "na1", anEnum = SomeEnum.LABEL2, classArray = {Number.class})
|
||||
})
|
||||
@SuppressWarnings({"serial", "unused"})
|
||||
@DirectAnnotation("direct")
|
||||
@MetaMetaAnnotation
|
||||
private static class AnnotatedComponent implements Serializable {
|
||||
|
||||
@TestAutowired
|
||||
|
|
@ -219,6 +266,11 @@ public class AnnotationMetadataTests {
|
|||
|
||||
public void doSleep() {
|
||||
}
|
||||
|
||||
@DirectAnnotation("direct")
|
||||
@MetaMetaAnnotation
|
||||
public void meta() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue