All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.hypersistence.utils.common.ReflectionUtils Maven / Gradle / Ivy

There is a newer version: 3.9.0
Show newest version
package io.hypersistence.utils.common;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

/**
 * ReflectionUtils - Reflection utilities holder.
 *
 * @author Vlad Mihalcea
 */
public final class ReflectionUtils {

    private static final String GETTER_PREFIX = "get";

    private static final String SETTER_PREFIX = "set";

    /**
     * Prevent any instantiation.
     */
    private ReflectionUtils() {
        throw new UnsupportedOperationException("The " + getClass() + " is not instantiable!");
    }

    /**
     * Instantiate a new {@link Object} of the provided type.
     *
     * @param className The fully-qualified Java class name of the {@link Object} to instantiate
     * @param        class type
     * @return new Java {@link Object} of the provided type
     */
    public static  T newInstance(String className) {
        Class clazz = getClass(className);
        return newInstance(clazz);
    }

    /**
     * Instantiate a new {@link Object} of the provided type.
     *
     * @param clazz The Java {@link Class} of the {@link Object} to instantiate
     * @param    class type
     * @return new Java {@link Object} of the provided type
     */
    @SuppressWarnings("unchecked")
    public static  T newInstance(Class clazz) {
        try {
            return (T) clazz.newInstance();
        } catch (InstantiationException e) {
            throw handleException(e);
        } catch (IllegalAccessException e) {
            throw handleException(e);
        }
    }

    /**
     * Instantiate a new {@link Object} of the provided type.
     *
     * @param clazz     The Java {@link Class} of the {@link Object} to instantiate
     * @param args      The arguments that need to be passed to the constructor
     * @param argsTypes The argument types that need to be passed to the constructor
     * @param        class type
     * @return new Java {@link Object} of the provided type
     */
    @SuppressWarnings("unchecked")
    public static  T newInstance(Class clazz, Object[] args, Class[] argsTypes) {
        try {
            Constructor constructor = clazz.getDeclaredConstructor(argsTypes);
            constructor.setAccessible(true);
            return constructor.newInstance(args);
        } catch (InstantiationException e) {
            throw handleException(e);
        } catch (IllegalAccessException e) {
            throw handleException(e);
        } catch (NoSuchMethodException e) {
            throw handleException(e);
        } catch (InvocationTargetException e) {
            throw handleException(e);
        }
    }

    /**
     * Get the {@link Field} with the given name belonging to the provided Java {@link Class}.
     *
     * @param targetClass the provided Java {@link Class} the field belongs to
     * @param fieldName   the {@link Field} name
     * @return the {@link Field} matching the given name
     */
    public static Field getField(Class targetClass, String fieldName) {
        Field field = null;

        try {
            field = targetClass.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            try {
                field = targetClass.getField(fieldName);
            } catch (NoSuchFieldException ignore) {
            }

            if (!targetClass.getSuperclass().equals(Object.class)) {
                return getField(targetClass.getSuperclass(), fieldName);
            } else {
                throw handleException(e);
            }
        } finally {
            if (field != null) {
                field.setAccessible(true);
            }
        }

        return field;
    }

    /**
     * Get the {@link Field} with the given name belonging to the provided Java {@link Class} or {@code null}
     * if no {@link Field} was found.
     *
     * @param targetClass the provided Java {@link Class} the field belongs to
     * @param fieldName   the {@link Field} name
     * @return the {@link Field} matching the given name or {@code null}
     */
    public static Field getFieldOrNull(Class targetClass, String fieldName) {
        try {
            return getField(targetClass, fieldName);
        } catch (IllegalArgumentException e) {
            return null;
        }
    }

