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

com.github.jaemon.dinger.utils.PackageUtils Maven / Gradle / Ivy

The newest version!
/*
 * Copyright ©2015-2023 Jaemon. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.jaemon.dinger.utils;

import com.github.jaemon.dinger.core.spring.ApplicationHome;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;

/**
 * PackageUtils
 *
 * @author Jaemon
 * @since 1.0
 */
public class PackageUtils {
    private static final Logger log = LoggerFactory.getLogger(PackageUtils.class);
    private static final ApplicationHome applicationHome = new ApplicationHome();

    public static final String SPOT = ".";
    public static final String SLANT = "/";
    private static final String JAR_FILE_SUFFIX = ".jar";

    private PackageUtils() {}

    /**
     * 获取指定包下所有的类
     *
     * @param packageName packageName
     * @param classNames classNames
     * @param isInterface isInterface
     * @param filterAnnotations filterAnnotations
     */
    public static void classNames(
            String packageName,
            List> classNames,
            boolean isInterface,
            Class... filterAnnotations
    ) {
        if (DingerUtils.isEmpty(packageName)) {
            return;
        }
        File applicationHomeSource = applicationHome.getSource();
        if (applicationHomeSource != null) {
            String absolutePath = applicationHomeSource.getAbsolutePath();
            if (absolutePath.endsWith(JAR_FILE_SUFFIX)) {
                jarClassNames(absolutePath, packageName, classNames, isInterface, filterAnnotations);
                return;
            }
        }

        forClassNames(packageName, classNames, isInterface, filterAnnotations);
    }

    /**
     * forClassNames
     *
     * @param packageName packageName
     * @param classNames classNames
     * @param isInterface isInterface
     * @param filterAnnotations filterAnnotations
     */
    public static void forClassNames(
            String packageName,
            List> classNames,
            boolean isInterface,
            Class... filterAnnotations)
    {
        // 处理过滤掉dingerScan和Dinger解析时重复的类
        List repeatCheck = classNames.stream().map(e -> e.getName()).collect(Collectors.toList());
        try {
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            URL url = classLoader.getResource(packageName.replace(SPOT, SLANT));
            // packageName is not exist
            if (url == null) {
                if (log.isDebugEnabled()) {
                    log.debug("packageName={} is not exist.", packageName);
                }
                return;
            }
            URI uri = url.toURI();
            File file = new File(uri);
            File[] files = file.listFiles();

            for (File f : files) {
                String name = f.getName();

                if (f.isFile()) {
                    String className = packageName + SPOT + name.substring(0, name.lastIndexOf(SPOT));
                    // bugfix gitee#I29N15
                    Class clazz = classLoader.loadClass(className);
                    // clazz.isInterface(): XXXDinger.java must be an interface
                    boolean check = isInterface ? clazz.isInterface() : true;
                    if (check) {
                        if (filterAnnotations.length > 0) {
                            for (Class annotation : filterAnnotations) {
                                if (clazz.isAnnotationPresent(annotation)) {
                                    if (!repeatCheck.contains(className)) {
                                        classNames.add(clazz);
                                    }
                                    break;
                                }
                            }
                        } else {
                            if (!repeatCheck.contains(className)) {
                                classNames.add(clazz);
                            }
                        }
                    } else {
                        if (log.isTraceEnabled()) {
                            log.trace("skip class {}.", clazz.getName());
                        }
                    }

                } else {
                    forClassNames(packageName + SPOT + name, classNames, isInterface, filterAnnotations);
                }
            }
        } catch (Exception ex) {
            if (log.isDebugEnabled()) {
                log.error("when analysis packageName={} catch exception=",
                        packageName, ex);
            } else {
                log.warn("when analysis packageName={} catch exception={}.",
                        packageName, ex.getMessage());
            }
        }
    }

    /**
     * jarClassNames
     *
     * @param jarPath jarPath
     * @param packageName packageName
     * @param classNames classNames
     * @param isInterface isInterface
     * @param filterAnnotations filterAnnotations
     */
    public static void jarClassNames(
            String jarPath,
            String packageName,
            List> classNames,
            boolean isInterface,
            Class... filterAnnotations)
    {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // 处理过滤掉dingerScan和Dinger解析时重复的类
        List repeatCheck = classNames.stream().map(e -> e.getName()).collect(Collectors.toList());
        packageName = packageName.replace(SPOT, SLANT);
        try {
            JarFile jarFile = new JarFile(jarPath);
            Enumeration entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry jarEntry = (JarEntry) entries.nextElement();
                String namePath = jarEntry.getName();
                if (namePath.contains(packageName) &&
                        namePath.endsWith(".class") /*&& !namePath.contains("$")*/) {
                    namePath = namePath.substring(namePath.indexOf(packageName));
                    String className = namePath.replaceAll("/", ".").replace(".class", "");
                    // bugfix gitee#I29N15
                    Class clazz = classLoader.loadClass(className);
                    boolean check = isInterface ? clazz.isInterface() : true;
                    if (check) {
                        if (filterAnnotations.length > 0) {
                            for (Class annotation : filterAnnotations) {
                                if (clazz.isAnnotationPresent(annotation)) {
                                    if (!repeatCheck.contains(className)) {
                                        classNames.add(clazz);
                                    }
                                    break;
                                }
                            }
                        } else {
                            if (!repeatCheck.contains(className)) {
                                classNames.add(clazz);
                            }
                        }
                    } else {
                        if (log.isTraceEnabled()) {
                            log.trace("skip class {}.", clazz.getName());
                        }
                    }
                }
            }
        } catch (Exception ex) {
            log.error("when analysis packageName={} catch exception=",
                    packageName, ex);
        }
    }

    private static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";

    /**
     * doScan
     *
     * @param packageName packageName
     * @param classNames classNames
     * @param filterAnnotations filterAnnotations
     * @throws Exception ex
     */
    private static void doScan(
            String packageName,
            List> classNames,
            Class... filterAnnotations)
    {
        List repeatCheck = classNames.stream().map(e -> e.getName()).collect(Collectors.toList());
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                packageName.replace(SPOT, SLANT) + '/' + DEFAULT_RESOURCE_PATTERN;
        try {
            Resource[] resources = new PathMatchingResourcePatternResolver().getResources(packageSearchPath);
            for (Resource resource : resources) {
                File f = resource.getFile();
                String name = f.getName();

                if (f.isFile()) {
                    String className = packageName + SPOT + name.substring(0, name.lastIndexOf(SPOT));
                    Class clazz = Class.forName(className);
                    if (filterAnnotations.length > 0) {
                        for (Class annotation : filterAnnotations) {
                            if (clazz.isAnnotationPresent(annotation)) {
                                if (!repeatCheck.contains(className)) {
                                    classNames.add(clazz);
                                }
                                break;
                            }
                        }
                    } else {
                        if (!repeatCheck.contains(className)) {
                            classNames.add(clazz);
                        }
                    }
                } else {
                    doScan(packageName + SPOT + name, classNames, filterAnnotations);
                }
            }
        } catch (Exception ex) {
            log.error("when analysis packageName={} catch exception=",
                    packageName, ex);
        }
    }


    public static void main(String[] args) {
        List> classNames = new ArrayList<>();
        classNames("com.jaemon.dinger", classNames, false);

        classNames.forEach(e -> System.out.println(e.getName()));

        System.out.println(classNames.size());
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy