com.cinchapi.common.reflect.Reflection.java Source code

Java tutorial

Introduction

Here is the source code for com.cinchapi.common.reflect.Reflection.java

Source

/*
 * Copyright (c) 2013-2015 Cinchapi Inc.
 * 
 * Licensed 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 com.cinchapi.common.reflect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.cinchapi.common.base.AnyObjects;
import com.cinchapi.common.base.AnyStrings;
import com.cinchapi.common.base.Array;
import com.cinchapi.common.base.ArrayBuilder;
import com.cinchapi.common.base.CheckedExceptions;
import com.cinchapi.common.base.TernaryTruth;
import com.cinchapi.common.base.Verify;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

/**
 * A collection of tools for using reflection to access or modify objects.
 * <strong>Use with caution.</strong>
 * <p>
 * <em>This class helps you do some naughty things. Think carefully about
 * whether
 * you should be using reflection in your application (its usage is usually a
 * sign of broken design, but there are some legitimate cases where its
 * necessary).</em>
 * </p>
 * <p>
 * Warning aside, if you're going to do reflection anyway, these functions
 * abstract away a lot of the bolierplate. They allow you to access variables,
 * constructors and methods no matter what visibility they are declared with and
 * no matter how far they are declared in the object hirearchy.
 * </p>
 * <h2>Known Limitations</h2>
 * <p>
 * <ul>
 * <li>Calling methods and constructors that take a mix of primitive types and
 * wrapper types does not work. Methods should be declared to take all of one or
 * the other.</li>
 * </ul>
 * </p>
 * 
 * @author Jeff Nelson
 */
public final class Reflection {

    /**
     * Use reflection to call an instance method on {@code obj} with the
     * specified {@code args}.
     * 
     * @param obj
     * @param methodName
     * @param args
     * @return the result of calling the method
     */
    public static <T> T call(Object obj, String methodName, Object... args) {
        return call(true, obj, methodName, args);
    }

    /**
     * Return a {@link Callable} that can execute
     * {@link #call(Object, String, Object...)} asynchronously.
     * 
     * @param obj the object on which to call the method
     * @param methodName the name of the method to call
     * @param args the method parameters
     * @return a {@link Callable} that can be used for asynchronous execution
     */
    public static <T> Callable<T> callable(final Object obj, final String methodName, final Object... args) {
        return new Callable<T>() {

            @Override
            public T call() throws Exception {
                return Reflection.call(obj, methodName, args);
            }

        };
    }

    /**
     * Call {@code methodName} on the specified {@code obj} with the specified
     * {@code args} if and only if the {@code evaluate} function returns
     * {@code true}.
     * 
     * @param evaluate the {@link Function} that is given the (possibly cached)
     *            {@link Method} instance that corresponds to {@code methodName}
     *            ; use this to evaluate whether the method should be called
     * @param obj the Object on which the method is called
     * @param methodName the name of the method to call
     * @param args the args to pass to the method
     * @return the result of calling the method
     */
    @SuppressWarnings("unchecked")
    public static <T> T callIf(Function<Method, Boolean> evaluate, Object obj, String methodName, Object... args) {
        Method method = getMethod(true, methodName, obj.getClass(), args);
        if (evaluate.apply(method)) {
            try {
                method.setAccessible(true);
                return (T) method.invoke(obj, args);
            } catch (ReflectiveOperationException e) {
                Throwable ex = e;
                if (ex instanceof InvocationTargetException && e.getCause() != null) {
                    ex = ex.getCause();
                } else {
                    ex = Throwables.getRootCause(ex);
                }
                throw CheckedExceptions.wrapAsRuntimeException(ex);
            }
        } else {
            throw new IllegalStateException(
                    "Cannot call " + method + " reflectively because " + "the evaluation function returned false");
        }
    }

    /**
     * Use reflection to call an instance method on {@code obj} with the
     * specified {@code args} if and only if that method is natively accessible
     * according to java language access rules.
     * 
     * @param obj
     * @param methodName
     * @param args
     * @return the result of calling the method
     */
    public static <T> T callIfAccessible(Object obj, String methodName, Object... args) {
        return call(false, obj, methodName, args);
    }

    /**
     * Use reflection to call a static method in {@code clazz} with the
     * specified {@code args}.
     * 
     * @param clazz the {@link Class} instance
     * @param method the method name
     * @param args the args to pass to the method upon invocation
     * @return the result of the method invocation
     */
    public static <T> T callStatic(Class<?> clazz, String method, Object... args) {
        return callStatic(true, clazz, method, args);
    }