    /**
     * Get the the value of {@link Field} with the given name belonging to the provided Java {@link Class} or {@code null}
     * if no {@link Field} was found.
     *
     * @param targetClass the provided Java {@link Class} the field belongs to
     * @param fieldName   the {@link Field} name
     * @return the value of {@link Field} matching the given name or {@code null}
     */
    public static  T getFieldValueOrNull(Class targetClass, String fieldName) {
        try {
            Field field = getField(targetClass, fieldName);
            T returnValue = (T) field.get(null);
            return returnValue;
        } catch (IllegalArgumentException | IllegalAccessException e) {
            return null;
        }
    }

    /**
     * Get the value of the field matching the given name and belonging to target {@link Object}.
     *
     * @param target    target {@link Object} whose field we are retrieving the value from
     * @param fieldName field name
     * @param        field type
     * @return field value
     */
    public static  T getFieldValue(Object target, String fieldName) {
        try {
            Field field = getField(target.getClass(), fieldName);
            @SuppressWarnings("unchecked")
            T returnValue = (T) field.get(target);
            return returnValue;
        } catch (IllegalAccessException e) {
            throw handleException(e);
        }
    }

    /**
     * Get the value of the field matching the given name and belonging to target {@link Object} or {@code null}
     * if no {@link Field} was found..
     *
     * @param target    target {@link Object} whose field we are retrieving the value from
     * @param fieldName field name
     * @param        field type
     * @return field value matching the given name or {@code null}
     */
    public static  T getFieldValueOrNull(Object target, String fieldName) {
        try {
            Field field = getField(target.getClass(), fieldName);
            @SuppressWarnings("unchecked")
            T returnValue = (T) field.get(target);
            return returnValue;
        } catch (IllegalAccessException e) {
            return null;
        }
    }

    /**
     * Set the value of the field matching the given name and belonging to target {@link Object}.
     *
     * @param target    target object
     * @param fieldName field name
     * @param value     field value
     */
    public static void setFieldValue(Object target, String fieldName, Object value) {
        try {
            Field field = getField(target.getClass(), fieldName);
            field.set(target, value);
        } catch (IllegalAccessException e) {
            throw handleException(e);
        }
    }

    /**
     * Get the {@link Method} with the given signature (name and parameter types) belonging to
     * the provided Java {@link Object}.
     *
     * @param target         target {@link Object}
     * @param methodName     method name
     * @param parameterTypes method parameter types
     * @return return {@link Method} matching the provided signature
     */
    public static Method getMethod(Object target, String methodName, Class... parameterTypes) {
        return getMethod(target.getClass(), methodName, parameterTypes);
    }

    /**
     * Get the {@link Method} with the given signature (name and parameter types) belonging to
     * the provided Java {@link Object} or {@code null} if no {@link Method} was found.
     *
     * @param target         target {@link Object}
     * @param methodName     method name
     * @param parameterTypes method parameter types
     * @return return {@link Method} matching the provided signature or {@code null}
     */
    public static Method getMethodOrNull(Object target, String methodName, Class... parameterTypes) {
        try {
            return getMethod(target.getClass(), methodName, parameterTypes);
        } catch (RuntimeException e) {
            return null;
        }
    }

    /**
     * Get the {@link Method} with the given signature (name and parameter types) belonging to
     * the provided Java {@link Class}.
     *
     * @param targetClass    target {@link Class}
     * @param methodName     method name
     * @param parameterTypes method parameter types
     * @return the {@link Method} matching the provided signature
     */
    @SuppressWarnings("unchecked")
    public static Method getMethod(Class targetClass, String methodName, Class... parameterTypes) {
        try {
            return targetClass.getDeclaredMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e) {
            try {
                return targetClass.getMethod(methodName, parameterTypes);
            } catch (NoSuchMethodException ignore) {
            }

            if (!targetClass.getSuperclass().equals(Object.class)) {
                return getMethod(targetClass.getSuperclass(), methodName, parameterTypes);
            } else {
                throw handleException(e);
            }
        }
    }

