1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.batch.support;
17
18 import java.lang.annotation.Annotation;
19 import java.lang.annotation.ElementType;
20 import java.lang.annotation.Target;
21 import java.lang.reflect.Method;
22 import java.util.concurrent.atomic.AtomicReference;
23
24 import org.springframework.aop.framework.Advised;
25 import org.springframework.core.annotation.AnnotationUtils;
26 import org.springframework.util.Assert;
27 import org.springframework.util.ClassUtils;
28 import org.springframework.util.ObjectUtils;
29 import org.springframework.util.ReflectionUtils;
30
31
32
33
34
35
36
37 public class MethodInvokerUtils {
38
39
40
41
42
43
44
45
46
47
48
49 public static MethodInvoker getMethodInvokerByName(Object object, String methodName, boolean paramsRequired,
50 Class<?>... paramTypes) {
51 Assert.notNull(object, "Object to invoke must not be null");
52 Method method = ClassUtils.getMethodIfAvailable(object.getClass(), methodName, paramTypes);
53 if (method == null) {
54 String errorMsg = "no method found with name [" + methodName + "] on class ["
55 + object.getClass().getSimpleName() + "] compatable with the signature ["
56 + getParamTypesString(paramTypes) + "].";
57 Assert.isTrue(!paramsRequired, errorMsg);
58
59
60 method = ClassUtils.getMethodIfAvailable(object.getClass(), methodName, new Class[] {});
61 Assert.notNull(method, errorMsg);
62 }
63 return new SimpleMethodInvoker(object, method);
64 }
65
66
67
68
69
70
71
72 public static String getParamTypesString(Class<?>... paramTypes) {
73 StringBuffer paramTypesList = new StringBuffer("(");
74 for (int i = 0; i < paramTypes.length; i++) {
75 paramTypesList.append(paramTypes[i].getSimpleName());
76 if (i + 1 < paramTypes.length) {
77 paramTypesList.append(", ");
78 }
79 }
80 return paramTypesList.append(")").toString();
81 }
82
83
84
85
86
87
88
89
90
91
92
93 public static MethodInvoker getMethodInvokerForInterface(Class<?> cls, String methodName, Object object,
94 Class<?>... paramTypes) {
95
96 if (cls.isAssignableFrom(object.getClass())) {
97 return MethodInvokerUtils.getMethodInvokerByName(object, methodName, true, paramTypes);
98 }
99 else {
100 return null;
101 }
102 }
103
104
105
106
107
108
109
110
111
112
113 public static MethodInvoker getMethodInvokerByAnnotation(final Class<? extends Annotation> annotationType,
114 final Object target, final Class<?>... expectedParamTypes) {
115 MethodInvoker mi = MethodInvokerUtils.getMethodInvokerByAnnotation(annotationType, target);
116 final Class<?> targetClass = (target instanceof Advised) ? ((Advised) target).getTargetSource()
117 .getTargetClass() : target.getClass();
118 if (mi != null) {
119 ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
120 @Override
121 public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
122 Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType);
123 if (annotation != null) {
124 Class<?>[] paramTypes = method.getParameterTypes();
125 if (paramTypes.length > 0) {
126 String errorMsg = "The method [" + method.getName() + "] on target class ["
127 + targetClass.getSimpleName() + "] is incompatable with the signature ["
128 + getParamTypesString(expectedParamTypes) + "] expected for the annotation ["
129 + annotationType.getSimpleName() + "].";
130
131 Assert.isTrue(paramTypes.length == expectedParamTypes.length, errorMsg);
132 for (int i = 0; i < paramTypes.length; i++) {
133 Assert.isTrue(expectedParamTypes[i].isAssignableFrom(paramTypes[i]), errorMsg);
134 }
135 }
136 }
137 }
138 });
139 }
140 return mi;
141 }
142
143
144
145
146
147
148
149
150
151
152
153 public static MethodInvoker getMethodInvokerByAnnotation(final Class<? extends Annotation> annotationType,
154 final Object target) {
155 Assert.notNull(target, "Target must not be null");
156 Assert.notNull(annotationType, "AnnotationType must not be null");
157 Assert.isTrue(ObjectUtils.containsElement(annotationType.getAnnotation(Target.class).value(),
158 ElementType.METHOD), "Annotation [" + annotationType + "] is not a Method-level annotation.");
159 final Class<?> targetClass = (target instanceof Advised) ? ((Advised) target).getTargetSource()
160 .getTargetClass() : target.getClass();
161 if (targetClass == null) {
162
163 return null;
164 }
165 final AtomicReference<Method> annotatedMethod = new AtomicReference<Method>();
166 ReflectionUtils.doWithMethods(targetClass, new ReflectionUtils.MethodCallback() {
167 @Override
168 public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
169 Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType);
170 if (annotation != null) {
171 Assert.isNull(annotatedMethod.get(), "found more than one method on target class ["
172 + targetClass.getSimpleName() + "] with the annotation type ["
173 + annotationType.getSimpleName() + "].");
174 annotatedMethod.set(method);
175 }
176 }
177 });
178 Method method = annotatedMethod.get();
179 if (method == null) {
180 return null;
181 }
182 else {
183 return new SimpleMethodInvoker(target, annotatedMethod.get());
184 }
185 }
186
187
188
189
190
191
192
193
194 public static <C, T> MethodInvoker getMethodInvokerForSingleArgument(Object target) {
195 final AtomicReference<Method> methodHolder = new AtomicReference<Method>();
196 ReflectionUtils.doWithMethods(target.getClass(), new ReflectionUtils.MethodCallback() {
197 @Override
198 public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
199 if (method.getParameterTypes() == null || method.getParameterTypes().length != 1) {
200 return;
201 }
202 if (method.getReturnType().equals(Void.TYPE) || ReflectionUtils.isEqualsMethod(method)) {
203 return;
204 }
205 Assert.state(methodHolder.get() == null,
206 "More than one non-void public method detected with single argument.");
207 methodHolder.set(method);
208 }
209 });
210 Method method = methodHolder.get();
211 return new SimpleMethodInvoker(target, method);
212 }
213 }