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

shz.AccessibleHelp Maven / Gradle / Ivy

package shz;

import shz.cache.MapCache;
import shz.constant.ArrayConstant;
import shz.constant.NullConstant;
import shz.enums.IEnum;
import shz.msg.ServerFailure;
import shz.queue.IArrayQueue;
import shz.st.tst.LTST;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.*;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Stream;

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

    public static Class forName(String className, boolean initialize, ClassLoader loader) {
        if (Validator.isBlank(className)) return null;
        switch (className) {
            case "boolean":
                return boolean.class;
            case "short":
                return short.class;
            case "char":
                return char.class;
            case "int":
                return int.class;
            case "long":
                return long.class;
            case "double":
                return double.class;
            case "byte":
                return byte.class;
            case "float":
                return float.class;
            case "void":
                return void.class;
            default:
                try {
                    if (initialize && loader == null) return Class.forName(className);
                    return Class.forName(className, initialize, loader == null ? Thread.currentThread().getContextClassLoader() : loader);
                } catch (ClassNotFoundException e) {
                    return null;
                }
        }
    }

    public static Class forName(String className, boolean initialize) {
        return forName(className, initialize, null);
    }

    public static Class forName(String className) {
        return forName(className, false, null);
    }

    public static boolean isPrimitive(Class cls) {
        if (cls == null || cls == void.class) return false;
        return cls.isPrimitive();
    }

    public static boolean isPrimitiveWrap(Class cls) {
        if (cls == null) return false;
        return cls == Boolean.class
                || cls == Byte.class
                || cls == Character.class
                || cls == Short.class
                || cls == Integer.class
                || cls == Long.class
                || cls == Double.class
                || cls == Float.class;
    }

    public static boolean isCommon(Class cls) {
        if (cls == null || cls == Void.class || cls == void.class) return false;
        return cls.isPrimitive()
                || cls == Boolean.class
                || cls == Character.class
                || CharSequence.class.isAssignableFrom(cls)
                || Number.class.isAssignableFrom(cls)
                || TemporalAccessor.class.isAssignableFrom(cls)
                || TemporalAdjuster.class.isAssignableFrom(cls)
                || Date.class.isAssignableFrom(cls)
                || Enum.class.isAssignableFrom(cls);
    }

    public static boolean canCast(Class src, Class des) {
        if (src == null || des == null) return false;
        boolean srcIsP = src.isPrimitive(), srcIsPw = !srcIsP && isPrimitiveWrap(src);
        boolean desIsP = des.isPrimitive(), desIsPw = !desIsP && isPrimitiveWrap(des);
        if ((srcIsP | srcIsPw) ^ (desIsP | desIsPw)) return false;
        if (!(srcIsP | srcIsPw | desIsP | desIsPw)) return des.isAssignableFrom(src);
        String desName = des.getTypeName();
        switch (src.getTypeName()) {
            case "java.lang.Boolean":
            case "boolean":
                return desName.endsWith("n");
            case "java.lang.Byte":
            case "byte":
                return desName.endsWith("te");
            case "java.lang.Character":
            case "char":
                return desName.endsWith("ter") || desName.endsWith("ar");
            case "java.lang.Short":
            case "short":
                return desName.endsWith("rt");
            case "java.lang.Integer":
            case "int":
                return desName.endsWith("ger") || desName.endsWith("nt");
            case "java.lang.Long":
            case "long":
                return desName.endsWith("g");
            case "java.lang.Double":
            case "double":
                return desName.endsWith("le");
            case "java.lang.Float":
            case "float":
                return desName.endsWith("at");
            case "java.lang.Void":
            case "void":
                return desName.endsWith("d");
            default:
                return false;
        }
    }

    /**
     * 获取指定类对象的父类或实现的接口中指定泛型的类对象
     *
     * @param cls              指定类对象(superOrInterface 的子类或实现类)
     * @param superOrInterface 指定类对象的父类或实现的接口
     * @param typeParamName    父类或接口中泛型参数的名称(T,K或V...)
     * @return 父类或接口中泛型参数的类对象
     */
    public static  Class getParameterizedType(Class cls, Class superOrInterface, String typeParamName) {
        return (Class) getParameterizedType0(cls, superOrInterface, typeParamName);
    }

    private static Class getParameterizedType0(Class cls, Class superOrInterface, String typeParamName) {
        Class cur = cls;
        for (; ; ) {
            if ((cur = oneTopChild(cur, superOrInterface)) == null) return Object.class;
            int idx = -1;
            TypeVariable[] typeParams = superOrInterface.getTypeParameters();
            for (int i = 0; i < typeParams.length; ++i)
                if (typeParamName.equals(typeParams[i].getName())) {
                    idx = i;
                    break;
                }
            if (idx < 0) return Object.class;
            Type genericSuperType = null;
            if (superOrInterface.isInterface()) {
                for (Type type : cur.getGenericInterfaces())
                    if (tryToClass(type) == superOrInterface) {
                        genericSuperType = type;
                        break;
                    }
            } else genericSuperType = cur.getGenericSuperclass();
            if (!(genericSuperType instanceof ParameterizedType)) return Object.class;
            Type[] actualTypeParams = ((ParameterizedType) genericSuperType).getActualTypeArguments();
            Type actualTypeParam = actualTypeParams[idx];
            Class result;
            if ((result = tryToClass(actualTypeParam)) != null) return result;
            if (actualTypeParam instanceof TypeVariable) {
                cur = cls;
                TypeVariable v = (TypeVariable) actualTypeParam;
                GenericDeclaration d;
                if (!((d = v.getGenericDeclaration()) instanceof Class)) return Object.class;
                typeParamName = v.getName();
                if (!(superOrInterface = (Class) d).isAssignableFrom(cls)) return Object.class;
                continue;
            }
            return Object.class;
        }
    }

    private static Class oneTopChild(Class c, Class p) {
        if (c == null || c == Object.class) return null;
        Class cur = c, sup;
        do {
            if ((sup = cur.getSuperclass()) == p) return cur;
            if (sup == null || !p.isAssignableFrom(sup)) break;
            cur = sup;
        } while (true);
        c = null;
        for (Class cls : cur.getInterfaces()) {
            if (cls == p) return cur;
            if (c == null && p.isAssignableFrom(cls)) c = cls;
        }
        return oneTopChild(c, p);
    }

    private static Class tryToClass(Type type) {
        if (type instanceof ParameterizedType) type = ((ParameterizedType) type).getRawType();
        if (type instanceof Class) return (Class) type;
        if (type instanceof GenericArrayType) {
            Type componentType = ((GenericArrayType) type).getGenericComponentType();
            if (componentType instanceof ParameterizedType)
                componentType = ((ParameterizedType) componentType).getRawType();
            if (componentType instanceof Class) return Array.newInstance((Class) componentType, 0).getClass();
        }
        return null;
    }

    public static Type[] getTypes(Field field) {
        Type genericType = field.getGenericType();
        if (genericType instanceof ParameterizedType) return ((ParameterizedType) genericType).getActualTypeArguments();
        return Validator.empty(Type[].class);
    }

    public static Type[] getTypes(Class cls) {
        if (cls == null) return Validator.empty(Type[].class);
        Type genericSuperType = null;
        if (cls.isInterface()) {
            for (Type type : cls.getGenericInterfaces())
                if ((genericSuperType = type) instanceof ParameterizedType) break;
        } else genericSuperType = cls.getGenericSuperclass();
        if (genericSuperType instanceof ParameterizedType)
            return ((ParameterizedType) genericSuperType).getActualTypeArguments();
        return Validator.empty(Type[].class);
    }

    public static Class typeToClass(Type type) {
        if (type == null) return null;
        Class cls;
        if ((cls = tryToClass(type)) != null) return cls;
        if (type instanceof TypeVariable) {
            TypeVariable v = (TypeVariable) type;
            if (!(v.getGenericDeclaration() instanceof Class)) return Object.class;
        }
        return forName(type.getTypeName());
    }

    public static Class[] typeToClass(Type[] types, int... indexes) {
        if (Validator.isEmpty(types)) return ArrayConstant.EMPTY_CLASS_ARRAY;
        Validator.requireNon(types.length < indexes.length);
        Type[] result = new Type[indexes.length];
        for (int i = 0; i < indexes.length; ++i) {
            Validator.requireNon(indexes[i] < 0 || indexes[i] >= types.length);
            result[i] = types[indexes[i]];
        }
        return Arrays.stream(result).map(AccessibleHelp::typeToClass).toArray(Class[]::new);
    }

    /**
     * 获取类对象的唯一标识符
     */
    public static String identify(Class cls) {
        if (cls == null) return NullConstant.STRING;
        Type[] types = getTypes(cls);
        if (types.length == 0) return cls.getName();
        StringBuilder sb = new StringBuilder(cls.getName());
        Set> exists = new HashSet<>();
        Arrays.stream(types).map(AccessibleHelp::typeToClass).filter(Objects::nonNull).forEach(c -> identify0(c, sb, exists, 1));
        return sb.toString();
    }

    private static void identify0(Class cls, StringBuilder sb, Set> exists, int nest) {
        Type[] types = getTypes(cls);
        if (types.length == 0) sb.append("-").append(cls.getName()).append(nest);
        else
            Arrays.stream(types).map(AccessibleHelp::typeToClass).filter(Objects::nonNull).forEach(c -> {
                if (exists.contains(c)) sb.append("-").append(c.getName()).append(nest + 1);
                else {
                    exists.add(c);
                    identify0(c, sb, exists, nest + 1);
                }
            });
    }

    public static Field accessible(Field field) {
        Objects.requireNonNull(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;
    }

    public static  Constructor accessible(Constructor constructor) {
        Objects.requireNonNull(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 Method accessible(Method method) {
        Objects.requireNonNull(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 final MapCache, List> FIELD_CACHE = new MapCache<>(128);

    /**
     * 获取类属性
     *
     * @param cls       类的class对象
     * @param predicate 属性过滤器
     * @param limit     限制获取属性个数
     */
    public static List fields(Class cls, Predicate predicate, int limit) {
        if (cls == null || predicate == null) return Collections.emptyList();
        List fields = FIELD_CACHE.get(cls);
        if (fields == null) {
            fields = new LinkedList<>();
            Class cur = cls;
            do {
                Arrays.stream(cur.getDeclaredFields()).map(AccessibleHelp::accessible).forEach(fields::add);
                cur = cur.getSuperclass();
            } while (cur != null && cur != Object.class);
            if (fields.isEmpty()) {
                FIELD_CACHE.put(cls, Collections.emptyList());
                return Collections.emptyList();
            }
            FIELD_CACHE.put(cls, new ArrayList<>(fields));
        }
        if (fields.isEmpty()) return Collections.emptyList();
        Stream stream = fields.stream().filter(predicate);
        return ToList.collect(limit > 0 ? stream.limit(limit) : stream);
    }

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

    public static List fields(Class cls) {
        //默认不获取静态属性
        return fields(cls, f -> (f.getModifiers() & Modifier.STATIC) == 0, 0);
    }

    private static final MapCache, List> FIELD_NAME_CACHE = new MapCache<>(128);

    /**
     * 获取类属性名称
     */
    public static List fieldNames(Class cls, Predicate predicate, int limit) {
        if (cls == null || predicate == null) return Collections.emptyList();
        List fieldNames = FIELD_NAME_CACHE.get(cls);
        if (fieldNames == null) {
            List fields = fields(cls);
            if (fields.isEmpty()) {
                FIELD_NAME_CACHE.put(cls, Collections.emptyList());
                return Collections.emptyList();
            }
            fieldNames = ToList.explicitCollect(fields.stream().map(Field::getName), fields.size());
            FIELD_NAME_CACHE.put(cls, fieldNames);
        }
        if (fieldNames.isEmpty()) return Collections.emptyList();
        Stream stream = fieldNames.stream().filter(predicate);
        return ToList.collect(limit > 0 ? stream.limit(limit) : stream);
    }

    public static List fieldNames(Class cls, Predicate predicate) {
        return fieldNames(cls, predicate, 0);
    }

    public static List fieldNames(Class cls) {
        return fieldNames(cls, f -> true, 0);
    }

    private static final MapCache, List>> CONSTRUCTOR_CACHE = new MapCache<>(128);

    /**
     * 获取类的构造方法
     */
    public static List> constructors(Class cls, Predicate> predicate, int limit) {
        if (cls == null || predicate == null) return Collections.emptyList();
        List> constructors = CONSTRUCTOR_CACHE.get(cls);
        if (constructors == null) {
            constructors = new LinkedList<>();
            Class cur = cls;
            do {
                Arrays.stream(cur.getDeclaredConstructors()).map(AccessibleHelp::accessible).forEach(constructors::add);
                cur = cur.getSuperclass();
            } while (cur != null && cur != Object.class);
            if (constructors.isEmpty()) {
                CONSTRUCTOR_CACHE.put(cls, Collections.emptyList());
                return Collections.emptyList();
            }
            CONSTRUCTOR_CACHE.put(cls, new ArrayList<>(constructors));
        }
        if (constructors.isEmpty()) return Collections.emptyList();
        Stream> stream = constructors.stream().filter(predicate);
        return ToList.collect(limit > 0 ? stream.limit(limit) : stream);
    }

    public static List> constructors(Class cls, Predicate> predicate) {
        return constructors(cls, predicate, 0);
    }

    public static List> constructors(Class cls) {
        return constructors(cls, f -> true, 0);
    }

    private static final MapCache, List> METHOD_CACHE = new MapCache<>(128);

    /**
     * 获取类的方法
     */
    public static List methods(Class cls, Predicate predicate, int limit) {
        if (cls == null || predicate == null) return Collections.emptyList();
        List methods = METHOD_CACHE.get(cls);
        if (methods == null) {
            methods = new LinkedList<>();
            Class cur = cls;
            do {
                Arrays.stream(cur.getDeclaredMethods()).map(AccessibleHelp::accessible).forEach(methods::add);
                cur = cur.getSuperclass();
            } while (cur != null && cur != Object.class);
            if (methods.isEmpty()) {
                METHOD_CACHE.put(cls, Collections.emptyList());
                return Collections.emptyList();
            }
            METHOD_CACHE.put(cls, new ArrayList<>(methods));
        }
        if (methods.isEmpty()) return Collections.emptyList();
        Stream stream = methods.stream().filter(predicate);
        return ToList.collect(limit > 0 ? stream.limit(limit) : stream);
    }

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

    public static List methods(Class cls) {
        return methods(cls, f -> !Modifier.isStatic(f.getModifiers()), 0);
    }

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

    /**
     * 根据方法名称及参数类型获取一个参数的方法
     */
    public static Method getMethod(Class cls, String methodName, Class ptype) {
        List methods = methods(cls, m -> {
            if (!m.getName().equals(methodName)) return false;
            Class[] ptypes = m.getParameterTypes();
            return ptypes.length == 1 && ptypes[0].isAssignableFrom(ptype);
        }, 0);
        Validator.requireNonEmpty(methods);
        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] == ptype) break;
            if (pa[idx].isAssignableFrom(pa[i])) idx = i;
        }
        return methods.get(idx);
    }

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

    private static int match(Class[][] psa, Class... ptypes) {
        int mlen = psa.length, j = 0;
        IArrayQueue ia = IArrayQueue.of(mlen);
        for (int i = 0; i < mlen; ++i) ia.offer(i);
        while (j < ptypes.length - 1) {
            IArrayQueue nia = IArrayQueue.of(mlen);
            for (int k = 0; k < mlen; ++k) {
                int i = ia.poll();
                if (psa[i][j] == ptypes[j]) ia.offer(i);
                else nia.offer(i);
            }
            mlen = ia.size();
            if (mlen == 1) return ia.poll();
            else if (mlen == 0) {
                int nmlen = nia.size();
                Class cls = psa[nia.head()][j];
                nia.offer(nia.poll());
                for (int k = 1; k < nmlen; ++k) {
                    int i = nia.poll();
                    if (cls.isAssignableFrom(psa[i][j])) {
                        nia.offer(i);
                        cls = psa[i][j];
                    }
                }
                if (nia.size() == 1) return nia.poll();
                while (!nia.isEmpty()) {
                    int i = nia.poll();
                    if (psa[i][j] == cls) ia.offer(i);
                }
                mlen = ia.size();
                if (mlen == 1) return ia.poll();
            }
            ++j;
        }
        int idx = ia.poll();
        if (psa[idx][j] == ptypes[j]) return idx;
        while (!ia.isEmpty()) {
            int i = ia.poll();
            if (psa[i][j] == ptypes[j]) return i;
            if (psa[idx][j].isAssignableFrom(psa[i][j])) idx = i;
        }
        return idx;
    }

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

    /**
     * 自定义类加载器
     */
    public static final class CustomClassLoader extends ClassLoader {
        private final Function classByteFunc;

        public CustomClassLoader(Function classByteFunc) {
            super(CustomClassLoader.class.getClassLoader());
            this.classByteFunc = classByteFunc;
        }

        public CustomClassLoader() {
            this(null);
        }

        @Override
        public Class loadClass(String name) throws ClassNotFoundException {
            if (Validator.nonBlank(name)) return super.loadClass(name, true);
            return classByteFunc == null ? null : loadClass(classByteFunc.apply(null));
        }

        public Class loadClass(byte[] bytes) {
            Validator.requireNonEmpty(bytes);
            return defineClass(null, bytes, 0, bytes.length);
        }

        @Override
        protected Class findClass(String name) throws ClassNotFoundException {
            byte[] bytes;
            if (classByteFunc != null && Validator.nonEmpty(bytes = classByteFunc.apply(name)))
                return defineClass(name, bytes, 0, bytes.length);
            return super.findClass(name);
        }
    }

    public static ClassLoader getClassLoader(Function classIs) {
        if (classIs == null) return null;
        return new CustomClassLoader(name -> IOHelp.read(classIs.apply(name)));
    }

    public static ClassLoader getClassLoader(Function classIs, Function modifier) {
        if (classIs == null) return null;
        return new CustomClassLoader(name -> modifier.apply(IOHelp.read(classIs.apply(name))));
    }

    @SafeVarargs
    public static ClassLoader getClassLoader(Function classIs, Function... modifiers) {
        if (classIs == null) return null;
        return new CustomClassLoader(name -> {
            Function modifier = modifiers[0];
            for (int i = 1; i < modifiers.length; ++i) modifier = modifier.andThen(modifiers[i]);
            return modifier.apply(IOHelp.read(classIs.apply(name)));
        });
    }

    public static ClassLoader getClassLoader(String classpath) {
        return getClassLoader(t -> getLocalClassIs(classpath, t));
    }

    public static InputStream getLocalClassIs(String classpath, String name) {
        if (Validator.isBlank(name)) return null;
        String path = name.replace('.', '/') + ".class";
        try {
            return IOHelp.getBis(Validator.isBlank(classpath)
                    ? new File(FileHelp.urlToFile(Thread.currentThread().getContextClassLoader().getResource("")), path)
                    : new File(classpath, path));
        } catch (Throwable t) {
            try {
                return IOHelp.getIsFromURL(path);
            } catch (Throwable cause) {
                return null;
            }
        }
    }

    public static ClassLoader getClassLoader(String classpath, Function modifier) {
        return getClassLoader(name -> getLocalClassIs(classpath, name), modifier);
    }

    @SafeVarargs
    public static ClassLoader getClassLoader(String classpath, Function... modifiers) {
        return getClassLoader(name -> getLocalClassIs(classpath, name), modifiers);
    }

    /**
     * 获取父类(包括父类的父类)
     */
    public static  List> getSuperClasses(Class cls) {
        if (cls == null) return Collections.emptyList();
        List> result = new LinkedList<>();
        Class cur = cls.getSuperclass();
        while (cur != Object.class) {
            result.add(cur);
            cur = cur.getSuperclass();
        }
        return result.isEmpty() ? Collections.emptyList() : result;
    }

    /**
     * 获取内部类(包括内部类的内部类)
     */
    public static List> getInnerClasses(Class cls) {
        if (cls == null) return Collections.emptyList();
        List> result = new LinkedList<>();
        Queue[]> queue = new LinkedList<>();
        queue.offer(cls.getDeclaredClasses());
        while (queue.size() > 0) {
            for (Class c : queue.poll()) {
                result.add(c);
                queue.offer(c.getDeclaredClasses());
            }
        }
        return result.isEmpty() ? Collections.emptyList() : result;
    }

    /**
     * 获取指定包下指定条件的类
     */
    public static List> getClasses(Predicate> predicate, int limit, String packageName) {
        if (predicate == null || packageName == null) return Collections.emptyList();
        String packagePath = packageName.replace('.', '/');
        Enumeration resources;
        try {
            resources = Thread.currentThread().getContextClassLoader().getResources(packagePath);
        } catch (IOException e) {
            return Collections.emptyList();
        }
        packageName = "".equals(packageName) ? "" : packageName + ".";
        List> result = new LinkedList<>();
        while (resources.hasMoreElements()) {
            URL url = resources.nextElement();
            String protocol = url.getProtocol();
            if ("file".equals(protocol)) try {
                getClassesFromFile(predicate, limit, packageName, new File(URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8.name())), result);
            } catch (UnsupportedEncodingException ignored) {
            }
            else if ("jar".equals(protocol)) try {
                getClassesFromJarFile(predicate, limit, packageName, ((JarURLConnection) url.openConnection()).getJarFile(), packagePath, result);
            } catch (IOException ignored) {
            }
            if (limit > 0 && result.size() >= limit) break;
        }
        return result.isEmpty() ? Collections.emptyList() : result;
    }

    private static void getClassesFromFile(Predicate> predicate, int limit, String packageName, File file, List> result) {
        File[] files = file.listFiles(f -> f.isDirectory() || f.getName().endsWith(".class"));
        if (Validator.isEmpty(files)) return;
        for (File f : files) {
            if (f.isDirectory()) getClassesFromFile(predicate, limit, packageName + f.getName() + ".", f, result);
            else try {
                Class forName = forName(packageName + f.getName().substring(0, f.getName().length() - 6), false, null);
                if (predicate.test(forName)) {
                    result.add(forName);
                    if (limit > 0 && result.size() >= limit) break;
                }
            } catch (Throwable ignored) {
            }
        }
    }

    private static void getClassesFromJarFile(Predicate> predicate, int limit, String packageName, JarFile jarFile, String packagePath, List> result) {
        Enumeration entries = jarFile.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String name = entry.getName();
            name = name.charAt(0) == '/' ? name.substring(1) : name;
            if (name.startsWith(packagePath)) {
                int last = name.lastIndexOf('/');
                packageName = last != -1 ? name.substring(0, last).replace('/', '.') + '.' : packageName;
                if (name.endsWith(".class") && !entry.isDirectory()) try {
                    Class forName = forName(packageName + name.substring(packageName.length(), name.length() - 6), false, null);
                    if (predicate.test(forName)) {
                        result.add(forName);
                        if (limit > 0 && result.size() >= limit) break;
                    }
                } catch (Throwable ignored) {
                }
            }
        }
    }

    public static List> getClasses(Predicate> predicate, int limit) {
        return getClasses(predicate, limit, "");
    }

    public static List> getClasses(Predicate> predicate, String packageName) {
        return getClasses(predicate, 0, packageName);
    }

    public static List> getClasses(Predicate> predicate) {
        return getClasses(predicate, 0, "");
    }

    public static List> getClasses(Predicate> predicate, int limit, String... packageNames) {
        if (predicate == null) return Collections.emptyList();
        List> result = new LinkedList<>();
        for (String name : packageNames) {
            if (Validator.isBlank(name)) continue;
            if (limit > 0) {
                if (result.size() >= limit) break;
                result.addAll(getClasses(predicate, limit - result.size(), name));
            } else result.addAll(getClasses(predicate, limit, name));
        }
        return result.isEmpty() ? Collections.emptyList() : result;
    }

    public static List> getClasses(Predicate> predicate, String... packageNames) {
        return getClasses(predicate, 0, packageNames);
    }

    /**
     * 获取指定包下指定条件的子类或实现类
     */
    public static List> getChildClasses(Class cls, Predicate> predicate, int limit, String packageName) {
        if (cls == null || predicate == null || packageName == null) return Collections.emptyList();
        return getClasses(
                c -> !Modifier.isAbstract(c.getModifiers())
                        && !Modifier.isInterface(c.getModifiers())
                        && cls.isAssignableFrom(c)
                        && predicate.test(c),
                limit,
                packageName
        );
    }

    public static List> getChildClasses(Class cls, Predicate> predicate, int limit) {
        return getChildClasses(cls, predicate, limit, "");
    }

    public static List> getChildClasses(Class cls, Predicate> predicate, String packageName) {
        return getChildClasses(cls, predicate, 0, packageName);
    }

    public static List> getChildClasses(Class cls, Predicate> predicate) {
        return getChildClasses(cls, predicate, 0, "");
    }

    public static List> getChildClasses(Class cls, Predicate> predicate, int limit, String... packageNames) {
        if (cls == null || predicate == null) return Collections.emptyList();
        return getClasses(
                c -> !Modifier.isAbstract(c.getModifiers())
                        && !Modifier.isInterface(c.getModifiers())
                        && cls.isAssignableFrom(c)
                        && predicate.test(c),
                limit,
                packageNames
        );
    }

    public static List> getChildClasses(Class cls, Predicate> predicate, String... packageNames) {
        return getChildClasses(cls, predicate, 0, packageNames);
    }

    public static List> getChildClasses(Class cls, int limit, String packageName) {
        return getChildClasses(cls, c -> true, limit, packageName);
    }

    public static List> getChildClasses(Class cls, int limit) {
        return getChildClasses(cls, limit, "");
    }

    public static List> getChildClasses(Class cls, String packageName) {
        return getChildClasses(cls, 0, packageName);
    }

    public static List> getChildClasses(Class cls) {
        return getChildClasses(cls, 0, "");
    }

    public static  T newObject(Class cls) {
        if (cls == null) return null;
        if (Modifier.isAbstract(cls.getModifiers()) || Modifier.isInterface(cls.getModifiers()))
            return (T) getChildClasses(cls).stream().map(AccessibleHelp::newObject).filter(Objects::nonNull).findFirst().orElse(null);
        if (isPrimitive(cls)) {
            if (cls == boolean.class) return (T) Boolean.FALSE;
            if (cls == byte.class) return (T) Byte.valueOf((byte) 0);
            if (cls == char.class) return (T) Character.valueOf((char) 0);
            if (cls == short.class) return (T) Short.valueOf((short) 0);
            if (cls == int.class) return (T) Integer.valueOf(0);
            if (cls == long.class) return (T) Long.valueOf(0);
            if (cls == double.class) return (T) Double.valueOf(0d);
            if (cls == float.class) return (T) Float.valueOf(0f);
            throw PRException.impossible();
        }
        if (cls == void.class || cls == Void.class) return null;
        List> constructors = constructors(cls, c -> c.getParameterCount() == 0, 1);
        if (constructors.isEmpty()) return null;
        try {
            return ((Constructor) constructors.get(0)).newInstance();
        } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
            return null;
        }
    }

    public static  T newObject(Class cls, Object initarg) {
        if (cls == null) return null;
        if (Modifier.isAbstract(cls.getModifiers()) || Modifier.isInterface(cls.getModifiers()))
            return (T) getChildClasses(cls).stream().map(c -> newObject(c, initarg)).filter(Objects::nonNull).findFirst().orElse(null);
        for (Constructor constructor : constructors(cls, c -> c.getParameterCount() == 1)) {
            try {
                return (T) constructor.newInstance(initarg);
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException ignored) {
            }
        }
        return null;
    }

    public static  T newObject(Class cls, Object... initargs) {
        if (cls == null) return null;
        if (Modifier.isAbstract(cls.getModifiers()) || Modifier.isInterface(cls.getModifiers()))
            return (T) getChildClasses(cls).stream().map(c -> newObject(c, initargs)).filter(Objects::nonNull).findFirst().orElse(null);
        for (Constructor constructor : constructors(cls, c -> c.getParameterCount() == initargs.length)) {
            try {
                return (T) constructor.newInstance(initargs);
            } catch (InstantiationException | IllegalAccessException | InvocationTargetException ignored) {
            }
        }
        return null;
    }

    public static  T newObject(String className, ClassLoader classLoader) {
        try {
            return newObject(classLoader == null ? (Class) forName(className, true) : (Class) classLoader.loadClass(className));
        } catch (Throwable t) {
            return null;
        }
    }

    public static  T newObject(String className, ClassLoader classLoader, Object initarg) {
        try {
            return newObject(classLoader == null ? (Class) forName(className, true) : (Class) classLoader.loadClass(className), initarg);
        } catch (Throwable t) {
            return null;
        }
    }

    public static  T newObject(String className, ClassLoader classLoader, Object... initargs) {
        try {
            return newObject(classLoader == null ? (Class) forName(className, true) : (Class) classLoader.loadClass(className), initargs);
        } catch (Throwable t) {
            return null;
        }
    }

    public static  T newObject(String className, String classpath) {
        return newObject(className, getClassLoader(classpath));
    }

    public static  T newObject(String className, String classpath, Object initarg) {
        return newObject(className, getClassLoader(classpath), initarg);
    }

    public static  T newObject(String className, String classpath, Object... initargs) {
        return newObject(className, getClassLoader(classpath), initargs);
    }

    public static  T cloneObject(T t) {
        if (t == null) return null;
        Class cls = (Class) t.getClass();
        T obj;
        Objects.requireNonNull(obj = newObject(cls));
        fields(cls).parallelStream().forEach(f -> setField(f, obj, getField(f, t)));
        return obj;
    }

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

    public static void setField(Field field, Object obj, Object val) {
        try {
            field.set(obj, val);
        } catch (IllegalAccessException ignored) {
        }
    }

    private static final MapCache, List> ENUM_CACHE = new MapCache<>(128);

    /**
     * 获取枚举类的所有实例
     */
    public static > List enumSet(Class cls) {
        if (cls == null || !Enum.class.isAssignableFrom(cls)) return Collections.emptyList();
        List result = (List) ENUM_CACHE.get(cls);
        if (result != null) return result;
        EnumSet enumSet = null;
        try {
            enumSet = EnumSet.allOf((Class) cls);
        } catch (Throwable ignored) {
        }
        if (enumSet == null) {
            ENUM_CACHE.put(cls, Collections.emptyList());
            return Collections.emptyList();
        }
        result = ToList.collectArray(enumSet.stream());
        ENUM_CACHE.put(cls, result);
        return result;
    }

    /**
     * 获取枚举类或接口的实现枚举类的所有实例
     */
    public static  List enumSets(Class cls) {
        if (cls == null) return Collections.emptyList();
        List result = (List) ENUM_CACHE.get(cls);
        if (result != null) return result;
        if (!Modifier.isInterface(cls.getModifiers())) return (List) enumSet(cls);
        result = ToList.collectArray(getChildClasses(cls).parallelStream().map(AccessibleHelp::enumSet).filter(Validator::nonEmpty).flatMap(Collection::stream).map(t -> (S) t));
        ENUM_CACHE.put(cls, result);
        return result;
    }

    private static final LTST> ENUM_CLASS_ST = LTST.of();

    /**
     * 根据全限定名或类名获取枚举类的所有实例
     */
    public static , T extends IEnum> List enumSet(String typeName) {
        if (Validator.isBlank(typeName)) return Collections.emptyList();
        char[] chars = typeName.toCharArray();
        Class cls = ENUM_CLASS_ST.get(chars);

        if (cls == null) {
            //全限定名
            if (typeName.indexOf(".") > 0) cls = AccessibleHelp.forName(typeName);
            else {
                //类名
                List> classes = AccessibleHelp.getClasses(c -> IEnum.class.isAssignableFrom(c) && c.getSimpleName().equals(typeName), 1);
                if (classes.isEmpty()) cls = null;
                else cls = classes.get(0);
            }
            if (cls == null || !IEnum.class.isAssignableFrom(cls)) cls = NullConstant.CLASS;
            ENUM_CLASS_ST.put(chars, cls);
        }

        if (cls == NullConstant.CLASS) return Collections.emptyList();

        List ts = enumSet(cls);
        if (ts.isEmpty()) return Collections.emptyList();
        return ToList.explicitCollect(ts.stream().map(e -> (T) e), ts.size());
    }

    /**
     * 通过反射执行方法
     */
    public static  U invoke(T receiver, String methodName) {
        Objects.requireNonNull(receiver);
        Validator.requireNonBlank(methodName);
        try {
            Method method = getMethod(receiver.getClass(), methodName);
            if (method.getReturnType() == void.class) method.invoke(receiver);
            else return (U) method.invoke(receiver);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw PRException.of(e);
        }
        return null;
    }

    public static  U invoke(T receiver, String methodName, Class ptype, Object arg) {
        Validator.requireNonAnyNull(receiver, ptype);
        Validator.requireNonBlank(methodName);
        try {
            Method method = getMethod(receiver.getClass(), methodName, ptype);
            if (method.getReturnType() == void.class) method.invoke(receiver, arg);
            else return (U) method.invoke(receiver, arg);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw PRException.of(e);
        }
        return null;
    }

    public static  U invoke(T receiver, String methodName, Class[] ptypes, Object[] args) {
        Validator.requireNonAnyNull(receiver, ptypes, args);
        Validator.requireNonBlank(methodName);
        Validator.requireNon(ptypes.length != args.length);
        try {
            Method method = getMethod(receiver.getClass(), methodName, ptypes);
            if (method.getReturnType() == void.class) method.invoke(receiver, args);
            else return (U) method.invoke(receiver, args);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw PRException.of(e);
        }
        return null;
    }

    public static  T invoke(String name, ClassLoader classLoader, String methodName) {
        return invoke(newObject(name, classLoader), methodName);
    }

    public static  T invoke(String name, ClassLoader classLoader, String methodName, Class ptype, Object arg) {
        return invoke(newObject(name, classLoader), methodName, ptype, arg);
    }

    public static  T invoke(String name, ClassLoader classLoader, String methodName, Class[] ptypes, Object[] args) {
        return invoke(newObject(name, classLoader), methodName, ptypes, args);
    }

    public static  U invoke(T receiver, String methodName, String limit, Class rtype) {
        Objects.requireNonNull(receiver);
        Validator.requireNonBlank(methodName);
        MethodHandle methodHandle = getMethodHandle(limit, MethodHandles.lookup(), receiver, methodName, MethodType.methodType(rtype == null ? void.class : rtype));
        try {
            if (rtype == null || rtype == void.class) methodHandle.invokeWithArguments();
            else return (U) methodHandle.invokeWithArguments();
        } catch (Throwable t) {
            return invoke(receiver, methodName);
        }
        return null;
    }

    private static  MethodHandle getMethodHandle(String limit, MethodHandles.Lookup lookup, T receiver, String name, MethodType type) {
        try {
            if ("static".equals(limit)) return lookup.findStatic(receiver.getClass(), name, type);
            try {
                //"virtual"
                return lookup.findVirtual(receiver.getClass(), name, type).bindTo(receiver);
            } catch (NoSuchMethodException e) {
                throw PRException.of(ServerFailure.NoSuchMethodException);
            } catch (IllegalAccessException e) {
                return lookup.findStatic(receiver.getClass(), name, type);
            }
        } catch (Throwable t) {
            throw PRException.of(t);
        }
    }

    public static  U invoke(T receiver, String methodName, Class rtype) {
        return invoke(receiver, methodName, "", rtype);
    }

    public static  U invoke(T receiver, String methodName, String limit, Class rtype, Class ptype, Object arg) {
        Validator.requireNonAnyNull(receiver, ptype);
        Validator.requireNonBlank(methodName);
        MethodHandle methodHandle = getMethodHandle(limit, MethodHandles.lookup(), receiver, methodName, MethodType.methodType(rtype == null ? void.class : rtype, ptype));
        try {
            if (rtype == null || rtype == void.class) methodHandle.invokeWithArguments(arg);
            else return (U) methodHandle.invokeWithArguments(arg);
        } catch (Throwable t) {
            return invoke(receiver, methodName, ptype, arg);
        }
        return null;
    }

    public static  U invoke(T receiver, String methodName, Class rtype, Class ptype, Object arg) {
        return invoke(receiver, methodName, null, rtype, ptype, arg);
    }

    public static  U invoke(T receiver, String methodName, String limit, Class rtype, Class[] ptypes, Object[] args) {
        Validator.requireNonAnyNull(receiver, ptypes, args);
        Validator.requireNonBlank(methodName);
        Validator.requireNon(ptypes.length != args.length);
        MethodHandle methodHandle = getMethodHandle(limit, MethodHandles.lookup(), receiver, methodName, MethodType.methodType(rtype == null ? void.class : rtype, ptypes));
        try {
            if (rtype == null || rtype == void.class) methodHandle.invokeWithArguments(args);
            else return (U) methodHandle.invokeWithArguments(args);
        } catch (Throwable t) {
            return invoke(receiver, methodName, ptypes, args);
        }
        return null;
    }

    public static  U invoke(T receiver, String methodName, Class rtype, Class[] ptypes, Object[] args) {
        return invoke(receiver, methodName, null, rtype, ptypes, args);
    }

    public static  T invoke(String name, ClassLoader classLoader, String methodName, String limit, Class rtype) {
        return invoke(newObject(name, classLoader), methodName, limit, rtype);
    }

    public static  T invoke(String name, ClassLoader classLoader, String methodName, Class rtype) {
        return invoke(newObject(name, classLoader), methodName, "", rtype);
    }

    public static  T invoke(String name, ClassLoader classLoader, String methodName, String limit, Class rtype, Class ptype, Object arg) {
        return invoke(newObject(name, classLoader), methodName, limit, rtype, ptype, arg);
    }

    public static  T invoke(String name, ClassLoader classLoader, String methodName, Class rtype, Class ptype, Object arg) {
        return invoke(newObject(name, classLoader), methodName, null, rtype, ptype, arg);
    }

    public static  T invoke(String name, ClassLoader classLoader, String methodName, String limit, Class rtype, Class[] ptypes, Object[] args) {
        return invoke(newObject(name, classLoader), methodName, limit, rtype, ptypes, args);
    }

    public static  T invoke(String name, ClassLoader classLoader, String methodName, Class rtype, Class[] ptypes, Object[] args) {
        return invoke(newObject(name, classLoader), methodName, null, rtype, ptypes, args);
    }

    public static boolean isAnnotationPresent(AnnotatedElement a, Class c) {
        return a != null && c != null && a.isAnnotationPresent(c);
    }

    public static boolean nonAnnotationPresent(AnnotatedElement a, Class c) {
        return !isAnnotationPresent(a, c);
    }

    public static boolean isAnyAnnotationPresent(AnnotatedElement a, Class c1, Class c2) {
        return isAnnotationPresent(a, c1) || isAnnotationPresent(a, c2);
    }

    public static boolean nonAnyAnnotationPresent(AnnotatedElement a, Class c1, Class c2) {
        return !isAnyAnnotationPresent(a, c1, c2);
    }

    public static boolean isAnyAnnotationPresent(AnnotatedElement a, Class... cs) {
        return Arrays.stream(cs).parallel().anyMatch(c -> isAnnotationPresent(a, c));
    }

    public static boolean nonAnyAnnotationPresent(AnnotatedElement a, Class... cs) {
        return !isAnyAnnotationPresent(a, cs);
    }

    public static boolean isAllAnnotationPresent(AnnotatedElement a, Class c1, Class c2) {
        return isAnnotationPresent(a, c1) && isAnnotationPresent(a, c2);
    }

    public static boolean nonAllAnnotationPresent(AnnotatedElement a, Class c1, Class c2) {
        return !isAllAnnotationPresent(a, c1, c2);
    }

    public static boolean isAllAnnotationPresent(AnnotatedElement a, Class... cs) {
        return Arrays.stream(cs).parallel().allMatch(c -> isAnnotationPresent(a, c));
    }

    public static boolean nonAllAnnotationPresent(AnnotatedElement a, Class... cs) {
        return !isAllAnnotationPresent(a, cs);
    }

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

    /**
     * 获取具有指定注解条件的属性值
     */
    public static  T getFieldByAnnotation(Object obj, Class cls, Predicate predicate) {
        return getField(obj, f -> isAnnotationPresent(f, cls) && (predicate == null || predicate.test(f.getAnnotation(cls))));
    }

    public static  T getFieldByAnnotation(Object obj, Class cls) {
        return getField(obj, f -> isAnnotationPresent(f, cls));
    }

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

    /**
     * 设置具有指定注解条件的属性
     */
    public static  void setFieldByAnnotation(Object obj, Class cls, Predicate predicate, Object value) {
        setField(obj, f -> isAnnotationPresent(f, cls) && (predicate == null || predicate.test(f.getAnnotation(cls))), value);
    }

    public static  void setFieldByAnnotation(Object obj, Class cls, Object value) {
        setField(obj, f -> isAnnotationPresent(f, cls), value);
    }
}