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

com.arch.util.ReflectionUtils Maven / Gradle / Ivy

There is a newer version: 18.12.0
Show newest version
package com.arch.util;

import org.apache.commons.beanutils.ConstructorUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
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.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public final class ReflectionUtils {

    private ReflectionUtils() {
        super();
    }

    public static Boolean evaluateRendered(Predicate evaluate, Object object) {
        if (evaluate == null) {
            return true;
        }

        return evaluate.test(object);
    }

    public static Boolean evaluateDisabled(Predicate evaluate, Object object) {
        if (evaluate == null) {
            return false;
        }

        return evaluate.test(object);
    }

    public static  T getValueByField(Object instance, Field field, Class clazzValueReturn) {
        return (T) getValueByName(instance, field.getName());
    }

    public static Object getValueByField(Object instance, Field field) {
        return getValueByName(instance, field.getName());
    }

    public static  T getValueByName(Object instance, String fieldName, Class clazzValueReturn) {
        return (T) getValueByName(instance, fieldName);
    }

    public static Object getValueByName(Object instance, String fieldName) {
        String attributeName = fieldName;
        Field field;
        Method getterMethod;
        String rootProperty;
        boolean isMultLevelProperty = attributeName.contains(".");
        String[] propertyTokens = attributeName.split("\\.");

        if (isMultLevelProperty) {
            rootProperty = propertyTokens[0];
            attributeName = removeStart(attributeName, rootProperty + ".");
            getterMethod = getGetter(instance.getClass(), rootProperty, true);
            field = getField(instance.getClass(), rootProperty, true);
        } else {
            getterMethod = getGetter(instance.getClass(), attributeName, true);
            field = getField(instance.getClass(), attributeName, true);
        }

        if (getterMethod == null && field == null) {
            throw new ReflectionException("Field not found " + fieldName);
        }

        if (getterMethod != null) {
            try {
                Object result = getterMethod.invoke(instance);
                if (isMultLevelProperty) {
                    return getValueByName(result, attributeName);
                } else {
                    return result;
                }
            } catch (IllegalAccessException | InvocationTargetException ex) {
                throw new ReflectionException(ex);
            }
        }

        setAttributesAcessible(field);

        try {
            Object result = field.get(instance);
            if (isMultLevelProperty) {
                return getValueByName(result, attributeName);
            } else {
                return result;
            }
        } catch (IllegalAccessException ex) {
            throw new ReflectionException(ex);
        }

    }

    public static Optional getOptionalValueByName(Object instance, String fieldName) {
        try {
            return Optional.of(getValueByName(instance, fieldName));
        } catch (Exception ex) {
            return Optional.empty();
        }
    }

    public static void setValue(Field field, Object target, Object value) {
        Method setterMethod = null;

        if (value != null) {
            setterMethod = getSetter(target.getClass(), field.getName(), value.getClass(), true);
        }

        if (setterMethod != null) {
            try {
                setterMethod.invoke(target, value);
            } catch (InvocationTargetException | IllegalAccessException ex) {
                throw new ReflectionException(ex);
            }
        } else {
            try {
                setAttributesAcessible(field);
                field.set(target, value);
            } catch (IllegalArgumentException | IllegalAccessException ex) {
                throw new ReflectionException(ex);
            }
        }
    }

    public static String getGetter(Field atributo) {
        return getGetter(atributo.getName());
    }

    public static String getGetter(String atributo) {
        return getMethod("get", atributo);
    }

    public static String getSetter(String atributo) {
        return getMethod("set", atributo);
    }

    public static Method getGetter(Object objeto, Field atributo) {
        return getGetter(objeto.getClass(), atributo.getName());
    }

    public static Method getGetter(Object objeto, String atributo) {
        return getGetter(objeto.getClass(), atributo, true);
    }

    public static Method getGetter(Object objeto, String atributo, boolean buscaClassePai) {
        return getGetter(objeto.getClass(), atributo, buscaClassePai);
    }

    public static Method getGetter(Class classe, String atributo, boolean buscaClassePai) {
        String methodGetter = getGetter(atributo);

        try {
            return classe.getDeclaredMethod(methodGetter);
        } catch (NoSuchMethodException ex) {
            LogUtils.generateSilent(ex);
            if (buscaClassePai && classe != Object.class) {
                return getGetter(classe.getSuperclass(), atributo, buscaClassePai);
            }
        }

        return null;
    }

    public static Method getSetter(Object objeto, String atributo, Class paramClassSet,
                                   boolean buscaClassePai) {
        return getSetter(objeto.getClass(), atributo, paramClassSet, buscaClassePai);
    }

    public static Method getSetter(Class clazz, String fieldName, Class paramClassSet,
                                   boolean buscaClassePai) {

        String methodGetter = getSetter(fieldName);

        try {
            return clazz.getDeclaredMethod(methodGetter, paramClassSet);
        } catch (NoSuchMethodException | SecurityException ex) {
            LogUtils.generateSilent(ex);
            if (buscaClassePai && clazz != Object.class) {
                return getSetter(clazz.getSuperclass(), methodGetter, paramClassSet, buscaClassePai);
            }
        }

        return null;
    }

    public static void setValue(String property, Object target, Object value) {
        Field field = getField(target, property, true);
        setAttributesAcessible(field);
        if (value == null) {
            setValue(field, target, null);
        } else {
            setValue(property, target, value, value.getClass());
        }
    }

    public static void setValue(String nameField, Object instance, Object value, Class setParamClass) {

        Object target = instance;
        String property = nameField;

        String[] propriedadeTokens = property.split("\\.");

        boolean isMultLevelProperty = property.contains(".");
        if (!isMultLevelProperty) {
            Method setterMethod = getSetter(target.getClass(), property, true, setParamClass);
            if (setterMethod != null) {
                try {
                    setterMethod.invoke(target, value);
                } catch (IllegalAccessException | InvocationTargetException ex) {
                    throw new ReflectionException(ex);
                }
            } else {
                Field field = getField(target.getClass(), property, true);
                if (field == null) {
                    throw new ReflectionException();
                }
                setValue(field, target, value);
            }
        } else {
            int lastIndexProperty = property.lastIndexOf('.');
            String propriedadeSet = propriedadeTokens[propriedadeTokens.length - 1];
            property = property.substring(0, lastIndexProperty);
            target = getValueByName(target, property);
            setValue(propriedadeSet, target, value, setParamClass);
        }
    }

    public static Method getSetter(Class clazz, String fieldName, boolean findInSuperClasses, Class... classParams) {

        String methodOrPropertyName = fieldName;

        if (methodOrPropertyName == null) {
            throw new IllegalStateException("methodOrPropertyName is null");
        }

        if (!methodOrPropertyName.startsWith("set")) {
            methodOrPropertyName = getSetter(methodOrPropertyName);
        }

        try {
            return clazz.getDeclaredMethod(methodOrPropertyName, classParams);
        } catch (NoSuchMethodException ex) {
            LogUtils.generate(ex);
            if (findInSuperClasses && clazz != Object.class) {
                return getSetter(clazz.getSuperclass(), methodOrPropertyName, findInSuperClasses, classParams);
            }
        }

        return null;
    }

    public static Field getField(Class clazz, String fieldName) {
        return getField(clazz, fieldName, true);
    }

    public static Field getField(Class clazz, String fieldName, boolean findInSuperClasses) {

        Class classFinal = clazz;
        String attribute = fieldName;

        while (attribute.contains(".")) {
            String attributeParcial = attribute.substring(0, attribute.indexOf('.'));
            Field field = getField(classFinal, attributeParcial, findInSuperClasses);

            classFinal = field.getType();
            attribute = attribute.replace(attributeParcial + ".", "");
        }

        try {
            return classFinal.getDeclaredField(attribute);
        } catch (NoSuchFieldException ex) {
            LogUtils.generateSilent(ex);
            if (findInSuperClasses && classFinal != Object.class) {
                return getField(classFinal.getSuperclass(), attribute, findInSuperClasses);
            }
        }

        return null;
    }

    public static Field getField(Class clazz, Class clazzField) {
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (field.getType() == clazzField) {
                return field;
            }
        }

        if (clazz.getSuperclass() != Object.class) {
            return getField(clazz.getSuperclass(), clazzField);
        }

        return null;
    }

    public static Field getFieldCollection(Class clazz, Class clazzOfCollection) {
        Field[] fields = clazz.getDeclaredFields();

        for (Field field : fields) {
            if (Collection.class.isAssignableFrom(field.getType())
                    && getGenericClass(field, 0) == clazzOfCollection) {
                return field;
            }
        }

        return null;
    }

    public static Field getField(Object target, String fieldName, boolean findInSuperClasses) {
        return getField(target.getClass(), fieldName, findInSuperClasses);
    }

    public static void setAttributesAcessible(Field... fields) {
        for (Field field : fields) {
            field.setAccessible(true);
        }
    }

    public static void setAttributesAcessible(Class clazz, List fieldList, boolean findInSuperClasses,
                                              boolean setFieldsAsAccessible) {
        if (clazz.equals(Object.class)) {
            return;
        }

        for (Field field : clazz.getDeclaredFields()) {
            if (setFieldsAsAccessible) {
                setAttributesAcessible(field);
            }
            fieldList.add(field);
        }

        if (findInSuperClasses) {
            setAttributesAcessible(clazz.getSuperclass(), fieldList, findInSuperClasses, setFieldsAsAccessible);
        }
    }

    public static Field[] getArrayFields(Class clazz, boolean findInSuperClasses, boolean setFieldsAsAccessible) {
        List campos = new ArrayList<>();
        setAttributesAcessible(clazz, campos, findInSuperClasses, setFieldsAsAccessible);
        return campos.toArray(new Field[campos.size()]);
    }

    public static Field[] getArrayFields(Object target, boolean findInSuperClasses, boolean setFieldsAsAccessible) {
        List campos = new ArrayList<>();
        setAttributesAcessible(target.getClass(), campos, findInSuperClasses, setFieldsAsAccessible);
        return campos.toArray(new Field[campos.size()]);
    }

    public static Collection getListFields(Object target, boolean findInSuperClasses, boolean setFieldsAsAccessible) {
        return Arrays
                .stream(getArrayFields(target, findInSuperClasses, setFieldsAsAccessible))
                .collect(Collectors.toList());
    }

    public static Object executeMethod(Object target, String methodName, Object... params) throws InvocationTargetException, IllegalAccessException {

        Optional optMethod = Arrays.stream(target.getClass().getMethods()).filter(m -> m.getName().equals(methodName)).findAny();

        if (optMethod.isPresent()) {
            return executeMethod(target, optMethod.get(), params);
        }

        Class[] paramsTypes = new Class[params.length];

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

        Method method = getMethod(target.getClass(), methodName, paramsTypes);

        if (method == null) {
            throw new ReflectionException("Método " + methodName + " com a assinatura buscada não encontrado em "
                    + target.getClass() + " e em nenhuma de suas super classes");
        }

        return executeMethod(target, method, params);
    }


    public static Object executeMethod(Object target, Method method, Object... params) throws InvocationTargetException, IllegalAccessException {
        if (target == null) {
            throw new IllegalStateException("Objeto não pode ser null");
        }

        Class[] paramsTypes = new Class[params.length];

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

        method.setAccessible(true);
        return method.invoke(target, params);
    }

    public static Method getMethod(Class clazz, String methodName, List args) {
        return getMethod(clazz, methodName, args.toArray());
    }

    public static Method getMethod(Class clazz, String methodName, Object[] args) {
        Class[] classes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            classes[i] = args[i].getClass();
        }

        return getMethod(clazz, methodName, classes);
    }

    public static Method getMethod(Class clazz, String methodName, Class... paramsTypes) {
        Method method;
        try {
            method = clazz.getMethod(methodName, paramsTypes);
        } catch (SecurityException e) {
            throw new ReflectionException(e);
        } catch (NoSuchMethodException e) {
            LogUtils.generateSilent(e);

            if (clazz == Object.class) {
                return null;
            }

            return getMethod(clazz.getSuperclass(), methodName, paramsTypes);
        }

        return method;
    }

    public static boolean isAttribute(Object target, String attribute, boolean findInSuperClasses) {
        return getField(target, attribute, findInSuperClasses) != null;
    }

    public static boolean isAttribute(Class clazz, String attribute, boolean findInSuperClasses) {
        return getField(clazz, attribute, findInSuperClasses) != null;
    }

    public static  Class getGenericClass(final Class clazz, final int idx) {
        final Type type = clazz.getGenericSuperclass();
        ParameterizedType paramType;
        try {
            paramType = (ParameterizedType) type;
        } catch (ClassCastException cause) {
//            LogUtils.generateSilent(cause);
//            paramType = (ParameterizedType) ((Class) type).getGenericSuperclass();

            if (clazz != Object.class) {
                return getGenericClass(clazz.getSuperclass(), idx);
            }

            throw cause;
        }

        return (Class) paramType.getActualTypeArguments()[idx];
    }

    public static  Class getGenericClass(final Field field, final int idx) {
        final Type type = field.getGenericType();
        final ParameterizedType paramType = (ParameterizedType) type;

        return (Class) paramType.getActualTypeArguments()[idx];
    }

    public static  Class getGenericClass(final Member member, final int idx) {
        Class result = null;

        if (member instanceof Field) {
            result = getGenericClass((Field) member, idx);
        } else if (member instanceof Method) {
            result = getGenericClass((Method) member, idx);
        }

        return result;
    }

    public static  Class getGenericClass(final Method method, final int pos) {
        return (Class) method.getGenericParameterTypes()[pos];
    }

    public static Object createInstance(Class clazz) {
        try {
            if (Collection.class.isAssignableFrom(clazz)) {
                return createCollection(clazz);
            } else if (Map.class.isAssignableFrom(clazz)) {
                return new HashMap();
            }

            return clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException ex) {
            LogUtils.generate(ex);
            throw new ReflectionException(ex);
        }
    }

    public static  E createInstance(Class clazz, Object... args) {
        try {
            return ConstructorUtils.invokeConstructor(clazz, args);
        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            throw new ReflectionException(e);
        }
    }

    public static boolean isCollection(Field field) {
        return Collection.class.isAssignableFrom(field.getType());
    }

    public static Object cloneAttributes(Object copiar, Object copiado) {

        if (copiar == null || copiado == null) {
            return null;
        }

        Field[] fieldsCopiado = getArrayFields(copiado, false, false);

        if (fieldsCopiado == null || fieldsCopiado.length == 0) {
            return copiar;
        }

        for (Field fieldCopiado : fieldsCopiado) {
            Field fieldCopiar = getField(copiar, fieldCopiado.getName(), false);

            if (fieldCopiar != null && fieldCopiar.getType().isAssignableFrom(fieldCopiado.getType())) {
                try {
                    setAttributesAcessible(fieldCopiar, fieldCopiado);
                    setValue(fieldCopiar, copiar, fieldCopiado.get(copiado));
                } catch (IllegalArgumentException | IllegalAccessException ex) {
                    throw new ReflectionException(ex);
                }
            }
        }

        return copiar;
    }

    public static boolean isFieldAssignFromClass(Field field, Class clazz) {
        if (!ParameterizedType.class.isAssignableFrom(field.getGenericType().getClass())) {
            return false;
        }

        ParameterizedType stringListType = (ParameterizedType) field.getGenericType();
        Class fieldClass = (Class) stringListType.getActualTypeArguments()[0];
        return clazz.isAssignableFrom(fieldClass);
    }

    public static Class getGenericClass(Field field) {
        if (!ParameterizedType.class.isAssignableFrom(field.getGenericType().getClass())) {
            return field.getType();
        }

        ParameterizedType stringListType = (ParameterizedType) field.getGenericType();

        return (Class) stringListType.getActualTypeArguments()[0];
    }

    private static String getMethod(String prefix, String fieldName) {
        if (fieldName.startsWith(prefix)) {
            return fieldName;
        }

        String first = fieldName.substring(0, 1);

        return prefix + fieldName.replaceFirst(first, first.toUpperCase(Locale.getDefault()));
    }

    private static String removeStart(String str, String remove) {
        return !isEmpty(str) && !isEmpty(remove) ? (str.startsWith(remove) ? str.substring(remove.length()) : str) : str;
    }

    private static boolean isEmpty(String str) {
        return str == null || str.length() == 0;
    }

    private static Object createCollection(Class clazz) {
        if (List.class.isAssignableFrom(clazz)) {
            return new ArrayList();
        } else if (Set.class.isAssignableFrom(clazz)) {
            return new HashSet();
        } else {
            return null;
        }
    }
}