11 changed files with 434 additions and 261 deletions
@ -0,0 +1,202 @@
@@ -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); |
||||
} |
||||
|
||||
} |
||||
@ -1,165 +0,0 @@
@@ -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); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue