|
Java example source code file (MemberUtils.java)
The MemberUtils.java Java example source code/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.lang3.reflect; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.apache.commons.lang3.ClassUtils; /** * Contains common code for working with {@link java.lang.reflect.Method Methods}/{@link java.lang.reflect.Constructor Constructors}, * extracted and refactored from {@link MethodUtils} when it was imported from Commons BeanUtils. * * @since 2.5 */ abstract class MemberUtils { // TODO extract an interface to implement compareParameterSets(...)? private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE; /** Array of primitive number types ordered by "promotability" */ private static final Class<?>[] ORDERED_PRIMITIVE_TYPES = { Byte.TYPE, Short.TYPE, Character.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE }; /** * XXX Default access superclass workaround. * * When a {@code public} class has a default access superclass with {@code public} members, * these members are accessible. Calling them from compiled code works fine. * Unfortunately, on some JVMs, using reflection to invoke these members * seems to (wrongly) prevent access even when the modifier is {@code public}. * Calling {@code setAccessible(true)} solves the problem but will only work from * sufficiently privileged code. Better workarounds would be gratefully * accepted. * @param o the AccessibleObject to set as accessible * @return a boolean indicating whether the accessibility of the object was set to true. */ static boolean setAccessibleWorkaround(final AccessibleObject o) { if (o == null || o.isAccessible()) { return false; } final Member m = (Member) o; if (!o.isAccessible() && Modifier.isPublic(m.getModifiers()) && isPackageAccess(m.getDeclaringClass().getModifiers())) { try { o.setAccessible(true); return true; } catch (final SecurityException e) { // NOPMD // ignore in favor of subsequent IllegalAccessException } } return false; } /** * Returns whether a given set of modifiers implies package access. * @param modifiers to test * @return {@code true} unless {@code package}/{@code protected}/{@code private} modifier detected */ static boolean isPackageAccess(final int modifiers) { return (modifiers & ACCESS_TEST) == 0; } /** * Returns whether a {@link Member} is accessible. * @param m Member to check * @return {@code true} if <code>m is accessible */ static boolean isAccessible(final Member m) { return m != null && Modifier.isPublic(m.getModifiers()) && !m.isSynthetic(); } /** * Compares the relative fitness of two Constructors in terms of how well they * match a set of runtime parameter types, such that a list ordered * by the results of the comparison would return the best match first * (least). * * @param left the "left" Constructor * @param right the "right" Constructor * @param actual the runtime parameter types to match against * {@code left}/{@code right} * @return int consistent with {@code compare} semantics * @since 3.5 */ static int compareConstructorFit(final Constructor<?> left, final Constructor right, final Class[] actual) { return compareParameterTypes(Executable.of(left), Executable.of(right), actual); } /** * Compares the relative fitness of two Methods in terms of how well they * match a set of runtime parameter types, such that a list ordered * by the results of the comparison would return the best match first * (least). * * @param left the "left" Method * @param right the "right" Method * @param actual the runtime parameter types to match against * {@code left}/{@code right} * @return int consistent with {@code compare} semantics * @since 3.5 */ static int compareMethodFit(final Method left, final Method right, final Class<?>[] actual) { return compareParameterTypes(Executable.of(left), Executable.of(right), actual); } /** * Compares the relative fitness of two Executables in terms of how well they * match a set of runtime parameter types, such that a list ordered * by the results of the comparison would return the best match first * (least). * * @param left the "left" Executable * @param right the "right" Executable * @param actual the runtime parameter types to match against * {@code left}/{@code right} * @return int consistent with {@code compare} semantics */ private static int compareParameterTypes(final Executable left, final Executable right, final Class<?>[] actual) { final float leftCost = getTotalTransformationCost(actual, left); final float rightCost = getTotalTransformationCost(actual, right); return leftCost < rightCost ? -1 : rightCost < leftCost ? 1 : 0; } /** * Returns the sum of the object transformation cost for each class in the * source argument list. * @param srcArgs The source arguments * @param destArgs The destination arguments * @param isVarArgs True if the destination arguments are for a varags methods * @return The total transformation cost */ private static float getTotalTransformationCost(final Class<?>[] srcArgs, final Executable executable) { final Class<?>[] destArgs = executable.getParameterTypes(); final boolean isVarArgs = executable.isVarArgs(); // "source" and "destination" are the actual and declared args respectively. float totalCost = 0.0f; final long normalArgsLen = isVarArgs ? destArgs.length-1 : destArgs.length; if (srcArgs.length < normalArgsLen) return Float.MAX_VALUE; for (int i = 0; i < normalArgsLen; i++) { totalCost += getObjectTransformationCost(srcArgs[i], destArgs[i]); } if (isVarArgs) { // When isVarArgs is true, srcArgs and dstArgs may differ in length. // There are two special cases to consider: final boolean noVarArgsPassed = srcArgs.length < destArgs.length; final boolean explicitArrayForVarags = (srcArgs.length == destArgs.length) && srcArgs[srcArgs.length-1].isArray(); final float varArgsCost = 0.001f; Class<?> destClass = destArgs[destArgs.length-1].getComponentType(); if (noVarArgsPassed) { // When no varargs passed, the best match is the most generic matching type, not the most specific. totalCost += getObjectTransformationCost(destClass, Object.class) + varArgsCost; } else if (explicitArrayForVarags) { Class<?> sourceClass = srcArgs[srcArgs.length-1].getComponentType(); totalCost += getObjectTransformationCost(sourceClass, destClass) + varArgsCost; } else { // This is typical varargs case. for (int i = destArgs.length-1; i < srcArgs.length; i++) { Class<?> srcClass = srcArgs[i]; totalCost += getObjectTransformationCost(srcClass, destClass) + varArgsCost; } } } return totalCost; } /** * Gets the number of steps required needed to turn the source class into * the destination class. This represents the number of steps in the object * hierarchy graph. * @param srcClass The source class * @param destClass The destination class * @return The cost of transforming an object */ private static float getObjectTransformationCost(Class<?> srcClass, final Class destClass) { if (destClass.isPrimitive()) { return getPrimitivePromotionCost(srcClass, destClass); } float cost = 0.0f; while (srcClass != null && !destClass.equals(srcClass)) { if (destClass.isInterface() && ClassUtils.isAssignable(srcClass, destClass)) { // slight penalty for interface match. // we still want an exact match to override an interface match, // but // an interface match should override anything where we have to // get a superclass. cost += 0.25f; break; } cost++; srcClass = srcClass.getSuperclass(); } /* * If the destination class is null, we've traveled all the way up to * an Object match. We'll penalize this by adding 1.5 to the cost. */ if (srcClass == null) { cost += 1.5f; } return cost; } /** * Gets the number of steps required to promote a primitive number to another * type. * @param srcClass the (primitive) source class * @param destClass the (primitive) destination class * @return The cost of promoting the primitive */ private static float getPrimitivePromotionCost(final Class<?> srcClass, final Class destClass) { float cost = 0.0f; Class<?> cls = srcClass; if (!cls.isPrimitive()) { // slight unwrapping penalty cost += 0.1f; cls = ClassUtils.wrapperToPrimitive(cls); } for (int i = 0; cls != destClass && i < ORDERED_PRIMITIVE_TYPES.length; i++) { if (cls == ORDERED_PRIMITIVE_TYPES[i]) { cost += 0.1f; if (i < ORDERED_PRIMITIVE_TYPES.length - 1) { cls = ORDERED_PRIMITIVE_TYPES[i + 1]; } } } return cost; } static boolean isMatchingMethod(Method method, Class<?>[] parameterTypes) { return MemberUtils.isMatchingExecutable(Executable.of(method), parameterTypes); } static boolean isMatchingConstructor(Constructor<?> method, Class[] parameterTypes) { return MemberUtils.isMatchingExecutable(Executable.of(method), parameterTypes); } private static boolean isMatchingExecutable(Executable method, Class<?>[] parameterTypes) { final Class<?>[] methodParameterTypes = method.getParameterTypes(); if (method.isVarArgs()) { int i; for (i = 0; i < methodParameterTypes.length - 1 && i < parameterTypes.length; i++) { if (!ClassUtils.isAssignable(parameterTypes[i], methodParameterTypes[i], true)) { return false; } } Class<?> varArgParameterType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType(); for (; i < parameterTypes.length; i++) { if (!ClassUtils.isAssignable(parameterTypes[i], varArgParameterType, true)) { return false; } } return true; } return ClassUtils.isAssignable(parameterTypes, methodParameterTypes, true); } /** * <p> A class providing a subset of the API of java.lang.reflect.Executable in Java 1.8, * providing a common representation for function signatures for Constructors and Methods.</p> */ private static final class Executable { private final Class<?>[] parameterTypes; private final boolean isVarArgs; private static Executable of(Method method) { return new Executable(method); } private static Executable of(Constructor<?> constructor) { return new Executable(constructor); } private Executable(Method method) { parameterTypes = method.getParameterTypes(); isVarArgs = method.isVarArgs(); } private Executable(Constructor<?> constructor) { parameterTypes = constructor.getParameterTypes(); isVarArgs = constructor.isVarArgs(); } public Class<?>[] getParameterTypes() { return parameterTypes; } public boolean isVarArgs() { return isVarArgs; } } } Other Java examples (source code examples)Here is a short list of links related to this Java MemberUtils.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.