    /**
     * Use reflection to call a static method in {@code clazz} with the
     * specified {@code args} if and only if that method is natively accessible
     * according to java language access rules.
     * 
     * @param clazz the {@link Class} instance
     * @param method the method name
     * @param args the args to pass to the method upon invocation
     * @return the result of the method invocation
     */
    public static <T> T callStaticIfAccessible(Class<?> clazz, String method, Object... args) {
        return callStatic(false, clazz, method, args);
    }

    /**
     * Retrieve the value of {@code variable} from the {@code obj}.
     * <p>
     * This is useful in situations when it is necessary to access an instance
     * variable that is not visible (i.e. when hacking the internals of a 3rd
     * party library).
     * </p>
     * 
     * @param variable the name of the variable to retrieve
     * @param obj the object from which to retrieve the value
     * @return the value of the {@code variable} on {@code obj}, if it exists;
     *         otherwise {@code null}
     */
    @Nullable
    @SuppressWarnings("unchecked")
    public static <T> T get(String variable, Object obj) {
        try {
            Field field = getField(variable, obj);
            return (T) field.get(obj);
        } catch (ReflectiveOperationException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    }

    /**
     * Given a {@link Class}, return an array containing all the {@link Field}
     * objects that represent those declared within the class's entire hierarchy
     * after the base {@link Object} class.
     * 
     * @param clazz the {@link Class} to inspect
     * @return the array of declared fields
     */
    public static Field[] getAllDeclaredFields(Class<?> clazz) {
        List<Field> fields = new ArrayList<Field>();
        while (clazz != Object.class) {
            for (Field field : clazz.getDeclaredFields()) {
                if (!field.getName().equalsIgnoreCase("fields0") && !field.isSynthetic()
                        && !Modifier.isStatic(field.getModifiers())) {
                    field.setAccessible(true);
                    fields.add(field);
                }
            }
            clazz = clazz.getSuperclass();
        }
        return fields.toArray(new Field[] {});
    }

    /**
     * Given an object, return an array containing all the {@link Field} objects
     * that represent those declared within {@code obj's} entire class hierarchy
     * after the base {@link Object}.
     * 
     * @param obj the {@link Object} to inspect
     * @return the array of declared fields
     */
    public static Field[] getAllDeclaredFields(Object obj) {
        return getAllDeclaredFields(obj.getClass());
    }

    /**
     * Reflectively get the value of the {@code field} from the provided
     * {@code object} and attempt an automatic type cast.
     * 
     * @param field the {@link Field} object representing the desired variable
     * @param object the object whose value for the {@code field} should be
     *            retrieved
     * @return the value of {@code field} in {@code object} if it exists,
     *         otherwise {@code null}
     */
    @Nullable
    @SuppressWarnings("unchecked")
    public static <T> T getCasted(Field field, Object object) {
        try {
            field.setAccessible(true);
            return (T) field.get(object);
        } catch (ReflectiveOperationException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    }

    /**
     * This is literally just syntactic sugar for {@link Class#forName(String)}
     * that doesn't throw a checked exception.
     * 
     * @param name the name of the class
     * @return the {@link Class} object if can be found
     */
    @SuppressWarnings("unchecked")
    public static <T> Class<T> getClassCasted(String name) {
        try {
            return (Class<T>) Class.forName(name);
        } catch (ClassNotFoundException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    }

    /**
     * Return the closest common ancestor class for all of the input
     * {@code classes}.
     * 
     * @param classes the classes that have a common ancestor
     * @return the closest common ancestor
     */
    public static Class<?> getClosestCommonAncestor(Class<?>... classes) {
        return Iterables.getFirst(getCommonAncestors(classes), Object.class);
    }

    /**
     * Return all the common ancestors for the {@code classes}.
     * 
     * @param classes
     * @return the common ancestors of the specified classes
     */
    public static Set<Class<?>> getCommonAncestors(Class<?>... classes) {
        Verify.thatArgument(classes.length > 0);
        Set<Class<?>> rollingIntersect = Sets.newLinkedHashSet(getClassAncestors(classes[0]));
        for (int i = 1; i < classes.length; i++) {
            rollingIntersect.retainAll(getClassAncestors(classes[i]));
        }
        return AnyObjects.defaultUnless(Collections.singleton(Object.class), rollingIntersect,
                set -> !set.isEmpty());
    }

    /**
     * Return the field with {@code name} that is declared in the class or class
     * hierarchy.
     * 
     * @param name the field name
     * @param clazz the class that contains the field
     * @return the {@link Field} object
     */
    public static Field getDeclaredField(String name, Class<?> clazz) {
        return getField(name, clazz);
    }

    /**
     * Return the field with {@code name} that is declared in the {@code obj}'s
     * class or class hierarchy.
     * 
     * @param name the field name
     * @param obj the object whose class contains the field
     * @return the {@link Field} object
     */
    public static Field getDeclaredField(String name, Object obj) {
        return getField(name, obj);
    }

    /**
     * Return the enum value at position {@code ordinal} for the
     * {@code enumType}.
     * 
     * @param enumType the {@link Enum} class
     * @param ordinal the value position
     * @return the {@link Enum} value
     */
    public static Enum<?> getEnumValue(Class<? extends Enum<?>> enumType, int ordinal) {
        try {
            return enumType.getEnumConstants()[ordinal];
        } catch (IndexOutOfBoundsException e) {
            throw new IllegalArgumentException(
                    AnyStrings.format("No enum value for {} with ordinal {}", enumType, ordinal));
        }
    }

    /**
     * Return the enum value from {@code enumType} with the specified
     * {@code identifier}.
     * 
     * @param enumType the {@link Enum} class
     * @param identifier the value name or ordinal
     * @return the {@link Enum} value
     */
    public static Enum<?> getEnumValue(Class<? extends Enum<?>> enumType, Object identifier) {
        if (identifier instanceof Integer) {
            return getEnumValue(enumType, (int) identifier);
        } else {
            return getEnumValue(enumType, identifier.toString());
        }
    }

    /**
     * Return the enum value from {@code enumType} with the specified
     * {@code name}.
     * 
     * @param enumType the {@link Enum} class
     * @param name the value name
     * @return the {@link Enum} value
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static Enum<?> getEnumValue(Class<? extends Enum<?>> enumType, String name) {
        return Enum.valueOf((Class<? extends Enum>) enumType, name);
    }

    /**
     * Return a {@link Method} instance from {@code clazz} named {@code method}
     * (that takes arguments of {@code paramTypes} respectively)
     * while making a best effort attempt to unbox primitive parameter types
     * 
     * @param clazz the class instance in which the method is contained
     * @param method the name of the method
     * @param paramTypes the types for the respective paramters
     * @return a {@link Method} instance that has been set to be accessible
     */
    public static Method getMethodUnboxed(Class<?> clazz, String method, Class<?>... paramTypes) {
        return getMethod(null, true, method, clazz, paramTypes);
    }

    @Nullable
    @SuppressWarnings("unchecked")
    public static <T> T getStatic(String variable, Class<?> clazz) {
        try {
            Field field = getField(variable, clazz);
            return (T) field.get(null);
        } catch (ReflectiveOperationException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    }

    /**
     * Return a collection containing the type arguments for the provided
     * {@code field}. If there are no type arguments, the collection that is
     * returned is empty.
     * 
     * @param field
     * @return the type arguments
     */
    @Nonnull
    public static Collection<Class<?>> getTypeArguments(Field field) {
        try {
            ParameterizedType parameterized = (ParameterizedType) field.getGenericType();
            Type[] types = parameterized.getActualTypeArguments();
            Set<Class<?>> typeArgs = Sets.newLinkedHashSetWithExpectedSize(types.length);
            for (Type type : types) {
                typeArgs.add((Class<?>) type);
            }
            return typeArgs;
        } catch (ClassCastException e) {
            return ImmutableSet.of();
        }
    }

    /**
     * Return a collection containing the type arguments for the provided
     * {@code field} in {@code clazz}. If there are no type arguments, the
     * collection that is returned is empty.
     * 
     * @param field
     * @param clazz
     * @return the type arguments
     */
    public static Collection<Class<?>> getTypeArguments(String field, Class<?> clazz) {
        return getTypeArguments(getDeclaredField(field, clazz));
    }

    /**
     * Return a collection containing the type arguments for the provided
     * {@code field} of the {@code object}'s class. If there are no type
     * arguments, the collection that is returned is empty.
     * 
     * @param field
     * @param object
     * @return the type arguments
     */
    public static Collection<Class<?>> getTypeArguments(String field, Object object) {
        return getTypeArguments(getDeclaredField(field, object));
    }

    /**
     * Return {@code true} if the {@code method} is callable with the provided
     * {@code params}.
     * 
     * @param method
     * @param params
     * @return {@code true} if the provided {@code params} match the expected
     *         parameter types of the {@code method}
     */
    public static boolean isCallableWith(Method method, Object... params) {
        TernaryTruth callable = isDefinitelyCallableWith(method, params);
        return callable == TernaryTruth.TRUE || callable == TernaryTruth.UNSURE;
    }

    /**
     * Return {@code true} if the {@code method} has an {@link Annotation
     * annotation} of {@code annotationClass} declared in its hierarchy.
     * <p>
     * Technically, annotations on elements other than classes cannot be
     * inherited in Java. However, there are some cases when it is useful to
     * know whether a version of a method, either in a child or super class,
     * does have an annotation, which this method will indicate.
     * </p>
     * <p>
     * A return type of {@code true} doesn't necessarily mean that the
     * {@code method} was directly annotated with an annotation of the specified
     * class. It simply means, that a version of the method was at some point in
     * the hierarchy. If necessary, the caller must do further inspection to
     * retrieve the exact annotation state.
     * </p>
     * 
     * @param method
     * @param annotationClass
     * @return {@code true} if a version of the method in the hierarchy was
     *         annotated
     */
    public static boolean isDeclaredAnnotationPresentInHierarchy(Method method,
            Class<? extends Annotation> annotationClass) {
        if (method.isAnnotationPresent(annotationClass)) {
            return true;
        } else {
            Class<?> clazz = method.getDeclaringClass().getSuperclass();
            if (clazz != null) {
                try {
                    method = getMethod(null, false, method.getName(), clazz, method.getParameterTypes());
                    return isDeclaredAnnotationPresentInHierarchy(method, annotationClass);
                } catch (Exception e) {
                    return false;
                }
            } else {
                return false;
            }
        }
    }

    /**
     * Implementation of {@link ClassLoader#loadClass(String)} that throws an
     * {@link RuntimeException} instead of a checked exception.
     * 
     * @param name
     * @param classLoader
     * @return the loaded class
     */
    public static Class<?> loadClassQuietly(String name, ClassLoader classLoader) {
        try {
            return classLoader.loadClass(name);
        } catch (ClassNotFoundException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    }

    /**
     * Given a {@link Class}, create a new instance by calling the appropriate
     * constructor for the given {@code args}.
     * 
     * @param clazz the type of instance to construct
     * @param args the parameters to pass to the constructor
     * @return the new instance
     */
    @SuppressWarnings("unchecked")
    public static <T> T newInstance(Class<? extends T> clazz, Object... args) {
        try {
            Constructor<? extends T> toCall = null;
            outer: for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
                Class<?>[] paramTypes = constructor.getParameterTypes();
                if (paramTypes == null && args == null) { // Handle no arg
                                                          // constructors
                    toCall = (Constructor<? extends T>) constructor;
                    break;
                } else if (args == null || paramTypes == null || args.length != paramTypes.length) {
                    continue;
                } else {
                    for (int i = 0; i < args.length; ++i) {
                        Object arg = args[i];
                        Class<?> type = paramTypes[i];
                        Class<?> altType = getAltType(type);
                        if (!type.isAssignableFrom(arg.getClass()) && !altType.isAssignableFrom(arg.getClass())) {
                            continue outer;
                        }
                    }
                    toCall = (Constructor<? extends T>) constructor;
                    break;
                }
            }
            if (toCall != null) {
                toCall.setAccessible(true);
                return (T) toCall.newInstance(args);
            } else {
                throw new NoSuchMethodException(
                        "No constructor for " + clazz + " accepts arguments: " + Arrays.toString(args));
            }
        } catch (InvocationTargetException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e.getTargetException());
        } catch (ReflectiveOperationException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    }

    /**
     * Call {@code constructor} with {@code args} and return a new instance of
     * type {@code T}.
     * 
     * @param constructor the {@link Constructor} to use for creation
     * @param args the initialization args to pass to the constructor
     * @return an instance of the class to which the {@code constructor} belongs
     */
    public static <T> T newInstance(Constructor<? extends T> constructor, Object... args) {
        try {
            constructor.setAccessible(true);
            return constructor.newInstance(args);
        } catch (ReflectiveOperationException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    }

    /**
     * Return a new instance of the specified {@code clazz} by calling the
     * appropriate constructor with the specified {@code args}.
     * 
     * @param clazz the fully qualified name of the {@link Class}
     * @param args the args to pass to the constructor
     * @return the new instance
     */
    @SuppressWarnings("unchecked")
    public static <T> T newInstance(String clazz, Object... args) {
        try {
            return (T) newInstance(Class.forName(clazz), args);
        } catch (ReflectiveOperationException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    }

    /**
     * Edit the value of all the variables that correspond to the keys in the
     * {@code data} with their associated values.
     * <p>
     * <strong>NOTE:</strong> This can have grave unintended consequences if you
     * alter the value of a variable after construction. Especially if other
     * parts of the code assume that {@code obj} is immutable, or the
     * {@code variable} is used in a multi threaded context.
     * </p>
     * <p>
     * This method will throw an error if one or more of the keys in the
     * {@code data} map does not correspond to a named variable within the
     * {@code obj}'s class.
     * </p>
     * 
     * @param data a mapping from variable name to value
     * @param obj the object on which to set the data
     */
    public static void set(Map<String, Object> data, Object obj) {
        data.forEach((variable, value) -> {
            set(variable, value, obj);
        });
    }

    /**
     * Edit the value of {@code variable} on {@code obj}.
     * <p>
     * <strong>NOTE:</strong> This can have grave unintended consequences if you
     * alter the value of a variable after construction. Especially if other
     * parts of the code assume that {@code obj} is immutable, or the
     * {@code variable} is used in a multi threaded context.
     * </p>
     * 
     * @param variable the name of the variable to set
     * @param value the value to set
     * @param obj the object on which to set the value
     */
    public static void set(String variable, Object value, Object obj) {
        try {
            Field field = getField(variable, obj);
            field.set(obj, value);
        } catch (ReflectiveOperationException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    }

    /**
     * Use reflection to call an instance method on {@code obj} with the
     * specified {@code args}.
     * 
     * @param setAccessible an indication as to whether the reflective call
     *            should suppress Java language access checks or not
     * @param obj
     * @param methodName
     * @param args
     * @return the result of calling the method
     */
    private static <T> T call(boolean setAccessible, Object obj, String methodName, Object... args) {
        Method method = getMethod(setAccessible, methodName, obj.getClass(), args);
        return invoke(method, obj, args);
    }

    /**
     * Do the work to use reflection to call a static method in {@code clazz}
     * with the specified {@code args} while optionally obeying the native java
     * language access rules.
     * 
     * @param setAccessible a flag that determines whether java language access
     *            rules will be overridden
     * @param clazz the {@link Class} instance
     * @param methodName the method name
     * @param args the args to pass to the method upon invocation
     * @return the result of the method invocation
     */
    private static <T> T callStatic(boolean setAccessible, Class<?> clazz, String methodName, Object... args) {
        Method method = getMethod(setAccessible, methodName, clazz, args);
        return invoke(method, null, args);
    }

    /**
     * Return the boxed version of {@code clazz} if it is a primitive, or the
     * unboxed version if it is a wrapper.
     * 
     * @param clazz the class for which the alt type is returned
     * @return the alt type
     */
    private static Class<?> getAltType(Class<?> clazz) {
        if (clazz.isPrimitive()) {
            if (clazz == int.class) {
                return Integer.class;
            } else if (clazz == long.class) {
                return Long.class;
            } else if (clazz == float.class) {
                return Float.class;
            } else if (clazz == double.class) {
                return Double.class;
            } else if (clazz == short.class) {
                return Short.class;
            } else if (clazz == byte.class) {
                return Byte.class;
            } else if (clazz == char.class) {
                return Character.class;
            } else if (clazz == boolean.class) {
                return Boolean.class;
            } else {
                return clazz;
            }
        } else {
            return unbox(clazz);
        }
    }

    /**
     * Get all the ancestors for {@code clazz} in an ordered set.
     * 
     * @param clazz
     * @return the ancestors of {@code clazz}
     */
    private static Set<Class<?>> getClassAncestors(Class<?> clazz) {
        Preconditions.checkArgument(clazz != null);
        Set<Class<?>> classes = Sets.newLinkedHashSet();
        Set<Class<?>> nextLevel = Sets.newLinkedHashSet();
        nextLevel.add(clazz);
        do {
            classes.addAll(nextLevel);
            Set<Class<?>> thisLevel = Sets.newLinkedHashSet(nextLevel);
            nextLevel.clear();
            for (Class<?> each : thisLevel) {
                Class<?> superClass = each.getSuperclass();
                if (superClass != null && superClass != Object.class) {
                    nextLevel.add(superClass);
                }
                for (Class<?> eachInt : each.getInterfaces()) {
                    nextLevel.add(eachInt);
                }
            }
        } while (!nextLevel.isEmpty());
        return classes;
    }

    /**
     * Return the value of the {@link Field} called {@code name} in
     * {@code clazz} from the specified {@code obj}.
     * 
     * @param name the name of the field
     * @param clazz the {@link Class} in which the field is defined
     * @return the associated {@link Field} object
     */
    private static Field getField(String name, Class<?> clazz) {
        try {
            Field field = null;
            while (clazz != null && field == null) {
                try {
                    field = clazz.getDeclaredField(name);
                } catch (NoSuchFieldException e) { // check the parent to see if
                                                   // the field was defined there
                    clazz = clazz.getSuperclass();
                }
            }
            if (field != null) {
                field.setAccessible(true);
                return field;
            } else {
                throw new NoSuchFieldException("No field name " + name + " exists in the hirearchy of " + clazz);
            }
        } catch (ReflectiveOperationException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    }

    /**
     * Return the {@link Field} object that holds the variable with {@code name}
     * in {@code obj}, if it exists. Otherwise a
     * NoSuchFieldException is thrown.
     * <p>
     * This method will take care of making the field accessible.
     * </p>
     * 
     * @param name the name of the field to get
     * @param obj the object from which to get the field
     * @return the {@link Field} object
     * @throws NoSuchFieldException
     */
    private static Field getField(String name, Object obj) {
        return getField(name, obj.getClass());
    }

    /**
     * Return a set of classes that are considered to be interchangeable with
     * {@code clazz}.
     * 
     * @param clazz
     * @return a set of classes
     */
    private static Set<Class<?>> getInterchangeableClasses(Class<?> clazz) {
        if (clazz == int.class) {
            return Sets.newHashSet(long.class, Long.class, Integer.class);
        } else if (clazz == Integer.class) {
            return Sets.newHashSet(long.class, Long.class, int.class);
        } else if (clazz == long.class) {
            return Sets.newHashSet(int.class, Long.class, Integer.class);
        } else if (clazz == Long.class) {
            return Sets.newHashSet(long.class, int.class, Integer.class);
        } else {
            return Collections.emptySet();
        }
    }

    /**
     * Return the {@link Method} object called {@code name} in {@code clazz}
     * that accepts the specified {@code args} and optionally ignore the native
     * java language access rules.
     * 
     * @param setAccessible a flag that indicates whether the native java
     *            language access rules should be ignored
     * @param name the method name
     * @param clazz the {@link Class} in which the method is defined
     * @param args the parameters defined in the method's signature
     * @return the associated {@link Method} object
     */
    private static Method getMethod(boolean setAccessible, String name, Class<?> clazz, Object... args) {
        Class<?>[] paramTypes = new Class<?>[args.length];
        for (int i = 0; i < paramTypes.length; ++i) {
            Object arg = args[i];
            paramTypes[i] = arg == null ? null : arg.getClass();
        }
        return getMethod(args, setAccessible, name, clazz, paramTypes);
    }

    /**
     * Return the {@link Method} object called {@code name} in {@code clazz}
     * that accepts the specified {@code args} and optionally ignore the native
     * java language access rules.
     * 
     * @param args (optional) args to plug into the params
     * @param setAccessible a flag that indicates whether the native java
     *            language access rules should be ignored
     * @param name the method name
     * @param clazz the {@link Class} in which the method is defined
     * @param paramType the parameters defined in the method's signature
     * @return the associated {@link Method} object
     */
    private static Method getMethod(@Nullable Object[] args, boolean setAccessible, String name, Class<?> clazz,
            Class<?>... paramTypes) {
        List<Method> potential = Lists.newArrayListWithCapacity(1);
        List<Method> deferred = Lists.newArrayListWithCapacity(1);
        try {
            while (clazz != null) {
                for (Method method : Arrays.stream(clazz.getDeclaredMethods())
                        .filter(method -> method.getName().equals(name)).collect(Collectors.toList())) {
                    TernaryTruth callable = isDefinitelyCallableWith(method, paramTypes);
                    if (callable == TernaryTruth.TRUE && method.getParameterCount() == paramTypes.length) {
                        potential.add(method);
                    } else if (callable != TernaryTruth.FALSE) {
                        deferred.add(method);
                    }
                }
                if (potential.isEmpty()) {
                    clazz = clazz.getSuperclass();
                } else {
                    break;
                }
            }
            if (potential.size() == 2) {
                // UTIL-12: Handle a corner case where an overloaded method
                // takes corresponding boxable parameters
                List<Class<?>> paramTypesA = Arrays.stream(potential.get(0).getParameterTypes())
                        .map(Reflection::unbox).collect(Collectors.toList());
                List<Class<?>> paramTypesB = Arrays.stream(potential.get(1).getParameterTypes())
                        .map(Reflection::unbox).collect(Collectors.toList());
                if (paramTypesA.equals(paramTypesB)) {
                    potential.remove(1);
                }
            }
            int matches = potential.size();
            Method method;
            if (matches < 1) {
                if (deferred.size() == 1) {
                    method = deferred.get(0);
                } else {
                    throw new NoSuchMethodException("Could not find method '" + name + "' that is invokable with: "
                            + Arrays.asList(args != null ? args : paramTypes));
                }
            } else if (matches > 1) {
                throw new IllegalArgumentException("Trying to invoke method " + "'" + name + "' with "
                        + Arrays.asList(args != null ? args : paramTypes)
                        + " isn't possible because there are too many null "
                        + "values and it is impossible to decide which " + "method is desired");
            } else {
                method = potential.get(0);
            }
            method.setAccessible(setAccessible);
            return method;
        } catch (ReflectiveOperationException e) {
            throw CheckedExceptions.wrapAsRuntimeException(e);
        }
    }

    /**
     * Invoke {@code method} with {@code args}. If {@code object} is
     * {@code null}, this is a static invocation.
     * 
     * @param method
     * @param object
     * @param args
     * @return the result of the method invocation
     */
    @SuppressWarnings("unchecked")
    private static <T> T invoke(Method method, @Nullable Object object, Object... args) {
        try {
            int count;
            // @formatter:off
            if ((count = method.getParameterCount()) > 0 // its possible for method to have varags
                    && (args.length >= count - 1) // the number of arguments provided is at least equal to the number of non vararg parameters 
                    && (method.getParameterTypes()[count - 1].isArray() // the last paramter expected is an array type
                            && (args.length == 0 || !args[args.length - 1] // no args were provided OR the last arg provided is NOT an array (meaning its not a vararg invocation literal)
                                    .getClass().isArray()))) {
                // @formatter:on
                // First, check to see if the last parameter type is a vararg
                // (e.g. array) and wrap the dangling args accordingly.
                ArrayBuilder<Object> _args = ArrayBuilder.builder();
                int i = 0;
                for (; i < count - 1; ++i) {
                    _args.add(args[i]);
                }
                ArrayBuilder<Object> varargs = ArrayBuilder.builder();
                for (; i < args.length; ++i) {
                    varargs.add(args[i]);
                }
                _args.add((Object) (varargs.length() > 0 ? varargs.build()
                        : java.lang.reflect.Array
                                .newInstance(method.getParameterTypes()[count - 1].getComponentType(), 0)));
                args = _args.build();
            }
            return (T) method.invoke(object, args);
        } catch (ReflectiveOperationException e) {
            Throwable ex = e;
            if (ex instanceof InvocationTargetException && e.getCause() != null) {
                ex = ex.getCause();
            } else {
                ex = Throwables.getRootCause(ex);
            }
            throw CheckedExceptions.wrapAsRuntimeException(ex);
        }
    }

    /**
     * Return a {@link TernaryTruth} value that indicates whether the
     * {@code method} is definitely callable with the provided
     * {@code paramTypes}.
     * <p>
     * This function is used to determine if the signature of the {@code method}
     * contains specific parameters types (e.g. not the {@link Object.class}
     * type}. If any of the parameters types are super generic, this method will
     * return {@link TernaryTruth#UNSURE} instead of {@link TernaryTruth#TRUE}
     * if all other factors indicate that the method is callable with the param
     * types.
     * </p>
     * 
     * @param method
     * @param paramTypes
     * @return a ternary truth value that indicates the level of certainty that
     *         the method is callable with the provided param types.
     */
    private static TernaryTruth isDefinitelyCallableWith(Method method, Class<?>... paramTypes) {
        TernaryTruth callable = TernaryTruth.TRUE;
        Class<?>[] expectedParamTypes = method.getParameterTypes();
        if (paramTypes.length == expectedParamTypes.length) {
            for (int i = 0; i < paramTypes.length; ++i) {
                Class<?> actual = paramTypes[i];
                if (actual != null) {
                    Class<?> expected = expectedParamTypes[i];
                    if (expected == actual || expected == unbox(actual)
                            || (expected != Object.class && expected.isAssignableFrom(actual))
                            || getInterchangeableClasses(actual).contains(expected)) {
                        continue;
                    } else if (expected == Object.class) {
                        // All value types inherit from Object
                        callable = TernaryTruth.UNSURE;
                        continue;
                    } else {
                        callable = TernaryTruth.FALSE;
                        break;
                    }
                } else {
                    // A null value can be assigned to any object type.
                    continue;
                }
            }
        } else {
            callable = TernaryTruth.FALSE;
        }
        if ((callable != TernaryTruth.TRUE && callable != TernaryTruth.UNSURE) && expectedParamTypes.length > 0
                && expectedParamTypes[expectedParamTypes.length - 1].isArray()
                && (paramTypes.length >= expectedParamTypes.length - 1)) {
            Class<?> varArgType = expectedParamTypes[expectedParamTypes.length - 1].getComponentType();
            // Check for the corner case where the method has a varargs
            // parameter. If so, see if all the dangling parameters fit in with
            // the varargs
            if (paramTypes.length == expectedParamTypes.length - 1) {
                // Handle corner case where no args are provided for a varargs
                // parameter
                callable = isDefinitelyCallableWith(method, ArrayBuilder.<Class<?>>builder().add(paramTypes)
                        .add(java.lang.reflect.Array.newInstance(varArgType, 0).getClass()).build());
            } else {
                for (int i = expectedParamTypes.length - 1; i < paramTypes.length; ++i) {
                    Class<?> paramType = paramTypes[i];
                    if (paramType == varArgType) {
                        callable = TernaryTruth.TRUE;
                    } else {
                        callable = TernaryTruth.FALSE;
                        break;
                    }
                }
            }

        }
        return callable;
    }

    /**
     * Return a {@link TernaryTruth} value that indicates whether the
     * {@code method} is definitely callable with the provided
     * {@code paramTypes}.
     * <p>
     * This function is used to determine if the signature of the {@code method}
     * contains specific parameters types (e.g. not the {@link Object.class}
     * type}. If any of the parameters types are super generic, this method will
     * return {@link TernaryTruth#UNSURE} instead of {@link TernaryTruth#TRUE}
     * if all other factors indicate that the method is callable with the param
     * types.
     * </p>
     * 
     * @param method
     * @param paramTypes
     * @return a ternary truth value that indicates the level of certainty that
     *         the method is callable with the provided param types.
     */
    private static TernaryTruth isDefinitelyCallableWith(Method method, Object... params) {
        return isDefinitelyCallableWith(method, Arrays.stream(params).map(Object::getClass)
                .collect(Collectors.toList()).toArray(Array.containing()));
    }

    /**
     * Return the unboxed version of the input {@code clazz}. This is usually
     * a class that represents a primitive for an autoboxed wrapper class.
     * Otherwise, the input {@code clazz} is returned.
     * 
     * @param clazz the {@link Class} to unbox
     * @return the unboxed class
     */
    private static Class<?> unbox(Class<?> clazz) {
        if (clazz == Integer.class) {
            return int.class;
        } else if (clazz == Long.class) {
            return long.class;
        } else if (clazz == Byte.class) {
            return byte.class;
        } else if (clazz == Short.class) {
            return short.class;
        } else if (clazz == Float.class) {
            return float.class;
        } else if (clazz == Double.class) {
            return double.class;
        } else if (clazz == Boolean.class) {
            return boolean.class;
        } else if (clazz == Character.class) {
            return char.class;
        } else {
            return clazz;
        }
    }

    private Reflection() {
        /* noinit */}

}