1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 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 * Contains common code for working with {@link java.lang.reflect.Method Methods}/{@link java.lang.reflect.Constructor Constructors}, 29 * extracted and refactored from {@link MethodUtils} when it was imported from Commons BeanUtils. 30 * 31 * @since 2.5 32 */ 33 final class MemberUtils { 34 // TODO extract an interface to implement compareParameterSets(...)? 35 36 private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE; 37 38 /** Array of primitive number types ordered by "promotability" */ 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 * Default access superclass workaround. 44 * 45 * When a {@code public} class has a default access superclass with {@code public} members, 46 * these members are accessible. Calling them from compiled code works fine. 47 * Unfortunately, on some JVMs, using reflection to invoke these members 48 * seems to (wrongly) prevent access even when the modifier is {@code public}. 49 * Calling {@code setAccessible(true)} solves the problem but will only work from 50 * sufficiently privileged code. Better workarounds would be gratefully 51 * accepted. 52 * @param obj the AccessibleObject to set as accessible 53 * @return a boolean indicating whether the accessibility of the object was set to true. 54 */ setAccessibleWorkaround(final T obj)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 // ignore in favor of subsequent IllegalAccessException 66 } 67 } 68 return obj; 69 } 70 71 /** 72 * Tests whether a given set of modifiers implies package access. 73 * @param modifiers to test 74 * @return {@code true} unless {@code package}/{@code protected}/{@code private} modifier detected 75 */ isPackageAccess(final int modifiers)76 static boolean isPackageAccess(final int modifiers) { 77 return (modifiers & ACCESS_TEST) == 0; 78 } 79 80 /** 81 * Tests whether a {@link Member} is public. 82 * @param member Member to test 83 * @return {@code true} if {@code m} is public 84 */ isPublic(final Member member)85 static boolean isPublic(final Member member) { 86 return member != null && Modifier.isPublic(member.getModifiers()); 87 } 88 89 /** 90 * Tests whether a {@link Member} is static. 91 * @param member Member to test 92 * @return {@code true} if {@code m} is static 93 */ isStatic(final Member member)94 static boolean isStatic(final Member member) { 95 return member != null && Modifier.isStatic(member.getModifiers()); 96 } 97 98 /** 99 * Tests whether a {@link Member} is accessible. 100 * @param member Member to test 101 * @return {@code true} if {@code m} is accessible 102 */ isAccessible(final Member member)103 static boolean isAccessible(final Member member) { 104 return isPublic(member) && !member.isSynthetic(); 105 } 106 107 /** 108 * Compares the relative fitness of two Constructors in terms of how well they 109 * match a set of runtime parameter types, such that a list ordered 110 * by the results of the comparison would return the best match first 111 * (least). 112 * 113 * @param left the "left" Constructor 114 * @param right the "right" Constructor 115 * @param actual the runtime parameter types to match against 116 * {@code left}/{@code right} 117 * @return int consistent with {@code compare} semantics 118 * @since 3.5 119 */ compareConstructorFit(final Constructor<?> left, final Constructor<?> right, final Class<?>[] actual)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 * Compares the relative fitness of two Methods in terms of how well they 126 * match a set of runtime parameter types, such that a list ordered 127 * by the results of the comparison would return the best match first 128 * (least). 129 * 130 * @param left the "left" Method 131 * @param right the "right" Method 132 * @param actual the runtime parameter types to match against 133 * {@code left}/{@code right} 134 * @return int consistent with {@code compare} semantics 135 * @since 3.5 136 */ compareMethodFit(final Method left, final Method right, final Class<?>[] actual)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 * Compares the relative fitness of two Executables in terms of how well they 143 * match a set of runtime parameter types, such that a list ordered 144 * by the results of the comparison would return the best match first 145 * (least). 146 * 147 * @param left the "left" Executable 148 * @param right the "right" Executable 149 * @param actual the runtime parameter types to match against 150 * {@code left}/{@code right} 151 * @return int consistent with {@code compare} semantics 152 */ compareParameterTypes(final Executable left, final Executable right, final Class<?>[] actual)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 * Returns the sum of the object transformation cost for each class in the 161 * source argument list. 162 * @param srcArgs The source arguments 163 * @param executable The executable to calculate transformation costs for 164 * @return The total transformation cost 165 */ getTotalTransformationCost(final Class<?>[] srcArgs, final Executable executable)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 // "source" and "destination" are the actual and declared args respectively. 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 // When isVarArgs is true, srcArgs and dstArgs may differ in length. 181 // There are two special cases to consider: 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 // When no varargs passed, the best match is the most generic matching type, not the most specific. 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 // This is typical varargs case. 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 * Gets the number of steps needed to turn the source class into 207 * the destination class. This represents the number of steps in the object 208 * hierarchy graph. 209 * @param srcClass The source class 210 * @param destClass The destination class 211 * @return The cost of transforming an object 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 // slight penalty for interface match. 221 // we still want an exact match to override an interface match, 222 // but 223 // an interface match should override anything where we have to 224 // get a superclass. 225 cost += 0.25f; 226 break; 227 } 228 cost++; 229 srcClass = srcClass.getSuperclass(); 230 } 231 /* 232 * If the destination class is null, we've traveled all the way up to 233 * an Object match. We'll penalize this by adding 1.5 to the cost. 234 */ 235 if (srcClass == null) { 236 cost += 1.5f; 237 } 238 return cost; 239 } 240 241 /** 242 * Gets the number of steps required to promote a primitive number to another 243 * type. 244 * @param srcClass the (primitive) source class 245 * @param destClass the (primitive) destination class 246 * @return The cost of promoting the primitive 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 // slight unwrapping penalty 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 * A class providing a subset of the API of java.lang.reflect.Executable in Java 1.8, 305 * providing a common representation for function signatures for Constructors and Methods. 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 } 339