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