1 | /* |
2 | * Copyright 2002-2008 the original author or authors. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | package org.springframework.batch.support; |
18 | |
19 | import java.lang.annotation.Annotation; |
20 | import java.lang.annotation.ElementType; |
21 | import java.lang.annotation.Target; |
22 | import java.lang.reflect.Method; |
23 | import java.util.concurrent.atomic.AtomicReference; |
24 | |
25 | import org.springframework.aop.support.AopUtils; |
26 | import org.springframework.core.annotation.AnnotationUtils; |
27 | import org.springframework.util.Assert; |
28 | import org.springframework.util.ObjectUtils; |
29 | import org.springframework.util.ReflectionUtils; |
30 | |
31 | /** |
32 | * MethodResolver implementation that finds a <em>single</em> Method on the |
33 | * given Class that contains the specified annotation type. |
34 | * |
35 | * @author Mark Fisher |
36 | */ |
37 | public class AnnotationMethodResolver implements MethodResolver { |
38 | |
39 | private Class<? extends Annotation> annotationType; |
40 | |
41 | |
42 | /** |
43 | * Create a MethodResolver for the specified Method-level annotation type |
44 | */ |
45 | public AnnotationMethodResolver(Class<? extends Annotation> annotationType) { |
46 | Assert.notNull(annotationType, "annotationType must not be null"); |
47 | Assert.isTrue(ObjectUtils.containsElement( |
48 | annotationType.getAnnotation(Target.class).value(), ElementType.METHOD), |
49 | "Annotation [" + annotationType + "] is not a Method-level annotation."); |
50 | this.annotationType = annotationType; |
51 | } |
52 | |
53 | |
54 | /** |
55 | * Find a <em>single</em> Method on the Class of the given candidate object |
56 | * that contains the annotation type for which this resolver is searching. |
57 | * |
58 | * @param candidate the instance whose Class will be checked for the |
59 | * annotation |
60 | * |
61 | * @return a single matching Method instance or <code>null</code> if the |
62 | * candidate's Class contains no Methods with the specified annotation |
63 | * |
64 | * @throws IllegalArgumentException if more than one Method has the |
65 | * specified annotation |
66 | */ |
67 | @Override |
68 | public Method findMethod(Object candidate) { |
69 | Assert.notNull(candidate, "candidate object must not be null"); |
70 | Class<?> targetClass = AopUtils.getTargetClass(candidate); |
71 | if (targetClass == null) { |
72 | targetClass = candidate.getClass(); |
73 | } |
74 | return this.findMethod(targetClass); |
75 | } |
76 | |
77 | /** |
78 | * Find a <em>single</em> Method on the given Class that contains the |
79 | * annotation type for which this resolver is searching. |
80 | * |
81 | * @param clazz the Class instance to check for the annotation |
82 | * |
83 | * @return a single matching Method instance or <code>null</code> if the |
84 | * Class contains no Methods with the specified annotation |
85 | * |
86 | * @throws IllegalArgumentException if more than one Method has the |
87 | * specified annotation |
88 | */ |
89 | @Override |
90 | public Method findMethod(final Class<?> clazz) { |
91 | Assert.notNull(clazz, "class must not be null"); |
92 | final AtomicReference<Method> annotatedMethod = new AtomicReference<Method>(); |
93 | ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { |
94 | @Override |
95 | public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { |
96 | Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType); |
97 | if (annotation != null) { |
98 | Assert.isNull(annotatedMethod.get(), "found more than one method on target class [" |
99 | + clazz + "] with the annotation type [" + annotationType + "]"); |
100 | annotatedMethod.set(method); |
101 | } |
102 | } |
103 | }); |
104 | return annotatedMethod.get(); |
105 | } |
106 | |
107 | } |