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

shz.core.AccessibleHelp Maven / Gradle / Ivy

There is a newer version: 2024.0.2
Show newest version
package shz.core;

import shz.core.cache.SimpleCache;
import shz.core.constant.NullConstant;
import shz.core.msg.ServerFailureMsg;
import shz.core.type.TypeHelp;

import java.lang.reflect.*;
import java.util.*;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;

@SuppressWarnings("unchecked")
public final class AccessibleHelp {
    private AccessibleHelp() {
        throw new IllegalStateException();
    }

    private static final SimpleCache, List> FIELDS_CACHE = new SimpleCache<>();

    /**
     * 获取域
     *
     * @param cls    类的class对象
     * @param filter 域过滤器
     * @param limit  限制获取属性个数
     * @param cache  是否缓存(若使用缓存,返回集合约定不可修改)
     */
    public static List fields(Class cls, Predicate filter, int limit, boolean cache) {
        if (cls == null) return Collections.emptyList();
        if (cache) {
            List fields = FIELDS_CACHE.get(cls, () -> {
                List result = new ArrayList<>();
                Class cur = cls;
                do {
                    result.addAll(Arrays.asList(cur.getDeclaredFields()));
                    cur = cur.getSuperclass();
                } while (cur != null && cur != Object.class);
                return result.isEmpty() ? Collections.emptyList() : new ArrayList<>(result);
            });
            if (fields.isEmpty()) return Collections.emptyList();
            if (filter == null) return fields;
            if (limit <= 0) return ToList.explicitCollect(fields.stream().filter(filter), fields.size());
            return ToList.explicitCollect(fields.stream().filter(filter).limit(limit), limit);
        }

        List result = new ArrayList<>();
        int size = 0;
        Class cur = cls;
        do {
            for (Field f : cur.getDeclaredFields()) {
                if (filter != null && !filter.test(f)) continue;
                result.add(f);
                ++size;
                if (limit > 0 && size >= limit) break;
            }
            cur = cur.getSuperclass();
        } while (cur != null && cur != Object.class);
        return result.isEmpty() ? Collections.emptyList() : result;
    }

    public static List fields(Class cls, Predicate filter, int limit) {
        return fields(cls, filter, limit, true);
    }

    public static List fields(Class cls, Predicate filter) {
        return fields(cls, filter, 0, true);
    }

    public static List fields(Class cls) {
        return fields(cls, null, 0, true);
    }

    private static final SimpleCache, List> METHODS_CACHE = new SimpleCache<>();

    /**
     * 获取类的方法
     */
    public static List methods(Class cls, Predicate filter, int limit, boolean cache) {
        if (cls == null) return Collections.emptyList();
        if (cache) {
            List methods = METHODS_CACHE.get(cls, () -> {
                List result = new ArrayList<>();
                Class cur = cls;
                do {
                    result.addAll(Arrays.asList(cur.getDeclaredMethods()));
                    cur = cur.getSuperclass();
                } while (cur != null && cur != Object.class);
                return result.isEmpty() ? Collections.emptyList() : new ArrayList<>(result);
            });
            if (methods.isEmpty()) return Collections.emptyList();
            if (filter == null) return methods;
            if (limit <= 0) return ToList.explicitCollect(methods.stream().filter(filter), methods.size());
            return ToList.explicitCollect(methods.stream().filter(filter).limit(limit), limit);
        }

        List result = new ArrayList<>();
        int size = 0;
        Class cur = cls;
        do {
            for (Method m : cur.getDeclaredMethods()) {
                if (filter != null && !filter.test(m)) continue;
                result.add(m);
                ++size;
                if (limit > 0 && size >= limit) break;
            }
            cur = cur.getSuperclass();
        } while (cur != null && cur != Object.class);
        return result.isEmpty() ? Collections.emptyList() : result;
    }

    public static List methods(Class cls, Predicate filter, int limit) {
        return methods(cls, filter, limit, true);
    }

    public static List methods(Class cls, Predicate filter) {
        return methods(cls, filter, 0, true);
    }

    public static List methods(Class cls) {
        return methods(cls, null, 0, true);
    }

    private static Field accessible(Field field) {
        if (field.isAccessible()) return field;
        if ((field.getModifiers() & Modifier.PUBLIC) == 0
                || (field.getDeclaringClass().getModifiers() & Modifier.PUBLIC) == 0
                || (field.getModifiers() & Modifier.FINAL) != 0)
            field.setAccessible(true);
        return field;
    }

    private static Method accessible(Method method) {
        if (method.isAccessible()) return method;
        if ((method.getModifiers() & Modifier.PUBLIC) == 0
                || (method.getDeclaringClass().getModifiers() & Modifier.PUBLIC) == 0)
            method.setAccessible(true);
        return method;
    }

    private static  Constructor accessible(Constructor constructor) {
        if (constructor.isAccessible()) return constructor;
        if ((constructor.getModifiers() & Modifier.PUBLIC) == 0
                || (constructor.getDeclaringClass().getModifiers() & Modifier.PUBLIC) == 0)
            constructor.setAccessible(true);
        return constructor;
    }

    public static  T getField(Field field, Object obj) {
        if (field == null) return null;
        try {
            return (T) accessible(field).get(obj);
        } catch (Exception e) {
            return null;
        }
    }

    public static boolean setField(Field field, Object obj, Object value) {
        if (field == null || obj == null) return false;
        try {
            accessible(field).set(obj, value);
            return true;
        } catch (Exception ignored) {
            return false;
        }
    }

    public static  T newInstance(Class cls) {
        if (cls == null) return null;
        try {
            return ((Constructor) accessible(cls.getDeclaredConstructor())).newInstance();
        } catch (Exception e) {
            if (List.class.isAssignableFrom(cls)) return (T) new ArrayList<>();
            if (Set.class.isAssignableFrom(cls)) return (T) new LinkedHashSet<>();
            if (Map.class.isAssignableFrom(cls)) return (T) new LinkedHashMap<>();
        }
        return null;
    }

    public static  T newInstance(Class cls, Object arg) {
        if (arg == null) {
            for (Constructor constructor : cls.getDeclaredConstructors()) {
                if (constructor.getParameterCount() == 1) {
                    try {
                        return (T) accessible(constructor).newInstance((Object) null);
                    } catch (Exception ignored) {
                    }
                }
            }
            return null;
        }
        Class paramType = arg.getClass();
        Constructor bestMatch = null;
        for (Constructor constructor : cls.getDeclaredConstructors()) {
            if (constructor.getParameterCount() == 1) {
                Class parameterType = constructor.getParameterTypes()[0];
                if (parameterType == paramType) {
                    bestMatch = constructor;
                    break;
                }
                if (bestMatch == null) {
                    if (parameterType.isAssignableFrom(paramType)) bestMatch = constructor;
                } else if (bestMatch.getParameterTypes()[0].isAssignableFrom(parameterType)) bestMatch = constructor;
            }

        }
        if (bestMatch == null) return null;
        try {
            return (T) accessible(bestMatch).newInstance(arg);
        } catch (Exception e) {
            return null;
        }
    }

    public static  T newInstance(Class cls, Object... args) {
        List> constructors = new ArrayList<>();
        for (Constructor constructor : cls.getDeclaredConstructors())
            if (constructor.getParameterCount() == args.length) constructors.add(constructor);
        if (constructors.isEmpty()) return null;
        Constructor constructor;
        if (constructors.size() == 1) constructor = constructors.get(0);
        else {
            Class[][] psa = constructors.stream().map(Constructor::getParameterTypes).toArray(Class[][]::new);
            Class[] paramTypes = Arrays.stream(args).map(arg -> arg == null ? Object.class : arg.getClass()).toArray(Class[]::new);
            constructor = constructors.get(TypeHelp.bestMatchParamTypes(psa, paramTypes));
        }
        try {
            return (T) accessible(constructor).newInstance(args);
        } catch (Exception e) {
            return null;
        }
    }

    public static  T invoke(Method method, Object obj, Object... args) {
        try {
            if (method.getReturnType() == void.class) accessible(method).invoke(obj, args);
            else return (T) accessible(method).invoke(obj, args);
        } catch (Exception e) {
            throw PRException.of(e);
        }
        return null;
    }

    public static  T getField(Object obj, Predicate filter) {
        List fields;
        if (obj == null || (fields = fields(obj.getClass(), filter, 1)).isEmpty()) return null;
        return getField(fields.get(0), obj);
    }

    public static boolean setField(Object obj, Predicate filter, Object value) {
        List fields;
        if (obj == null || (fields = fields(obj.getClass(), filter, 1)).isEmpty()) return false;
        return setField(fields.get(0), obj, value);
    }

    public static void setField(Object obj, Function func) {
        if (obj == null || func == null) return;
        List fields = fields(obj.getClass());
        if (fields.isEmpty()) return;
        fields.forEach(f -> {
            Object value = func.apply(f);
            if (value == NullConstant.OBJECT) return;
            setField(f, obj, value);
        });
    }

    public static void setField(Object obj, BiFunction, Field, Object> func) {
        if (obj == null || func == null) return;
        List fields = fields(obj.getClass());
        if (fields.isEmpty()) return;
        Map nameMap = ToMap.explicitCollect(fields.stream(), Field::getName, Function.identity(), fields.size());
        fields.forEach(f -> {
            Object value = func.apply(nameMap, f);
            if (value == NullConstant.OBJECT) return;
            setField(f, obj, value);
        });
    }

    /**
     * 根据方法名称获取空参方法
     */
    public static Method getMethod(Class cls, String methodName) {
        List methods = methods(cls, m -> m.getName().equals(methodName) && m.getParameterCount() == 0, 1);
        return methods.isEmpty() ? null : methods.get(0);
    }

    /**
     * 根据方法名称及参数类型获取一个参数的方法
     */
    public static Method getMethod(Class cls, String methodName, Class paramType) {
        List methods = methods(cls, m -> {
            if (!m.getName().equals(methodName)) return false;
            Class[] ptypes = m.getParameterTypes();
            return ptypes.length == 1 && ptypes[0].isAssignableFrom(paramType);
        }, 0);
        if (methods.isEmpty()) return null;
        if (methods.size() == 1) return methods.get(0);
        Class[] pa = methods.stream().map(m -> m.getParameterTypes()[0]).toArray(Class[]::new);
        int idx = 0;
        for (int i = 1; i < pa.length; ++i) {
            if (pa[idx] == paramType) break;
            if (pa[idx].isAssignableFrom(pa[i])) idx = i;
        }
        return methods.get(idx);
    }

    /**
     * 根据方法名称及参数类型获取二个参数的方法
     */
    public static Method getMethod(Class cls, String methodName, Class paramType1, Class paramType2) {
        List methods = methods(cls, m -> {
            if (!m.getName().equals(methodName)) return false;
            Class[] ptypes = m.getParameterTypes();
            return ptypes.length == 2 && ptypes[0].isAssignableFrom(paramType1) && ptypes[1].isAssignableFrom(paramType2);
        }, 0);
        if (methods.isEmpty()) return null;
        if (methods.size() == 1) return methods.get(0);
        Class[][] psa = methods.stream().map(Method::getParameterTypes).toArray(Class[][]::new);
        return methods.get(TypeHelp.bestMatchParamTypes(psa, paramType1, paramType2));
    }

    /**
     * 根据方法名称及参数类型获取多个参数的方法
     */
    public static Method getMethod(Class cls, String methodName, Class... paramTypes) {
        List methods = methods(cls, m -> {
            if (!m.getName().equals(methodName)) return false;
            Class[] pTypes = m.getParameterTypes();
            if (pTypes.length != paramTypes.length) return false;
            for (int i = 0; i < pTypes.length; ++i) if (!pTypes[i].isAssignableFrom(paramTypes[i])) return false;
            return true;
        }, 0);
        if (methods.isEmpty()) return null;
        if (methods.size() == 1) return methods.get(0);
        Class[][] psa = methods.stream().map(Method::getParameterTypes).toArray(Class[][]::new);
        return methods.get(TypeHelp.bestMatchParamTypes(psa, paramTypes));
    }

    /**
     * 通过反射执行方法
     */
    public static  T invoke(Object obj, String methodName) {
        return invoke(getMethod(Objects.requireNonNull(obj).getClass(), methodName), obj);
    }

    public static  T invoke(Object obj, String methodName, Class paramType, Object arg) {
        return invoke(getMethod(Objects.requireNonNull(obj).getClass(), methodName, paramType), obj, arg);
    }

    public static  T invoke(Object obj, String methodName, Class[] paramTypes, Object[] args) {
        return invoke(getMethod(Objects.requireNonNull(obj).getClass(), methodName, paramTypes), obj, args);
    }

    public static  T invoke(Object obj, Method method, Function paramNamesFunc, Map data) {
        Class[] parameterTypes = method.getParameterTypes();
        if (parameterTypes.length == 0) return invoke(method, obj);
        String[] paramNames = paramNamesFunc.apply(method);
        ServerFailureMsg.requireNon(NullHelp.length(paramNames) != parameterTypes.length, "参数名称列表与参数类型列表长度不一致");
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        Object[] args = new Object[parameterTypes.length];
        for (int i = 0; i < parameterTypes.length; ++i) {
            if (TypeHelp.likeCommon(parameterTypes[i]))
                args[i] = FieldSetter.cast(data.get(paramNames[i]), parameterTypes[i]);
            else args[i] = FieldSetter.create(data, parameterTypes[i], genericParameterTypes[i]);
        }
        return invoke(method, obj, args);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy