Allow meta-annotations to override attributes from their parent
Issue: SPR-10181
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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.annotation;
|
||||
|
||||
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.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Utility class used to collect all annotation values including those declared on meta-annotations.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
*/
|
||||
public class AnnotatedElementUtils {
|
||||
|
||||
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, String annotationType) {
|
||||
final Set<String> types = new LinkedHashSet<String>();
|
||||
process(element, annotationType, new Processor<Object>() {
|
||||
@Override
|
||||
public Object process(Annotation annotation, int depth) {
|
||||
if (depth > 0) {
|
||||
types.add(annotation.annotationType().getName());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void postProcess(Annotation annotation, Object result) {
|
||||
}
|
||||
});
|
||||
return (types.isEmpty() ? null : types);
|
||||
}
|
||||
|
||||
public static boolean hasMetaAnnotationTypes(AnnotatedElement element, String annotationType) {
|
||||
return Boolean.TRUE.equals(process(element, annotationType, new Processor<Boolean>() {
|
||||
@Override
|
||||
public Boolean process(Annotation annotation, int depth) {
|
||||
if (depth > 0) {
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void postProcess(Annotation annotation, Boolean result) {
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public static boolean isAnnotated(AnnotatedElement element, String annotationType) {
|
||||
return Boolean.TRUE.equals(process(element, annotationType, new Processor<Boolean>() {
|
||||
@Override
|
||||
public Boolean process(Annotation annotation, int depth) {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public void postProcess(Annotation annotation, Boolean result) {
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, String annotationType) {
|
||||
return getAnnotationAttributes(element, annotationType, false, false);
|
||||
}
|
||||
|
||||
public static AnnotationAttributes getAnnotationAttributes(
|
||||
AnnotatedElement element, String annotationType,
|
||||
final boolean classValuesAsString, final boolean nestedAnnotationsAsMap) {
|
||||
|
||||
return process(element, annotationType, new Processor<AnnotationAttributes>() {
|
||||
@Override
|
||||
public AnnotationAttributes process(Annotation annotation, int depth) {
|
||||
return AnnotationUtils.getAnnotationAttributes(annotation, classValuesAsString, nestedAnnotationsAsMap);
|
||||
}
|
||||
@Override
|
||||
public void postProcess(Annotation annotation, AnnotationAttributes result) {
|
||||
for (String key : result.keySet()) {
|
||||
if (!"value".equals(key)) {
|
||||
Object value = AnnotationUtils.getValue(annotation, key);
|
||||
if (value != null) {
|
||||
result.put(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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<Void>() {
|
||||
@Override
|
||||
public Void 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;
|
||||
}
|
||||
@Override
|
||||
public void postProcess(Annotation annotation, Void result) {
|
||||
for (String key : attributes.keySet()) {
|
||||
if (!"value".equals(key)) {
|
||||
Object value = AnnotationUtils.getValue(annotation, key);
|
||||
if (value != null) {
|
||||
attributes.add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return (attributes.isEmpty() ? 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 doProcess(element, annotationType, processor, new HashSet<AnnotatedElement>(), 0);
|
||||
}
|
||||
|
||||
private static <T> T doProcess(AnnotatedElement element, String annotationType,
|
||||
Processor<T> processor, Set<AnnotatedElement> visited, int depth) {
|
||||
|
||||
if (visited.add(element)) {
|
||||
for (Annotation annotation : element.getAnnotations()) {
|
||||
if (annotation.annotationType().getName().equals(annotationType) || depth > 0) {
|
||||
T result = processor.process(annotation, depth);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
result = doProcess(annotation.annotationType(), annotationType, processor, visited, depth + 1);
|
||||
if (result != null) {
|
||||
processor.postProcess(annotation, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Annotation annotation : element.getAnnotations()) {
|
||||
T result = doProcess(annotation.annotationType(), annotationType, processor, visited, depth);
|
||||
if (result != null) {
|
||||
processor.postProcess(annotation, result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
void postProcess(Annotation annotation, T result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
package org.springframework.core.annotation;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
@@ -27,10 +26,9 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link LinkedHashMap} subclass representing annotation attribute key/value pairs
|
||||
* as read by Spring's reflection- or ASM-based {@link
|
||||
* org.springframework.core.type.AnnotationMetadata AnnotationMetadata} implementations.
|
||||
* Provides 'pseudo-reification' to avoid noisy Map generics in the calling code as well
|
||||
* as convenience methods for looking up annotation attributes in a type-safe fashion.
|
||||
* as read by Spring's reflection- or ASM-based {@link org.springframework.core.type.AnnotationMetadata}
|
||||
* implementations. Provides 'pseudo-reification' to avoid noisy Map generics in the calling code
|
||||
* as well as convenience methods for looking up annotation attributes in a type-safe fashion.
|
||||
*
|
||||
* @author Chris Beams
|
||||
* @since 3.1.1
|
||||
@@ -63,24 +61,6 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
||||
super(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an {@link AnnotationAttributes} instance based on the given map; if the map
|
||||
* is already an {@code AnnotationAttributes} instance, it is casted and returned
|
||||
* immediately without creating any new instance; otherwise create a new instance by
|
||||
* wrapping the map with the {@link #AnnotationAttributes(Map)} constructor.
|
||||
* @param map original source of annotation attribute key/value pairs
|
||||
*/
|
||||
public static AnnotationAttributes fromMap(Map<String, Object> map) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (map instanceof AnnotationAttributes) {
|
||||
return (AnnotationAttributes) map;
|
||||
}
|
||||
|
||||
return new AnnotationAttributes(map);
|
||||
}
|
||||
|
||||
public String getString(String attributeName) {
|
||||
return doGet(attributeName, String.class);
|
||||
@@ -96,7 +76,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <N extends Number> N getNumber(String attributeName) {
|
||||
return (N) doGet(attributeName, Integer.class);
|
||||
return (N) doGet(attributeName, Number.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -124,11 +104,20 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T doGet(String attributeName, Class<T> expectedType) {
|
||||
Assert.hasText(attributeName, "attributeName must not be null or empty");
|
||||
Object value = this.get(attributeName);
|
||||
Assert.notNull(value, format("Attribute '%s' not found", attributeName));
|
||||
Assert.isAssignable(expectedType, value.getClass(),
|
||||
format("Attribute '%s' is of type [%s], but [%s] was expected. Cause: ",
|
||||
Object value = get(attributeName);
|
||||
Assert.notNull(value, String.format("Attribute '%s' not found", attributeName));
|
||||
if (!expectedType.isInstance(value)) {
|
||||
if (expectedType.isArray() && expectedType.getComponentType().isInstance(value)) {
|
||||
Object arrayValue = Array.newInstance(expectedType.getComponentType(), 1);
|
||||
Array.set(arrayValue, 0, value);
|
||||
value = arrayValue;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Attribute '%s' is of type [%s], but [%s] was expected. Cause: ",
|
||||
attributeName, value.getClass().getSimpleName(), expectedType.getSimpleName()));
|
||||
}
|
||||
}
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
@@ -156,4 +145,23 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return an {@link AnnotationAttributes} instance based on the given map; if the map
|
||||
* is already an {@code AnnotationAttributes} instance, it is casted and returned
|
||||
* immediately without creating any new instance; otherwise create a new instance by
|
||||
* wrapping the map with the {@link #AnnotationAttributes(Map)} constructor.
|
||||
* @param map original source of annotation attribute key/value pairs
|
||||
*/
|
||||
public static AnnotationAttributes fromMap(Map<String, Object> map) {
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
if (map instanceof AnnotationAttributes) {
|
||||
return (AnnotationAttributes) map;
|
||||
}
|
||||
return new AnnotationAttributes(map);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* 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>() {
|
||||
@Override
|
||||
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>() {
|
||||
@Override
|
||||
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>() {
|
||||
@Override
|
||||
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>>() {
|
||||
@Override
|
||||
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>() {
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
@@ -52,11 +52,12 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
||||
/**
|
||||
* Create a new {@link StandardAnnotationMetadata} wrapper for the given Class,
|
||||
* providing the option to return any nested annotations or annotation arrays in the
|
||||
* form of {@link AnnotationAttributes} instead of actual {@link Annotation} instances.
|
||||
* form of {@link org.springframework.core.annotation.AnnotationAttributes} instead
|
||||
* of actual {@link Annotation} instances.
|
||||
* @param introspectedClass the Class to instrospect
|
||||
* @param nestedAnnotationsAsMap return nested annotations and annotation arrays as
|
||||
* {@link AnnotationAttributes} for compatibility with ASM-based
|
||||
* {@link AnnotationMetadata} implementations
|
||||
* {@link org.springframework.core.annotation.AnnotationAttributes} for compatibility
|
||||
* with ASM-based {@link AnnotationMetadata} implementations
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
|
||||
@@ -107,8 +108,7 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAnnotationAttributes(String annotationType,
|
||||
boolean classValuesAsString) {
|
||||
public Map<String, Object> getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
|
||||
return AnnotatedElementUtils.getAnnotationAttributes(getIntrospectedClass(),
|
||||
annotationType, classValuesAsString, this.nestedAnnotationsAsMap);
|
||||
}
|
||||
@@ -119,8 +119,7 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(
|
||||
String annotationType, boolean classValuesAsString) {
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType, boolean classValuesAsString) {
|
||||
return AnnotatedElementUtils.getAllAnnotationAttributes(getIntrospectedClass(),
|
||||
annotationType, classValuesAsString, this.nestedAnnotationsAsMap);
|
||||
}
|
||||
@@ -141,7 +140,6 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
|
||||
Method[] methods = getIntrospectedClass().getDeclaredMethods();
|
||||
Set<MethodMetadata> annotatedMethods = new LinkedHashSet<MethodMetadata>();
|
||||
for (Method method : methods) {
|
||||
// TODO: on OpenJDK 8 b99, bridge methods seem to be discovered as annotated as well...
|
||||
if (AnnotatedElementUtils.isAnnotated(method, annotationType)) {
|
||||
annotatedMethods.add(new StandardMethodMetadata(method, this.nestedAnnotationsAsMap));
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
@@ -49,9 +50,14 @@ public class StandardMethodMetadata implements MethodMetadata {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new StandardMethodMetadata wrapper for the given Method.
|
||||
* Create a new StandardMethodMetadata wrapper for the given Method,
|
||||
* providing the option to return any nested annotations or annotation arrays in the
|
||||
* form of {@link org.springframework.core.annotation.AnnotationAttributes} instead
|
||||
* of actual {@link java.lang.annotation.Annotation} instances.
|
||||
* @param introspectedMethod the Method to introspect
|
||||
* @param nestedAnnotationsAsMap
|
||||
* @param nestedAnnotationsAsMap return nested annotations and annotation arrays as
|
||||
* {@link org.springframework.core.annotation.AnnotationAttributes} for compatibility
|
||||
* with ASM-based {@link AnnotationMetadata} implementations
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public StandardMethodMetadata(Method introspectedMethod, boolean nestedAnnotationsAsMap) {
|
||||
@@ -115,8 +121,7 @@ public class StandardMethodMetadata implements MethodMetadata {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(
|
||||
String annotationType, boolean classValuesAsString) {
|
||||
public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationType, boolean classValuesAsString) {
|
||||
return AnnotatedElementUtils.getAllAnnotationAttributes(this.introspectedMethod,
|
||||
annotationType, classValuesAsString, this.nestedAnnotationsAsMap);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user