1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.lang3.reflect;
18
19 import java.lang.reflect.AccessibleObject;
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Member;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Modifier;
24
25 import org.apache.commons.lang3.ClassUtils;
26
27
28
29
30
31 final class MemberUtils {
32
33
34
35
36
37
38 private static final class Executable {
39
40 private static Executable of(final Constructor<?> constructor) {
41 return new Executable(constructor);
42 }
43
44 private static Executable of(final Method method) {
45 return new Executable(method);
46 }
47
48 private final Class<?>[] parameterTypes;
49 private final boolean isVarArgs;
50
51 private Executable(final Constructor<?> constructor) {
52 parameterTypes = constructor.getParameterTypes();
53 isVarArgs = constructor.isVarArgs();
54 }
55
56 private Executable(final Method method) {
57 parameterTypes = method.getParameterTypes();
58 isVarArgs = method.isVarArgs();
59 }
60
61 public Class<?>[] getParameterTypes() {
62 return parameterTypes;
63 }
64
65 public boolean isVarArgs() {
66 return isVarArgs;
67 }
68 }
69
70 private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
71
72
73
74
75 private static final Class<?>[] WIDENING_PRIMITIVE_TYPES = {
76
77 Byte.TYPE,
78 Short.TYPE,
79 Character.TYPE,
80 Integer.TYPE,
81 Long.TYPE,
82 Float.TYPE,
83 Double.TYPE
84
85 };
86
87
88
89
90
91
92
93
94
95
96 static int compareConstructorFit(final Constructor<?> left, final Constructor<?> right, final Class<?>[] actual) {
97 return compareParameterTypes(Executable.of(left), Executable.of(right), actual);
98 }
99
100
101
102
103
104
105
106
107
108
109 static int compareMethodFit(final Method left, final Method right, final Class<?>[] actual) {
110 return compareParameterTypes(Executable.of(left), Executable.of(right), actual);
111 }
112
113
114
115
116
117
118
119
120
121
122 private static int compareParameterTypes(final Executable left, final Executable right, final Class<?>[] actual) {
123 final float leftCost = getTotalTransformationCost(actual, left);
124 final float rightCost = getTotalTransformationCost(actual, right);
125 return Float.compare(leftCost, rightCost);
126 }
127
128
129
130
131
132
133
134
135 private static float getObjectTransformationCost(Class<?> srcClass, final Class<?> destClass) {
136 if (destClass.isPrimitive()) {
137 return getPrimitivePromotionCost(srcClass, destClass);
138 }
139 float cost = 0.0f;
140 while (srcClass != null && !destClass.equals(srcClass)) {
141 if (destClass.isInterface() && ClassUtils.isAssignable(srcClass, destClass)) {
142
143
144
145
146
147 cost += 0.25f;
148 break;
149 }
150 cost++;
151 srcClass = srcClass.getSuperclass();
152 }
153
154
155
156 if (srcClass == null) {
157 cost += 1.5f;
158 }
159 return cost;
160 }
161
162
163
164
165
166
167
168
169 private static float getPrimitivePromotionCost(final Class<?> srcClass, final Class<?> destClass) {
170 if (srcClass == null) {
171 return 1.5f;
172 }
173 float cost = 0.0f;
174 Class<?> cls = srcClass;
175 if (!cls.isPrimitive()) {
176
177 cost += 0.1f;
178 cls = ClassUtils.wrapperToPrimitive(cls);
179 }
180
181 for (int i = 0; cls != destClass && i < WIDENING_PRIMITIVE_TYPES.length; i++) {
182 if (cls == WIDENING_PRIMITIVE_TYPES[i]) {
183 cost += 0.1f;
184 if (i < WIDENING_PRIMITIVE_TYPES.length - 1) {
185 cls = WIDENING_PRIMITIVE_TYPES[i + 1];
186 }
187 }
188 }
189 return cost;
190 }
191
192
193
194
195
196
197
198
199 private static float getTotalTransformationCost(final Class<?>[] srcArgs, final Executable executable) {
200 final Class<?>[] destArgs = executable.getParameterTypes();
201 final boolean isVarArgs = executable.isVarArgs();
202
203 float totalCost = 0.0f;
204 final long normalArgsLen = isVarArgs ? destArgs.length - 1 : destArgs.length;
205 if (srcArgs.length < normalArgsLen) {
206 return Float.MAX_VALUE;
207 }
208 for (int i = 0; i < normalArgsLen; i++) {
209 totalCost += getObjectTransformationCost(srcArgs[i], destArgs[i]);
210 }
211 if (isVarArgs) {
212
213
214 final boolean noVarArgsPassed = srcArgs.length < destArgs.length;
215 final boolean explicitArrayForVarargs = srcArgs.length == destArgs.length && srcArgs[srcArgs.length - 1] != null
216 && srcArgs[srcArgs.length - 1].isArray();
217 final float varArgsCost = 0.001f;
218 final Class<?> destClass = destArgs[destArgs.length - 1].getComponentType();
219 if (noVarArgsPassed) {
220
221 totalCost += getObjectTransformationCost(destClass, Object.class) + varArgsCost;
222 } else if (explicitArrayForVarargs) {
223 final Class<?> sourceClass = srcArgs[srcArgs.length - 1].getComponentType();
224 totalCost += getObjectTransformationCost(sourceClass, destClass) + varArgsCost;
225 } else {
226
227 for (int i = destArgs.length - 1; i < srcArgs.length; i++) {
228 final Class<?> srcClass = srcArgs[i];
229 totalCost += getObjectTransformationCost(srcClass, destClass) + varArgsCost;
230 }
231 }
232 }
233 return totalCost;
234 }
235
236
237
238
239
240
241
242 static boolean isAccessible(final Member member) {
243 return isPublic(member) && !member.isSynthetic();
244 }
245
246 static boolean isMatchingConstructor(final Constructor<?> method, final Class<?>[] parameterTypes) {
247 return isMatchingExecutable(Executable.of(method), parameterTypes);
248 }
249
250 private static boolean isMatchingExecutable(final Executable method, final Class<?>[] parameterTypes) {
251 final Class<?>[] methodParameterTypes = method.getParameterTypes();
252 if (ClassUtils.isAssignable(parameterTypes, methodParameterTypes, true)) {
253 return true;
254 }
255 if (method.isVarArgs()) {
256 int i;
257 for (i = 0; i < methodParameterTypes.length - 1 && i < parameterTypes.length; i++) {
258 if (!ClassUtils.isAssignable(parameterTypes[i], methodParameterTypes[i], true)) {
259 return false;
260 }
261 }
262 final Class<?> varArgParameterType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType();
263 for (; i < parameterTypes.length; i++) {
264 if (!ClassUtils.isAssignable(parameterTypes[i], varArgParameterType, true)) {
265 return false;
266 }
267 }
268 return true;
269 }
270 return false;
271 }
272
273 static boolean isMatchingMethod(final Method method, final Class<?>[] parameterTypes) {
274 return isMatchingExecutable(Executable.of(method), parameterTypes);
275 }
276
277
278
279
280
281
282
283 static boolean isPackage(final int modifiers) {
284 return (modifiers & ACCESS_TEST) == 0;
285 }
286
287
288
289
290
291
292
293 static boolean isPublic(final Member member) {
294 return member != null && Modifier.isPublic(member.getModifiers());
295 }
296
297
298
299
300
301
302
303 static boolean isStatic(final Member member) {
304 return member != null && Modifier.isStatic(member.getModifiers());
305 }
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322 static <T extends AccessibleObject> T setAccessibleWorkaround(final T obj) {
323 if (AccessibleObjects.isAccessible(obj)) {
324 return obj;
325 }
326 final Member m = (Member) obj;
327 if (isPublic(m) && isPackage(m.getDeclaringClass().getModifiers())) {
328 try {
329 obj.setAccessible(true);
330 return obj;
331 } catch (final SecurityException ignored) {
332
333 }
334 }
335 return obj;
336 }
337
338 }