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

com.feingto.cloud.kit.ClassKit Maven / Gradle / Ivy

There is a newer version: 2.5.2.RELEASE
Show newest version
package com.feingto.cloud.kit;

import com.google.common.collect.Lists;
import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

/**
 * Class 工具类
 *
 * @author longfei
 */
public class ClassKit {
    /**
     * 判断类是否存在
     *
     * @param className 类名
     * @return boolean
     */
    public static boolean isExist(String className) {
        Class clazz = null;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException ignored) {
        }
        return Objects.nonNull(clazz);
    }

    /**
     * 判断是否基本类型
     *
     * @param clazz Class
     * @return boolean
     */
    public static boolean isJavaBasicType(Class clazz) {
        return Objects.nonNull(clazz) && (clazz.isPrimitive() || Number.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz) || Boolean.class.isAssignableFrom(clazz) || CharSequence.class.isAssignableFrom(clazz) || Enum.class.isAssignableFrom(clazz) || Date.class.isAssignableFrom(clazz) || Calendar.class.isAssignableFrom(clazz));
    }

    /**
     * 判断指定的类是否为Collection(或者其子类或者其子接口)
     *
     * @param clazz Class
     * @return boolean
     */
    public static boolean isCollection(Class clazz) {
        return Objects.nonNull(clazz) && Collection.class.isAssignableFrom(clazz);
    }

    /**
     * 判断指定的类是否为Map(或者其子类或者其子接口)
     *
     * @param clazz Class
     * @return boolean
     */
    public static boolean isMap(Class clazz) {
        return Objects.nonNull(clazz) && Map.class.isAssignableFrom(clazz);
    }

    /**
     * 判断指定的类是否为Java基本类型的数组
     *
     * @param clazz Class
     * @return boolean
     */
    public static boolean isPrimitiveArray(Class clazz) {
        return (clazz == byte[].class || (clazz == short[].class || (clazz == int[].class || (clazz == long[].class || (clazz == char[].class || (clazz == float[].class || (clazz == double[].class || clazz == boolean[].class)))))));
    }

    /**
     * 判断指定的类是否为Java基本类型的数组
     *
     * @param clazz Class
     * @return boolean
     */
    public static boolean isPrimitiveWrapperArray(Class clazz) {
        return (clazz == Byte[].class || (clazz == Short[].class || (clazz == Integer[].class || (clazz == Long[].class || (clazz == Character[].class || (clazz == Float[].class || (clazz == Double[].class || clazz == Boolean[].class)))))));
    }

    /**
     * 获取包括该类本身但不包含java.lang.Object的所有超类
     *
     * @param clazz Class
     * @return 超类数组
     */
    public static Class[] getAllSupperClass(Class clazz) {
        List> classes = new ArrayList<>();
        getAllSupperClass(classes, clazz);
        return classes.toArray(new Class[0]);
    }

    private static void getAllSupperClass(List> classes, Class clazz) {
        if (!clazz.equals(Object.class)) {
            classes.add(clazz);
            getAllSupperClass(classes, clazz.getSuperclass());
        }
    }

    /**
     * 获取该类所有实现的接口数组
     *
     * @param clazz Class
     * @return 该类所有的实现接口数组
     */
    public static Class[] getAllInterface(Class clazz) {
        List> classes = new ArrayList<>();
        Class[] interfaces = clazz.getInterfaces();
        for (Class interfaceClazz : interfaces) {
            classes.add(interfaceClazz);
            getAllSupperInterface(classes, interfaceClazz);
        }
        return classes.toArray(new Class[0]);
    }

    private static void getAllSupperInterface(List> classes, Class clazz) {
        if (!clazz.equals(Object.class)) {
            Class[] interfaces = clazz.getInterfaces();
            for (Class interfaceClazz : interfaces) {
                classes.add(interfaceClazz);
                getAllSupperInterface(classes, interfaceClazz);
            }
        }
    }

    /**
     * 获取包括该类本身以及所有超类(不含java.lang.Object)和实现的接口中定义的属性
     *
     * @param clazz Class
     * @return 属性数组
     */
    public static Field[] getAllField(Class clazz) {
        List fieldList = new ArrayList<>();
        Class[] supperInterfaces = getAllSupperClass(clazz);
        for (Class aClazz : supperInterfaces) {
            fieldList.addAll(Lists.newArrayList(aClazz.getDeclaredFields()));
        }

        supperInterfaces = getAllInterface(clazz);
        for (Class aInterface : supperInterfaces) {
            fieldList.addAll(Lists.newArrayList(aInterface.getDeclaredFields()));
        }

        return fieldList.toArray(new Field[0]);
    }

    /**
     * 获取该类中所有字段
     *
     * @param clazz Class
     * @return 属性数组
     */
    public static Field[] getFields(Class clazz) {
        return new ArrayList<>(Lists.newArrayList(clazz.getDeclaredFields())).toArray(new Field[0]);
    }

    /**
     * 得到方法参数名称和方法参数值
     * 注:类里面同名方法会解析第一个
     *
     * @param clazz      当前类
     * @param clazzName  方法类名
     * @param methodName 方法名
     * @param args       方法参数
     * @return Map
     */
    public static Map getFieldMap(Class clazz, String clazzName, String methodName, Object[] args) throws NotFoundException {
        Map map = new HashMap<>();
        ClassPool pool = ClassPool.getDefault();
        ClassClassPath classPath = new ClassClassPath(clazz);
        pool.insertClassPath(classPath);
        CtClass cc = pool.get(clazzName);
        CtMethod cm = cc.getDeclaredMethod(methodName);
        MethodInfo methodInfo = cm.getMethodInfo();
        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
        if (Objects.isNull(attr)) {
            throw new RuntimeException();
        }
        int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
        for (int i = 0; i < cm.getParameterTypes().length; i++) {
            map.put(attr.variableName(i + pos), args[i]);
        }
        return map;
    }

    /**
     * 获取启用元注解clazz的全部类
     *
     * @param packageName 包路径
     * @param clazz       元注解类
     * @return 类集合
     */
    public static Set> getClassesByAnnotation(String packageName, Class clazz) {
        return getClasses(packageName).stream()
                .filter(clz -> clz.isAnnotationPresent(clazz))
                .collect(Collectors.toSet());
    }

    /**
     * 从包package中获取所有的Class
     *
     * @param packageName 包路径
     * @return 类集合
     */
    public static Set> getClasses(String packageName) {
        // 第一个class类的集合
        Set> classes = new LinkedHashSet<>();
        // 获取包的名字, 并进行替换
        String packageDirName = packageName.replace('.', '/');
        // 定义一个枚举的集合, 并进行循环来处理这个目录下的things
        Enumeration dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                // 如果是以文件的形式保存在服务器上
                if ("file".equals(protocol)) {
                    // 获取包的物理路径
                    String filePath = EncodeKit.urlDecode(url.getFile());
                    // 以文件的方式扫描整个包下的文件, 并添加到集合中
                    getClassesByPackage(packageName, filePath, true, classes);
                } else if ("jar".equals(protocol)) {
                    // 如果是jar包文件, 定义一个JarFile
                    JarFile jar;
                    try {
                        // 获取jar
                        jar = ((JarURLConnection) url.openConnection()).getJarFile();
                        // 从jar包, 得到一个枚举类
                        Enumeration entries = jar.entries();
                        // 同样的进行循环迭代
                        while (entries.hasMoreElements()) {
                            // 获取jar里的一个实体, 可以是目录和一些jar包里的其他文件, 如META-INF等文件
                            JarEntry entry = entries.nextElement();
                            String name = entry.getName();
                            if (name.charAt(0) == '/') {
                                name = name.substring(1);
                            }
                            // 如果前半部分和定义的包名相同
                            if (name.startsWith(packageDirName)) {
                                int idx = name.lastIndexOf('/');
                                // 如果以"/"结尾, 则是一个包
                                if (idx != -1) {
                                    // 获取包名, 把"/"替换成"."
                                    packageName = name.substring(0, idx).replace('/', '.');
                                }
                                // 如果是一个.class文件, 并且不是目录
                                if (name.endsWith(".class") && !entry.isDirectory()) {
                                    // 去掉后面的".class", 获取真正的类名
                                    String className = name.substring(packageName.length() + 1, name.length() - 6);
                                    try {
                                        classes.add(Class.forName(packageName + '.' + className));
                                    } catch (ClassNotFoundException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classes;
    }

    /**
     * 以文件的形式扫描包下的所有Class并加载到上下文
     *
     * @param packageName 包名
     * @param packagePath 存放类文件的包目录路径
     * @param recursive   是否循环迭代
     * @param classes     类集合
     */
    public static void getClassesByPackage(String packageName, String packagePath, final boolean recursive, Set> classes) {
        File dir = new File(packagePath);
        if (dir.exists() && dir.isDirectory()) {
            // 自定义过滤规则, 如果可以循环(包含子目录)或以.class结尾的文件(编译好的java类文件)
            File[] dirfiles = dir.listFiles(file -> recursive && file.isDirectory() || file.getName().endsWith(".class"));
            if (Objects.nonNull(dirfiles)) {
                for (File file : dirfiles) {
                    if (file.isDirectory()) {
                        getClassesByPackage(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, classes);
                    } else {
                        // 如果是java类文件, 去掉后面的.class, 只留下类名
                        String className = file.getName().substring(0, file.getName().length() - 6);
                        try {
                            classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    /**
     * 读取目录下的jar文件中指定目录下面的全部class
     *
     * @param packagePath jar文件目录路径
     * @param packageName jar文件里的包名:格式"/xxx/yyy"
     * @return 类集合
     */
    public static Set> getClassesByJar(String packagePath, String packageName) {
        Set> classes = new HashSet<>();
        File dir = new File(packagePath);
        if (dir.exists() && dir.isDirectory()) {
            File[] dirfiles = dir.listFiles(file -> file.getName().endsWith(".jar"));
            if (Objects.nonNull(dirfiles)) {
                for (File file : dirfiles) {
                    classes.addAll(getClassesByJar(file, packageName));
                }
            }
        }
        return classes;
    }

    /**
     * 读取jar文件中指定目录下面的全部class
     *
     * @param file        jar文件
     * @param packageName jar文件里的包名"com.feingto.cloud.admin.plugins"
     * @return 类集合
     */
    public static Set> getClassesByJar(File file, String packageName) {
        packageName = packageName.replace('.', '/');
        Set> classes = new HashSet<>();
        try {
            JarFile jarFile = new JarFile(file);
            List entryList = new ArrayList<>();
            Enumeration entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                if (entry.getName().endsWith(".class") && (
                        StringUtils.hasText(packageName) && entry.getName().startsWith(packageName)
                                || StringUtils.isEmpty(packageName)
                )) {
                    entryList.add(entry);
                }
            }
            for (JarEntry entry : entryList) {
                String className = entry.getName().replace('/', '.');
                if (className.endsWith(".class") && !entry.isDirectory()) {
                    className = className.substring(0, className.length() - 6);
                    try {
                        classes.add(Thread.currentThread().getContextClassLoader().loadClass(className));
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classes;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy