diff --git a/org.springframework.core/ivy.xml b/org.springframework.core/ivy.xml
index 87d47b61d2c..8532a4dcc1e 100644
--- a/org.springframework.core/ivy.xml
+++ b/org.springframework.core/ivy.xml
@@ -23,6 +23,8 @@
Ordered instance overriding a statically defined
+ * annotation value (if any).
+ *
+ * @author Juergen Hoeller
+ * @since 2.0.1
+ * @see org.springframework.core.Ordered
+ * @see Order
+ */
+public class AnnotationAwareOrderComparator extends OrderComparator {
+
+ protected int getOrder(Object obj) {
+ if (obj instanceof Ordered) {
+ return ((Ordered) obj).getOrder();
+ }
+ if (obj != null) {
+ Order order = obj.getClass().getAnnotation(Order.class);
+ if (order != null) {
+ return order.value();
+ }
+ }
+ return Ordered.LOWEST_PRECEDENCE;
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/org.springframework.core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java
new file mode 100644
index 00000000000..5e38149b444
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2002-2008 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.Method;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.core.BridgeMethodResolver;
+import org.springframework.util.Assert;
+
+/**
+ * General utility methods for working with annotations, handling bridge methods
+ * (which the compiler generates for generic declarations) as well as super
+ * methods (for optional "annotation inheritance"). Note that none of
+ * this is provided by the JDK's introspection facilities themselves.
+ *
+ *
As a general rule for runtime-retained annotations (e.g. for transaction + * control, authorization or service exposure), always use the lookup methods on + * this class (e.g., {@link #findAnnotation(Method, Class)}, + * {@link #getAnnotation(Method, Class)}, and {@link #getAnnotations(Method)}) + * instead of the plain annotation lookup methods in the JDK. You can still + * explicitly choose between lookup on the given class level only + * ({@link #getAnnotation(Method, Class)}) and lookup in the entire inheritance + * hierarchy of the given method ({@link #findAnnotation(Method, Class)}). + * + * @author Rob Harrop + * @author Juergen Hoeller + * @author Sam Brannen + * @author Mark Fisher + * @since 2.0 + * @see java.lang.reflect.Method#getAnnotations() + * @see java.lang.reflect.Method#getAnnotation(Class) + */ +public abstract class AnnotationUtils { + + /** The attribute name for annotations with a single element */ + static final String VALUE = "value"; + + + /** + * Get all {@link Annotation Annotations} from the supplied {@link Method}. + *
Correctly handles bridge {@link Method Methods} generated by the compiler.
+ * @param method the method to look for annotations on
+ * @return the annotations found
+ * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
+ */
+ public static Annotation[] getAnnotations(Method method) {
+ return BridgeMethodResolver.findBridgedMethod(method).getAnnotations();
+ }
+
+ /**
+ * Get a single {@link Annotation} of annotationType from the
+ * supplied {@link Method}.
+ *
Correctly handles bridge {@link Method Methods} generated by the compiler.
+ * @param method the method to look for annotations on
+ * @param annotationType the annotation class to look for
+ * @return the annotations found
+ * @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)
+ */
+ public static A getAnnotation(Method method, Class annotationType) {
+ return BridgeMethodResolver.findBridgedMethod(method).getAnnotation(annotationType);
+ }
+
+ /**
+ * Get a single {@link Annotation} of Annotations on methods are not inherited by default, so we need to handle
+ * this explicitly. Tge
+ * @param method the method to look for annotations on
+ * @param annotationType the annotation class to look for
+ * @return the annotation found, or This method explicitly handles class-level annotations which are
+ * not declared as {@link java.lang.annotation.Inherited inherited}
+ * as well as annotations on interfaces.
+ * The algorithm operates as follows: Searches for an annotation on the given
+ * class and returns it if found. Else searches all interfaces that the given
+ * class declares, returning the annotation from the first matching candidate,
+ * if any. Else proceeds with introspection of the superclass of the given class,
+ * checking the superclass itself; if no annotation found there, proceeds with
+ * the interfaces that the superclass declares. Recursing up through the entire
+ * superclass hierarchy if no match is found.
+ * @param clazz the class to look for annotations on
+ * @param annotationType the annotation class to look for
+ * @return the annotation found, or If the supplied The standard {@link Class} API does not provide a mechanism for
+ * determining which class in an inheritance hierarchy actually declares an
+ * {@link Annotation}, so we need to handle this explicitly.
+ * @param annotationType the Class object corresponding to the annotation type
+ * @param clazz the Class object corresponding to the class on which to
+ * check for the annotation, or Note: This method does not determine if the annotation
+ * is {@link java.lang.annotation.Inherited inherited}. For greater clarity
+ * regarding inherited annotations, consider using
+ * {@link #isAnnotationInherited(Class, Class)} instead.
+ * @param annotationType the Class object corresponding to the annotation type
+ * @param clazz the Class object corresponding to the class on which to
+ * check for the annotation
+ * @return If the supplied Value is optional, and represents order value as defined
+ * in the Ordered interface. Lower values have higher priority.
+ * Default value is If this method returns Package-visible in order to allow for repackaging the ASM library
+ * without effect on users of the This filter is useful when matching needs to be made based on potentially the
+ * whole class/interface hierarchy. The algorithm employed uses succeed-fast
+ * strategy i.e. if at anytime a match is declared, no further processing is
+ * carried out.
+ *
+ * @author Ramnivas Laddad
+ * @author Mark Fisher
+ * @since 2.5
+ */
+public abstract class AbstractTypeHierarchyTraversingFilter implements TypeFilter {
+
+ private final boolean considerInherited;
+
+ private final boolean considerInterfaces;
+
+
+ protected AbstractTypeHierarchyTraversingFilter(boolean considerInherited, boolean considerInterfaces) {
+ this.considerInherited = considerInherited;
+ this.considerInterfaces = considerInterfaces;
+ }
+
+
+ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
+ throws IOException {
+
+ // This method optimizes avoiding unnecessary creation of ClassReaders
+ // as well as visiting over those readers.
+ if (matchSelf(metadataReader)) {
+ return true;
+ }
+ ClassMetadata metadata = metadataReader.getClassMetadata();
+ if (matchClassName(metadata.getClassName())) {
+ return true;
+ }
+
+ if (!this.considerInherited) {
+ return false;
+ }
+ if (metadata.hasSuperClass()) {
+ // Optimization to avoid creating ClassReader for super class.
+ Boolean superClassMatch = matchSuperClass(metadata.getSuperClassName());
+ if (superClassMatch != null) {
+ if (superClassMatch.booleanValue()) {
+ return true;
+ }
+ }
+ else {
+ // Need to read super class to determine a match...
+ if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
+ return true;
+ }
+ }
+ }
+
+ if (!this.considerInterfaces) {
+ return false;
+ }
+ for (String ifc : metadata.getInterfaceNames()) {
+ // Optimization to avoid creating ClassReader for super class
+ Boolean interfaceMatch = matchInterface(ifc);
+ if (interfaceMatch != null) {
+ if (interfaceMatch.booleanValue()) {
+ return true;
+ }
+ }
+ else {
+ // Need to read interface to determine a match...
+ if (match(ifc, metadataReaderFactory)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private boolean match(String className, MetadataReaderFactory metadataReaderFactory) throws IOException {
+ return match(metadataReaderFactory.getMetadataReader(className), metadataReaderFactory);
+ }
+
+ /**
+ * Override this to match self characteristics alone. Typically,
+ * the implementation will use a visitor to extract information
+ * to perform matching.
+ */
+ protected boolean matchSelf(MetadataReader metadataReader) {
+ return false;
+ }
+
+ /**
+ * Override this to match on type name.
+ */
+ protected boolean matchClassName(String className) {
+ return false;
+ }
+
+ /**
+ * Override this to match on super type name.
+ */
+ protected Boolean matchSuperClass(String superClassName) {
+ return null;
+ }
+
+ /**
+ * Override this to match on interface type name.
+ */
+ protected Boolean matchInterface(String interfaceNames) {
+ return null;
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/filter/AnnotationTypeFilter.java b/org.springframework.core/src/main/java/org/springframework/core/type/filter/AnnotationTypeFilter.java
new file mode 100644
index 00000000000..777ead9157a
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/type/filter/AnnotationTypeFilter.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2002-2007 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.filter;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Inherited;
+
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.core.type.classreading.MetadataReader;
+
+/**
+ * A simple filter which matches classes with a given annotation,
+ * checking inherited annotations as well.
+ *
+ * The matching logic mirrors that of A critical implementation details of this type filter is that it does not
+ * load the class being examined to match with a type pattern.
+ *
+ * @author Ramnivas Laddad
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+public class AspectJTypeFilter implements TypeFilter {
+
+ private final World world;
+
+ private final TypePattern typePattern;
+
+
+ public AspectJTypeFilter(String typePatternExpression, ClassLoader classLoader) {
+ this.world = new BcelWorld(classLoader, IMessageHandler.THROW, null);
+ this.world.setBehaveInJava5Way(true);
+ PatternParser patternParser = new PatternParser(typePatternExpression);
+ TypePattern typePattern = patternParser.parseTypePattern();
+ typePattern.resolve(this.world);
+ IScope scope = new SimpleScope(this.world, new FormalBinding[0]);
+ this.typePattern = typePattern.resolveBindings(scope, Bindings.NONE, false, false);
+ }
+
+
+ public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
+ throws IOException {
+
+ String className = metadataReader.getClassMetadata().getClassName();
+ ResolvedType resolvedType = this.world.resolve(className);
+ return this.typePattern.matchesStatically(resolvedType);
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/filter/AssignableTypeFilter.java b/org.springframework.core/src/main/java/org/springframework/core/type/filter/AssignableTypeFilter.java
new file mode 100644
index 00000000000..8fb8ecd3f7d
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/type/filter/AssignableTypeFilter.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2002-2007 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.filter;
+
+/**
+ * A simple filter which matches classes that are assignable to a given type.
+ *
+ * @author Rod Johnson
+ * @author Mark Fisher
+ * @author Ramnivas Laddad
+ * @since 2.5
+ */
+public class AssignableTypeFilter extends AbstractTypeHierarchyTraversingFilter {
+
+ private final Class targetType;
+
+
+ /**
+ * Create a new AssignableTypeFilter for the given type.
+ * @param targetType the type to match
+ */
+ public AssignableTypeFilter(Class targetType) {
+ super(true, true);
+ this.targetType = targetType;
+ }
+
+
+ @Override
+ protected boolean matchClassName(String className) {
+ return this.targetType.getName().equals(className);
+ }
+
+ @Override
+ protected Boolean matchSuperClass(String superClassName) {
+ return matchTargetType(superClassName);
+ }
+
+ @Override
+ protected Boolean matchInterface(String interfaceName) {
+ return matchTargetType(interfaceName);
+ }
+
+ protected Boolean matchTargetType(String typeName) {
+ if (this.targetType.getName().equals(typeName)) {
+ return true;
+ }
+ else if (Object.class.getName().equals(typeName)) {
+ return Boolean.FALSE;
+ }
+ else if (typeName.startsWith("java.")) {
+ try {
+ Class clazz = getClass().getClassLoader().loadClass(typeName);
+ return Boolean.valueOf(this.targetType.isAssignableFrom(clazz));
+ }
+ catch (ClassNotFoundException ex) {
+ // Class not found - can't determine a match that way.
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/filter/RegexPatternTypeFilter.java b/org.springframework.core/src/main/java/org/springframework/core/type/filter/RegexPatternTypeFilter.java
new file mode 100644
index 00000000000..16605d64b2f
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/type/filter/RegexPatternTypeFilter.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2002-2007 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.filter;
+
+import java.util.regex.Pattern;
+
+import org.springframework.core.type.ClassMetadata;
+import org.springframework.util.Assert;
+
+/**
+ * A simple filter for matching a fully-qualified class name with a regex {@link Pattern}.
+ *
+ * @author Mark Fisher
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+public class RegexPatternTypeFilter extends AbstractClassTestingTypeFilter {
+
+ private final Pattern pattern;
+
+
+ public RegexPatternTypeFilter(Pattern pattern) {
+ Assert.notNull(pattern, "Pattern must not be null");
+ this.pattern = pattern;
+ }
+
+
+ @Override
+ protected boolean match(ClassMetadata metadata) {
+ return this.pattern.matcher(metadata.getClassName()).matches();
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/filter/TypeFilter.java b/org.springframework.core/src/main/java/org/springframework/core/type/filter/TypeFilter.java
new file mode 100644
index 00000000000..bdcf33524d5
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/type/filter/TypeFilter.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2002-2007 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.filter;
+
+import java.io.IOException;
+
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+
+/**
+ * Base interface for type filters using a
+ * {@link org.springframework.core.type.classreading.MetadataReader}.
+ *
+ * @author Costin Leau
+ * @author Juergen Hoeller
+ * @author Mark Fisher
+ * @since 2.5
+ */
+public interface TypeFilter {
+
+ /**
+ * Determine whether this filter matches for the class described by
+ * the given metadata.
+ * @param metadataReader the metadata reader for the target class
+ * @param metadataReaderFactory a factory for obtaining metadata readers
+ * for other classes (such as superclasses and interfaces)
+ * @return whether this filter matches
+ * @throws IOException in case of I/O failure when reading metadata
+ */
+ boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
+ throws IOException;
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/filter/package.html b/org.springframework.core/src/main/java/org/springframework/core/type/filter/package.html
new file mode 100644
index 00000000000..fad995c6bd7
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/type/filter/package.html
@@ -0,0 +1,7 @@
+
+annotationType from the
+ * supplied {@link Method}, traversing its super methods if no annotation
+ * can be found on the given method itself.
+ * null if none found
+ */
+ public static A findAnnotation(Method method, Class annotationType) {
+ A annotation = getAnnotation(method, annotationType);
+ Class> cl = method.getDeclaringClass();
+ while (annotation == null) {
+ cl = cl.getSuperclass();
+ if (cl == null || cl == Object.class) {
+ break;
+ }
+ try {
+ Method equivalentMethod = cl.getDeclaredMethod(method.getName(), method.getParameterTypes());
+ annotation = getAnnotation(equivalentMethod, annotationType);
+ }
+ catch (NoSuchMethodException ex) {
+ // We're done...
+ }
+ }
+ return annotation;
+ }
+
+ /**
+ * Find a single {@link Annotation} of annotationType from the
+ * supplied {@link Class}, traversing its interfaces and super classes
+ * if no annotation can be found on the given class itself.
+ * null if none found
+ */
+ public static A findAnnotation(Class> clazz, Class annotationType) {
+ Assert.notNull(clazz, "Class must not be null");
+ A annotation = clazz.getAnnotation(annotationType);
+ if (annotation != null) {
+ return annotation;
+ }
+ for (Class> ifc : clazz.getInterfaces()) {
+ annotation = findAnnotation(ifc, annotationType);
+ if (annotation != null) {
+ return annotation;
+ }
+ }
+ Class superClass = clazz.getSuperclass();
+ if (superClass == null || superClass == Object.class) {
+ return null;
+ }
+ return findAnnotation(superClass, annotationType);
+ }
+
+ /**
+ * Find the first {@link Class} in the inheritance hierarchy of the
+ * specified clazz (including the specified
+ * clazz itself) which declares an annotation for the
+ * specified annotationType, or null if not
+ * found. If the supplied clazz is null,
+ * null will be returned.
+ * clazz is an interface, only the interface
+ * itself will be checked; the inheritance hierarchy for interfaces will not
+ * be traversed.
+ * null.
+ * @return the first {@link Class} in the inheritance hierarchy of the
+ * specified clazz which declares an annotation for the specified
+ * annotationType, or null if not found.
+ * @see Class#isAnnotationPresent(Class)
+ * @see Class#getDeclaredAnnotations()
+ */
+ public static Class> findAnnotationDeclaringClass(Class extends Annotation> annotationType, Class> clazz) {
+ Assert.notNull(annotationType, "Annotation type must not be null");
+ if (clazz == null || clazz.equals(Object.class)) {
+ return null;
+ }
+ return (isAnnotationDeclaredLocally(annotationType, clazz)) ?
+ clazz : findAnnotationDeclaringClass(annotationType, clazz.getSuperclass());
+ }
+
+ /**
+ * Determine whether an annotation for the specified annotationType
+ * is declared locally on the supplied clazz.
+ * The supplied {@link Class} object may represent any type.
+ * true if an annotation for the specified
+ * annotationType is declared locally on the supplied clazz
+ * @see Class#getDeclaredAnnotations()
+ * @see #isAnnotationInherited(Class, Class)
+ */
+ public static boolean isAnnotationDeclaredLocally(Class extends Annotation> annotationType, Class> clazz) {
+ Assert.notNull(annotationType, "Annotation type must not be null");
+ Assert.notNull(clazz, "Class must not be null");
+ boolean declaredLocally = false;
+ for (Annotation annotation : Arrays.asList(clazz.getDeclaredAnnotations())) {
+ if (annotation.annotationType().equals(annotationType)) {
+ declaredLocally = true;
+ break;
+ }
+ }
+ return declaredLocally;
+ }
+
+ /**
+ * Determine whether an annotation for the specified annotationType
+ * is present on the supplied clazz and is
+ * {@link java.lang.annotation.Inherited inherited}
+ * (i.e., not declared locally for the class).
+ * clazz is an interface, only the interface
+ * itself will be checked. In accord with standard meta-annotation
+ * semantics, the inheritance hierarchy for interfaces will not be
+ * traversed. See the {@link java.lang.annotation.Inherited JavaDoc} for the
+ * @Inherited meta-annotation for further details regarding annotation
+ * inheritance.
+ * @param annotationType the Class object corresponding to the annotation type
+ * @param clazz the Class object corresponding to the class on which to
+ * check for the annotation
+ * @return true if an annotation for the specified
+ * annotationType is present on the supplied clazz
+ * and is {@link java.lang.annotation.Inherited inherited}
+ * @see Class#isAnnotationPresent(Class)
+ * @see #isAnnotationDeclaredLocally(Class, Class)
+ */
+ public static boolean isAnnotationInherited(Class extends Annotation> annotationType, Class> clazz) {
+ Assert.notNull(annotationType, "Annotation type must not be null");
+ Assert.notNull(clazz, "Class must not be null");
+ return (clazz.isAnnotationPresent(annotationType) && !isAnnotationDeclaredLocally(annotationType, clazz));
+ }
+
+ /**
+ * Retrieve the given annotation's attributes as a Map.
+ * @param annotation the annotation to retrieve the attributes for
+ * @return the Map of annotation attributes, with attribute names as keys
+ * and corresponding attribute values as values
+ */
+ public static Map"value"
+ * attribute of a single-element Annotation, given an annotation instance.
+ * @param annotation the annotation instance from which to retrieve the value
+ * @return the attribute value, or null if not found
+ * @see #getValue(Annotation, String)
+ */
+ public static Object getValue(Annotation annotation) {
+ return getValue(annotation, VALUE);
+ }
+
+ /**
+ * Retrieve the value of a named Annotation attribute, given an
+ * annotation instance.
+ * @see #getValue(Annotation)
+ * @param annotation the annotation instance from which to retrieve the value
+ * @param attributeName the name of the attribute value to retrieve
+ * @return the attribute value, or null if not found
+ */
+ public static Object getValue(Annotation annotation, String attributeName) {
+ try {
+ Method method = annotation.annotationType().getDeclaredMethod(attributeName, new Class[0]);
+ return method.invoke(annotation);
+ }
+ catch (Exception ex) {
+ return null;
+ }
+ }
+
+ /**
+ * Retrieve the default value of the
+ * "value" attribute of a single-element
+ * Annotation, given an annotation instance.
+ * @param annotation the annotation instance from which to retrieve
+ * the default value
+ * @return the default value, or null if not found
+ * @see #getDefaultValue(Annotation, String)
+ */
+ public static Object getDefaultValue(Annotation annotation) {
+ return getDefaultValue(annotation, VALUE);
+ }
+
+ /**
+ * Retrieve the default value of a named Annotation attribute,
+ * given an annotation instance.
+ * @param annotation the annotation instance from which to retrieve
+ * the default value
+ * @param attributeName the name of the attribute value to retrieve
+ * @return the default value of the named attribute, or null
+ * if not found.
+ * @see #getDefaultValue(Class, String)
+ */
+ public static Object getDefaultValue(Annotation annotation, String attributeName) {
+ return getDefaultValue(annotation.annotationType(), attributeName);
+ }
+
+ /**
+ * Retrieve the default value of the
+ * "value" attribute of a single-element
+ * Annotation, given the {@link Class annotation type}.
+ * @param annotationType the annotation type for which the
+ * default value should be retrieved
+ * @return the default value, or null if not found
+ * @see #getDefaultValue(Class, String)
+ */
+ public static Object getDefaultValue(Class extends Annotation> annotationType) {
+ return getDefaultValue(annotationType, VALUE);
+ }
+
+ /**
+ * Retrieve the default value of a named Annotation attribute,
+ * given the {@link Class annotation type}.
+ * @param annotationType the annotation type for which the
+ * default value should be retrieved
+ * @param attributeName the name of the attribute value to retrieve.
+ * @return the default value of the named attribute, or null
+ * if not found
+ * @see #getDefaultValue(Annotation, String)
+ */
+ public static Object getDefaultValue(Class extends Annotation> annotationType, String attributeName) {
+ try {
+ Method method = annotationType.getDeclaredMethod(attributeName, new Class[0]);
+ return method.getDefaultValue();
+ }
+ catch (Exception ex) {
+ return null;
+ }
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/annotation/Order.java b/org.springframework.core/src/main/java/org/springframework/core/annotation/Order.java
new file mode 100644
index 00000000000..917e7b8eebb
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/annotation/Order.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2002-2006 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.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.core.Ordered;
+
+/**
+ * Annotation to define ordering.
+ *
+ * Integer.MAX_VALUE, indicating lowest
+ * priority (losing to any other specified order value).
+ *
+ * @author Rod Johnson
+ * @since 2.0
+ * @see org.springframework.core.Ordered
+ * @see AnnotationAwareOrderComparator
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
+public @interface Order {
+
+ int value() default Ordered.LOWEST_PRECEDENCE;
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/annotation/package.html b/org.springframework.core/src/main/java/org/springframework/core/annotation/package.html
new file mode 100644
index 00000000000..c9139bffb60
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/annotation/package.html
@@ -0,0 +1,7 @@
+
+null if no matching
+ * annotation is defined.
+ */
+ Mapfalse, then the
+ * underlying class is a top-level class.
+ */
+ boolean hasEnclosingClass();
+
+ /**
+ * Return the name of the enclosing class of the underlying class,
+ * or null if the underlying class is a top-level class.
+ */
+ String getEnclosingClassName();
+
+ /**
+ * Return whether the underlying class has a super class.
+ */
+ boolean hasSuperClass();
+
+ /**
+ * Return the name of the super class of the underlying class,
+ * or null if there is no super class defined.
+ */
+ String getSuperClassName();
+
+ /**
+ * Return the name of all interfaces that the underlying class
+ * implements, or an empty array if there are none.
+ */
+ String[] getInterfaceNames();
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/StandardAnnotationMetadata.java b/org.springframework.core/src/main/java/org/springframework/core/type/StandardAnnotationMetadata.java
new file mode 100644
index 00000000000..471cd55cb0c
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/type/StandardAnnotationMetadata.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2002-2007 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.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.core.annotation.AnnotationUtils;
+
+/**
+ * {@link AnnotationMetadata} implementation that uses standard reflection
+ * to introspect a given Class.
+ *
+ * @author Juergen Hoeller
+ * @author Mark Fisher
+ * @since 2.5
+ */
+public class StandardAnnotationMetadata extends StandardClassMetadata implements AnnotationMetadata {
+
+ public StandardAnnotationMetadata(Class introspectedClass) {
+ super(introspectedClass);
+ }
+
+
+ public SetClass.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+public class StandardClassMetadata implements ClassMetadata {
+
+ private final Class introspectedClass;
+
+
+ public StandardClassMetadata(Class introspectedClass) {
+ this.introspectedClass = introspectedClass;
+ }
+
+ public final Class getIntrospectedClass() {
+ return this.introspectedClass;
+ }
+
+
+ public String getClassName() {
+ return getIntrospectedClass().getName();
+ }
+
+ public boolean isInterface() {
+ return getIntrospectedClass().isInterface();
+ }
+
+ public boolean isAbstract() {
+ return Modifier.isAbstract(getIntrospectedClass().getModifiers());
+ }
+
+ public boolean isConcrete() {
+ return !(isInterface() || isAbstract());
+ }
+
+ public boolean isIndependent() {
+ return (!hasEnclosingClass() ||
+ (getIntrospectedClass().getDeclaringClass() != null &&
+ Modifier.isStatic(getIntrospectedClass().getModifiers())));
+ }
+
+ public boolean hasEnclosingClass() {
+ return (getIntrospectedClass().getEnclosingClass() != null);
+ }
+
+ public String getEnclosingClassName() {
+ Class enclosingClass = getIntrospectedClass().getEnclosingClass();
+ return (enclosingClass != null ? enclosingClass.getName() : null);
+ }
+
+ public boolean hasSuperClass() {
+ return (getIntrospectedClass().getSuperclass() != null);
+ }
+
+ public String getSuperClassName() {
+ Class superClass = getIntrospectedClass().getSuperclass();
+ return (superClass != null ? superClass.getName() : null);
+ }
+
+ public String[] getInterfaceNames() {
+ Class[] ifcs = getIntrospectedClass().getInterfaces();
+ String[] ifcNames = new String[ifcs.length];
+ for (int i = 0; i < ifcs.length; i++) {
+ ifcNames[i] = ifcs[i].getName();
+ }
+ return ifcNames;
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/classreading/AnnotationMetadataReadingVisitor.java b/org.springframework.core/src/main/java/org/springframework/core/type/classreading/AnnotationMetadataReadingVisitor.java
new file mode 100644
index 00000000000..9236bf38fa9
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/type/classreading/AnnotationMetadataReadingVisitor.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2002-2008 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.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+import org.springframework.core.type.AnnotationMetadata;
+
+/**
+ * ASM class visitor which looks for the class name and implemented types as
+ * well as for the annotations defined on the class, exposing them through
+ * the {@link org.springframework.core.type.AnnotationMetadata} interface.
+ *
+ * @author Juergen Hoeller
+ * @author Mark Fisher
+ * @since 2.5
+ */
+class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor implements AnnotationMetadata {
+
+ private final Mapnull)
+ * @throws IOException in case of I/O failure
+ */
+ MetadataReader getMetadataReader(String className) throws IOException;
+
+ /**
+ * Obtain a MetadataReader for the given resource.
+ * @param resource the resource (pointing to a ".class" file)
+ * @return a holder for the ClassReader instance (never null)
+ * @throws IOException in case of I/O failure
+ */
+ MetadataReader getMetadataReader(Resource resource) throws IOException;
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/classreading/SimpleMetadataReader.java b/org.springframework.core/src/main/java/org/springframework/core/type/classreading/SimpleMetadataReader.java
new file mode 100644
index 00000000000..d4b711fe814
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/type/classreading/SimpleMetadataReader.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2002-2008 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 org.objectweb.asm.ClassReader;
+
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.core.type.ClassMetadata;
+
+/**
+ * {@link MetadataReader} implementation based on an ASM
+ * {@link org.objectweb.asm.ClassReader}.
+ *
+ * core.type package.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+class SimpleMetadataReader implements MetadataReader {
+
+ private final ClassReader classReader;
+
+ private final ClassLoader classLoader;
+
+
+ public SimpleMetadataReader(ClassReader classReader, ClassLoader classLoader) {
+ this.classReader = classReader;
+ this.classLoader = classLoader;
+ }
+
+
+ public ClassMetadata getClassMetadata() {
+ ClassMetadataReadingVisitor visitor = new ClassMetadataReadingVisitor();
+ this.classReader.accept(visitor, true);
+ return visitor;
+ }
+
+ public AnnotationMetadata getAnnotationMetadata() {
+ AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(this.classLoader);
+ this.classReader.accept(visitor, true);
+ return visitor;
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/classreading/SimpleMetadataReaderFactory.java b/org.springframework.core/src/main/java/org/springframework/core/type/classreading/SimpleMetadataReaderFactory.java
new file mode 100644
index 00000000000..90b7b2ce9b6
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/type/classreading/SimpleMetadataReaderFactory.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2002-2008 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.io.IOException;
+import java.io.InputStream;
+
+import org.objectweb.asm.ClassReader;
+
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Simple implementation of the {@link MetadataReaderFactory} interface,
+ * creating a new ASM {@link org.objectweb.asm.ClassReader} for every request.
+ *
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+public class SimpleMetadataReaderFactory implements MetadataReaderFactory {
+
+ private final ResourceLoader resourceLoader;
+
+
+ /**
+ * Create a new SimpleMetadataReaderFactory for the default class loader.
+ */
+ public SimpleMetadataReaderFactory() {
+ this.resourceLoader = new DefaultResourceLoader();
+ }
+
+ /**
+ * Create a new SimpleMetadataReaderFactory for the given resource loader.
+ * @param resourceLoader the Spring ResourceLoader to use
+ * (also determines the ClassLoader to use)
+ */
+ public SimpleMetadataReaderFactory(ResourceLoader resourceLoader) {
+ this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader());
+ }
+
+ /**
+ * Create a new SimpleMetadataReaderFactory for the given class loader.
+ * @param classLoader the ClassLoader to use
+ */
+ public SimpleMetadataReaderFactory(ClassLoader classLoader) {
+ this.resourceLoader =
+ (classLoader != null ? new DefaultResourceLoader(classLoader) : new DefaultResourceLoader());
+ }
+
+
+ public MetadataReader getMetadataReader(String className) throws IOException {
+ String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
+ ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
+ return getMetadataReader(this.resourceLoader.getResource(resourcePath));
+ }
+
+ public MetadataReader getMetadataReader(Resource resource) throws IOException {
+ InputStream is = resource.getInputStream();
+ try {
+ return new SimpleMetadataReader(new ClassReader(is), this.resourceLoader.getClassLoader());
+ }
+ finally {
+ is.close();
+ }
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/classreading/package.html b/org.springframework.core/src/main/java/org/springframework/core/type/classreading/package.html
new file mode 100644
index 00000000000..4af765c4ffe
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/type/classreading/package.html
@@ -0,0 +1,7 @@
+
+Class.isAnnotationPresent().
+ *
+ * @author Mark Fisher
+ * @author Ramnivas Laddad
+ * @author Juergen Hoeller
+ * @since 2.5
+ */
+public class AnnotationTypeFilter extends AbstractTypeHierarchyTraversingFilter {
+
+ private final Class extends Annotation> annotationType;
+
+ private final boolean considerMetaAnnotations;
+
+
+ /**
+ * Create a new AnnotationTypeFilter for the given annotation type.
+ * This filter will also match meta-annotations. To disable the
+ * meta-annotation matching, use the constructor that accepts a
+ * 'considerMetaAnnotations' argument.
+ * @param annotationType the annotation type to match
+ */
+ public AnnotationTypeFilter(Class extends Annotation> annotationType) {
+ this(annotationType, true);
+ }
+
+ /**
+ * Create a new AnnotationTypeFilter for the given annotation type.
+ * @param annotationType the annotation type to match
+ * @param considerMetaAnnotations whether to also match on meta-annotations
+ */
+ public AnnotationTypeFilter(Class extends Annotation> annotationType, boolean considerMetaAnnotations) {
+ super(annotationType.isAnnotationPresent(Inherited.class), false);
+ this.annotationType = annotationType;
+ this.considerMetaAnnotations = considerMetaAnnotations;
+ }
+
+
+ @Override
+ protected boolean matchSelf(MetadataReader metadataReader) {
+ AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
+ return metadata.hasAnnotation(this.annotationType.getName()) ||
+ (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
+ }
+
+ @Override
+ protected Boolean matchSuperClass(String superClassName) {
+ if (Object.class.getName().equals(superClassName)) {
+ return Boolean.FALSE;
+ }
+ else if (superClassName.startsWith("java.")) {
+ try {
+ Class clazz = getClass().getClassLoader().loadClass(superClassName);
+ return Boolean.valueOf(clazz.getAnnotation(this.annotationType) != null);
+ }
+ catch (ClassNotFoundException ex) {
+ // Class not found - can't determine a match that way.
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/org.springframework.core/src/main/java/org/springframework/core/type/filter/AspectJTypeFilter.java b/org.springframework.core/src/main/java/org/springframework/core/type/filter/AspectJTypeFilter.java
new file mode 100644
index 00000000000..262338d9124
--- /dev/null
+++ b/org.springframework.core/src/main/java/org/springframework/core/type/filter/AspectJTypeFilter.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2002-2007 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.filter;
+
+import java.io.IOException;
+
+import org.aspectj.bridge.IMessageHandler;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.bcel.BcelWorld;
+import org.aspectj.weaver.patterns.Bindings;
+import org.aspectj.weaver.patterns.FormalBinding;
+import org.aspectj.weaver.patterns.IScope;
+import org.aspectj.weaver.patterns.PatternParser;
+import org.aspectj.weaver.patterns.SimpleScope;
+import org.aspectj.weaver.patterns.TypePattern;
+
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+
+/**
+ * Type filter that uses AspectJ type pattern for matching.
+ *
+ *