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