    /**
     * Get the {@link Method} with the given signature (name and parameter types) belonging to
     * the provided Java {@link Object} or {@code null} if no {@link Method} was found.
     *
     * @param targetClass    target {@link Class}
     * @param methodName     method name
     * @param parameterTypes method parameter types
     * @return return {@link Method} matching the provided signature or {@code null}
     */
    public static Method getMethodOrNull(Class targetClass, String methodName, Class... parameterTypes) {
        try {
            return getMethod(targetClass, methodName, parameterTypes);
        } catch (RuntimeException e) {
            return null;
        }
    }

    /**
     * Get the {@link Method} with the given signature (name and parameter types) belonging to
     * the provided Java {@link Class}, excluding inherited ones, or {@code null} if no {@link Method} was found.
     *
     * @param targetClass    target {@link Class}
     * @param methodName     method name
     * @param parameterTypes method parameter types
     * @return return {@link Method} matching the provided signature or {@code null}
     */
    public static Method getDeclaredMethodOrNull(Class targetClass, String methodName, Class... parameterTypes) {
        try {
            return targetClass.getDeclaredMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

    /**
     * Check if the provided Java {@link Class} contains a method matching
     * the given signature (name and parameter types).
     *
     * @param targetClass    target {@link Class}
     * @param methodName     method name
     * @param parameterTypes method parameter types
     * @return the provided Java {@link Class} contains a method with the given signature
     */
    public static boolean hasMethod(Class targetClass, String methodName, Class... parameterTypes) {
        try {
            targetClass.getMethod(methodName, parameterTypes);
            return true;
        } catch (NoSuchMethodException e) {
            return false;
        }
    }

    /**
     * Get the property setter {@link Method} with the given signature (name and parameter types)
     * belonging to the provided Java {@link Object}.
     *
     * @param target        target {@link Object}
     * @param propertyName  property name
     * @param parameterType setter property type
     * @return the setter {@link Method} matching the provided signature
     */
    public static Method getSetter(Object target, String propertyName, Class parameterType) {
        String setterMethodName = SETTER_PREFIX + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
        Method setter = getMethod(target, setterMethodName, parameterType);
        setter.setAccessible(true);
        return setter;
    }

    /**
     * Get the property setter {@link Method} with the given signature (name and parameter types)
     * belonging to the provided Java {@link Object} or {@code null} if no setter
     * was found matching the provided name.
     *
     * @param target        target {@link Object}
     * @param propertyName  property name
     * @param parameterType setter property type
     * @return the setter {@link Method} matching the provided signature or {@code null}
     */
    public static Method getSetterOrNull(Object target, String propertyName, Class parameterType) {
        try {
            return getSetter(target, propertyName, parameterType);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Get the property getter {@link Method} with the given name belonging to
     * the provided Java {@link Object}.
     *
     * @param target       target {@link Object}
     * @param propertyName property name
     * @return the getter {@link Method} matching the provided name
     */
    public static Method getGetter(Object target, String propertyName) {
        String getterMethodName = GETTER_PREFIX + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
        Method getter = getMethod(target, getterMethodName);
        getter.setAccessible(true);
        return getter;
    }

    /**
     * Invoke the provided {@link Method} on the given Java {@link Object}.
     *
     * @param target     target {@link Object} whose method we are invoking
     * @param method     method to invoke
     * @param parameters parameters passed to the method call
     * @param         return value object type
     * @return the value return by the {@link Method} invocation
     */
    public static  T invokeMethod(Object target, Method method, Object... parameters) {
        try {
            method.setAccessible(true);
            @SuppressWarnings("unchecked")
            T returnValue = (T) method.invoke(target, parameters);
            return returnValue;
        } catch (InvocationTargetException e) {
            throw handleException(e);
        } catch (IllegalAccessException e) {
            throw handleException(e);
        }
    }

    /**
     * Invoke the method with the provided signature (name and parameter types)
     * on the given Java {@link Object}.
     *
     * @param target     target {@link Object} whose method we are invoking
     * @param methodName method name to invoke
     * @param parameters parameters passed to the method call
     * @param         return value object type
     * @return the value return by the method invocation
     */
    public static  T invokeMethod(Object target, String methodName, Object... parameters) {
        try {
            Class[] parameterClasses = new Class[parameters.length];

            for (int i = 0; i < parameters.length; i++) {
                parameterClasses[i] = parameters[i].getClass();
            }

            Method method = getMethod(target, methodName, parameterClasses);
            method.setAccessible(true);
            @SuppressWarnings("unchecked")
            T returnValue = (T) method.invoke(target, parameters);
            return returnValue;
        } catch (InvocationTargetException e) {
            throw handleException(e);
        } catch (IllegalAccessException e) {
            throw handleException(e);
        }
    }

    /**
     * Invoke the property getter with the provided name on the given Java {@link Object}.
     *
     * @param target       target {@link Object} whose property getter we are invoking
     * @param propertyName property name whose getter we are invoking
     * @param           return value object type
     * @return the value return by the getter invocation
     */
    public static  T invokeGetter(Object target, String propertyName) {
        Method setter = getGetter(target, propertyName);
        try {
            return (T) setter.invoke(target);
        } catch (IllegalAccessException e) {
            throw handleException(e);
        } catch (InvocationTargetException e) {
            throw handleException(e);
        }
    }

    /**
     * Invoke the property setter with the provided signature (name and parameter types)
     * on the given Java {@link Object}.
     *
     * @param target       target {@link Object} whose property setter we are invoking
     * @param propertyName property name whose setter we are invoking
     * @param parameter    parameter passed to the setter call
     */
    public static void invokeSetter(Object target, String propertyName, Object parameter) {
        Method setter = getSetter(target, propertyName, parameter.getClass());
        try {
            setter.invoke(target, parameter);
        } catch (IllegalAccessException e) {
            throw handleException(e);
        } catch (InvocationTargetException e) {
            throw handleException(e);
        }
    }

    /**
     * Invoke the {@link boolean} property setter with the provided name
     * on the given Java {@link Object}.
     *
     * @param target       target {@link Object} whose property setter we are invoking
     * @param propertyName property name whose setter we are invoking
     * @param parameter    {@link boolean} parameter passed to the setter call
     */
    public static void invokeSetter(Object target, String propertyName, boolean parameter) {
        Method setter = getSetter(target, propertyName, boolean.class);
        try {
            setter.invoke(target, parameter);
        } catch (IllegalAccessException e) {
            throw handleException(e);
        } catch (InvocationTargetException e) {
            throw handleException(e);
        }
    }

    /**
     * Invoke the {@link int} property setter with the provided name
     * on the given Java {@link Object}.
     *
     * @param target       target {@link Object} whose property setter we are invoking
     * @param propertyName property name whose setter we are invoking
     * @param parameter    {@link int} parameter passed to the setter call
     */
    public static void invokeSetter(Object target, String propertyName, int parameter) {
        Method setter = getSetter(target, propertyName, int.class);
        try {
            setter.invoke(target, parameter);
        } catch (IllegalAccessException e) {
            throw handleException(e);
        } catch (InvocationTargetException e) {
            throw handleException(e);
        }
    }

    /**
     * Invoke the {@code static} {@link Method} with the provided parameters.
     *
     * @param method     target {@code static} {@link Method} to invoke
     * @param parameters parameters passed to the method call
     * @param         return value object type
     * @return the value return by the method invocation
     */
    public static  T invokeStaticMethod(Method method, Object... parameters) {
        try {
            method.setAccessible(true);
            @SuppressWarnings("unchecked")
            T returnValue = (T) method.invoke(null, parameters);
            return returnValue;
        } catch (InvocationTargetException e) {
            throw handleException(e);
        } catch (IllegalAccessException e) {
            throw handleException(e);
        }
    }

    /**
     * Get the Java {@link Class} with the given fully-qualified name.
     *
     * @param className the Java {@link Class} name to be retrieved
     * @param        {@link Class} type
     * @return the Java {@link Class} object
     */
    @SuppressWarnings("unchecked")
    public static  Class getClass(String className) {
        try {
            return (Class) Class.forName(className, false, Thread.currentThread().getContextClassLoader());
        } catch (ClassNotFoundException e) {
            throw handleException(e);
        }
    }

    /**
     * Get the {@link URI} resource with the given fully-qualified name.
     *
     * @param name the {@link URI} resource to be retrieved
     * @return the Java {@link Class} object
     */
    public static URL getResource(String name) {
        return Thread.currentThread().getContextClassLoader().getResource(name);
    }

    /**
     * Get the Java {@link Class} with the given fully-qualified name or or {@code null}
     * if no {@link Class} was found matching the provided name.
     *
     * @param className the Java {@link Class} name to be retrieved
     * @param        {@link Class} type
     * @return the Java {@link Class} object or {@code null}
     */
    @SuppressWarnings("unchecked")
    public static  Class getClassOrNull(String className) {
        try {
            return (Class) getClass(className);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Get the Java Wrapper {@link Class} associated to the given primitive type.
     *
     * @param clazz primitive class
     * @return the Java Wrapper {@link Class}
     */
    public static Class getWrapperClass(Class clazz) {
        if (!clazz.isPrimitive())
            return clazz;

        if (clazz == Integer.TYPE)
            return Integer.class;
        if (clazz == Long.TYPE)
            return Long.class;
        if (clazz == Boolean.TYPE)
            return Boolean.class;
        if (clazz == Byte.TYPE)
            return Byte.class;
        if (clazz == Character.TYPE)
            return Character.class;
        if (clazz == Float.TYPE)
            return Float.class;
        if (clazz == Double.TYPE)
            return Double.class;
        if (clazz == Short.TYPE)
            return Short.class;
        if (clazz == Void.TYPE)
            return Void.class;

        return clazz;
    }

    /**
     * Get the first super class matching the provided package name.
     *
     * @param clazz       Java class
     * @param packageName package name
     * @param          class generic type
     * @return the first super class matching the provided package name or {@code null}.
     */
    public static  Class getFirstSuperClassFromPackage(Class clazz, String packageName) {
        if (clazz.getPackage().getName().equals(packageName)) {
            return clazz;
        } else {
            Class superClass = clazz.getSuperclass();
            return (superClass == null || superClass.equals(Object.class)) ?
                null :
                (Class) getFirstSuperClassFromPackage(superClass, packageName);
        }
    }

    /**
     * Get the generic types of a given Class.
     *
     * @param parameterizedType parameterized Type
     * @return generic types for the given Class.
     */
    public static Set getGenericTypes(ParameterizedType parameterizedType) {
        Set genericTypes = new LinkedHashSet<>();
        for (Type genericType : parameterizedType.getActualTypeArguments()) {
            if (genericType instanceof Class) {
                genericTypes.add((Class) genericType);
            }
        }
        return genericTypes;
    }

    /**
     * Get class package name.
     *
     * @param className Class name.
     * @return class package name
     */
    public static String getClassPackageName(String className) {
        try {
            Class clazz = getClassOrNull(className);
            if (clazz == null) {
                return null;
            }
            Package classPackage = clazz.getPackage();
            return classPackage != null ? classPackage.getName() : null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * Get the {@link Member} with the given name belonging to the provided Java {@link Class} or {@code null}
     * if no {@link Member} was found.
     *
     * @param targetClass the provided Java {@link Class} the field or method belongs to
     * @param memberName  the {@link Field} or {@link Method} name
     * @return the {@link Field} or {@link Method} matching the given name or {@code null}
     */
    public static Member getMemberOrNull(Class targetClass, String memberName) {
        Field field = getFieldOrNull(targetClass, memberName);
        return (field != null) ? field : getMethodOrNull(targetClass, memberName);
    }

    /**
     * Get the generic {@link Type} of the {@link Member} with the given name belonging to the provided Java {@link Class} or {@code null}
     * if no {@link Member} was found.
     *
     * @param targetClass the provided Java {@link Class} the field or method belongs to
     * @param memberName  the {@link Field} or {@link Method} name
     * @return the generic {@link Type} of the {@link Field} or {@link Method} matching the given name or {@code null}
     */
    public static Type getMemberGenericTypeOrNull(Class targetClass, String memberName) {
        Field field = getFieldOrNull(targetClass, memberName);
        return (field != null) ? field.getGenericType() : getMethodOrNull(targetClass, memberName).getGenericReturnType();
    }

    /**
     * Get classes by their package name
     *
     * @param packageName package name
     * @return classes
     */
    public static List getClassesByPackage(String packageName) {
        List classes = new ArrayList<>();

        try {
            final String packagePath = packageName.replace('.', File.separatorChar);
            final String javaClassExtension = ".class";
            try (Stream allPaths = Files.walk(Paths.get(getResource(packagePath).toURI()))) {
                allPaths.filter(Files::isRegularFile).forEach(file -> {
                    final String path = file.toString().replace(File.separatorChar, '.');
                    final String name = path.substring(
                        path.indexOf(packageName),
                        path.length() - javaClassExtension.length()
                    );
                    classes.add(ReflectionUtils.getClass(name));
                });
            }
        } catch (URISyntaxException | IOException e) {
            throw new IllegalArgumentException(e);
        }

        return classes;
    }

    /**
     * Handle the {@link NoSuchFieldException} by rethrowing it as an {@link IllegalArgumentException}.
     *
     * @param e the original {@link NoSuchFieldException}
     * @return the {@link IllegalArgumentException} wrapping exception
     */
    private static IllegalArgumentException handleException(NoSuchFieldException e) {
        return new IllegalArgumentException(e);
    }

    /**
     * Handle the {@link NoSuchMethodException} by rethrowing it as an {@link IllegalArgumentException}.
     *
     * @param e the original {@link NoSuchMethodException}
     * @return the {@link IllegalArgumentException} wrapping exception
     */
    private static IllegalArgumentException handleException(NoSuchMethodException e) {
        return new IllegalArgumentException(e);
    }

    /**
     * Handle the {@link IllegalAccessException} by rethrowing it as an {@link IllegalArgumentException}.
     *
     * @param e the original {@link IllegalAccessException}
     * @return the {@link IllegalArgumentException} wrapping exception
     */
    private static IllegalArgumentException handleException(IllegalAccessException e) {
        return new IllegalArgumentException(e);
    }

    /**
     * Handle the {@link InvocationTargetException} by rethrowing it as an {@link IllegalArgumentException}.
     *
     * @param e the original {@link InvocationTargetException}
     * @return the {@link IllegalArgumentException} wrapping exception
     */
    private static IllegalArgumentException handleException(InvocationTargetException e) {
        return new IllegalArgumentException(e);
    }

    /**
     * Handle the {@link ClassNotFoundException} by rethrowing it as an {@link IllegalArgumentException}.
     *
     * @param e the original {@link ClassNotFoundException}
     * @return the {@link IllegalArgumentException} wrapping exception
     */
    private static IllegalArgumentException handleException(ClassNotFoundException e) {
        return new IllegalArgumentException(e);
    }

    /**
     * Handle the {@link InstantiationException} by rethrowing it as an {@link IllegalArgumentException}.
     *
     * @param e the original {@link InstantiationException}
     * @return the {@link IllegalArgumentException} wrapping exception
     */
    private static IllegalArgumentException handleException(InstantiationException e) {
        return new IllegalArgumentException(e);
    }

    /**
     * Get the Member type.
     *
     * @param member member
     * @return member type
     */
    public static Class getMemberType(Member member) {
        if (Field.class.isInstance(member)) {
            return ((Field) member).getType();
        } else if (Method.class.isInstance(member)) {
            return ((Method) member).getReturnType();
        }
        throw new UnsupportedOperationException(
            String.format(
                "The [%s] member is neither a Field or a Method!",
                member
            )
        );
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy