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

io.microsphere.io.scanner.SimpleClassScanner Maven / Gradle / Ivy

There is a newer version: 0.0.9
Show newest version
/**
 *
 */
package io.microsphere.io.scanner;

import io.microsphere.filter.FilterUtils;
import io.microsphere.filter.PackageNameClassNameFilter;
import io.microsphere.lang.ClassDataRepository;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

import static io.microsphere.lang.function.Streams.filterAll;
import static io.microsphere.net.URLUtils.resolveArchiveFile;
import static io.microsphere.util.ClassLoaderUtils.ResourceType.PACKAGE;
import static io.microsphere.util.ClassLoaderUtils.findLoadedClass;
import static io.microsphere.util.ClassLoaderUtils.getResources;
import static io.microsphere.util.ClassLoaderUtils.loadClass;
import static io.microsphere.util.ClassUtils.findClassNamesInClassPath;
import static io.microsphere.util.StringUtils.substringBefore;
import static java.util.Collections.unmodifiableSet;

/**
 * Simple {@link Class} Scanner
 *
 * @author Mercy
 * @version 1.0.0
 * @see SimpleClassScanner
 * @since 1.0.0
 */
public class SimpleClassScanner {

    /**
     * Singleton
     */
    public final static SimpleClassScanner INSTANCE = new SimpleClassScanner();

    public SimpleClassScanner() {
    }

    /**
     * It's equal to invoke {@link #scan(ClassLoader, String, boolean, boolean)} method with
     * requiredLoad=false and recursive=false
     *
     * @param classLoader {@link ClassLoader}
     * @param packageName the name of package
     * @return {@link #scan(ClassLoader, String, boolean, boolean)} method with requiredLoad=false
     * @throws IllegalArgumentException scanned source is not legal
     * @throws IllegalStateException    scanned source's state is not valid
     */
    public Set> scan(ClassLoader classLoader, String packageName) throws IllegalArgumentException, IllegalStateException {
        return scan(classLoader, packageName, false);
    }

    /**
     * It's equal to invoke {@link #scan(ClassLoader, String, boolean, boolean)} method with
     * requiredLoad=false
     *
     * @param classLoader {@link ClassLoader}
     * @param packageName the name of package
     * @param recursive   included sub-package
     * @return {@link #scan(ClassLoader, String, boolean, boolean)} method with requiredLoad=false
     * @throws IllegalArgumentException scanned source is not legal
     * @throws IllegalStateException    scanned source's state is not valid
     */
    public Set> scan(ClassLoader classLoader, String packageName, boolean recursive) throws IllegalArgumentException, IllegalStateException {
        return scan(classLoader, packageName, recursive, false);
    }


    /**
     * scan {@link Class} set under specified package name or its' sub-packages in {@link ClassLoader}, if
     * requiredLoad indicates true , try to load those classes.
     *
     * @param classLoader  {@link ClassLoader}
     * @param packageName  the name of package
     * @param recursive    included sub-package
     * @param requiredLoad try to load those classes or not
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalStateException
     */
    public Set> scan(ClassLoader classLoader, String packageName, final boolean recursive, boolean requiredLoad) throws IllegalArgumentException, IllegalStateException {
        Set> classesSet = new LinkedHashSet();

        final String packageResourceName = PACKAGE.resolve(packageName);

        try {
            Set classNames = new LinkedHashSet();
            // Find in class loader
            Set resourceURLs = getResources(classLoader, PACKAGE, packageName);

            if (resourceURLs.isEmpty()) {
                //Find in class path
                ClassDataRepository repository = ClassDataRepository.INSTANCE;
                List classNamesInPackage = new ArrayList<>(repository.getClassNamesInPackage(packageName));

                if (!classNamesInPackage.isEmpty()) {
                    String classPath = repository.findClassPath(classNamesInPackage.get(0));
                    URL resourceURL = new File(classPath).toURI().toURL();
                    resourceURLs = new HashSet();
                    resourceURLs.add(resourceURL);
                }
            }

            for (URL resourceURL : resourceURLs) {
                URL classPathURL = resolveClassPathURL(resourceURL, packageResourceName);
                String classPath = classPathURL.getFile();
                Set classNamesInClassPath = findClassNamesInClassPath(classPath, true);
                classNames.addAll(filterClassNames(classNamesInClassPath, packageName, recursive));
            }

            for (String className : classNames) {
                Class class_ = requiredLoad ? loadClass(className, classLoader) : findLoadedClass(classLoader, className);
                if (class_ != null) {
                    classesSet.add(class_);
                }
            }

        } catch (IOException e) {

        }
        return unmodifiableSet(classesSet);
    }

    public Set> scan(ClassLoader classLoader, URL resourceInArchive, boolean requiredLoad,
                              Predicate>... classFilters) {
        File archiveFile = resolveArchiveFile(resourceInArchive);
        Set classNames = findClassNamesInClassPath(archiveFile, true);
        Set> classesSet = new LinkedHashSet<>();
        for (String className : classNames) {
            Class class_ = requiredLoad ? loadClass(className, classLoader) : findLoadedClass(classLoader, className);
            if (class_ != null) {
                classesSet.add(class_);
            }
        }
        return filterAll(classesSet, classFilters);
    }

    public Set> scan(ClassLoader classLoader, File archiveFile, boolean requiredLoad,
                              Predicate>... classFilters) {
        Set classNames = findClassNamesInClassPath(archiveFile, true);
        Set> classesSet = new LinkedHashSet<>();
        for (String className : classNames) {
            Class class_ = requiredLoad ? loadClass(className, classLoader) : findLoadedClass(classLoader, className);
            if (class_ != null) {
                classesSet.add(class_);
            }
        }
        return filterAll(classesSet, classFilters);
    }

    private Set filterClassNames(Set classNames, String packageName, boolean recursive) {
        PackageNameClassNameFilter packageNameClassNameFilter = new PackageNameClassNameFilter(packageName, recursive);
        Set filterClassNames = new LinkedHashSet(FilterUtils.filter(classNames, packageNameClassNameFilter));
        return filterClassNames;
    }


    private URL resolveClassPathURL(URL resourceURL, String packageResourceName) {
        String resource = resourceURL.toExternalForm();
        String classPath = substringBefore(resource, packageResourceName);
        URL classPathURL = null;
        try {
            classPathURL = new URL(classPath);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
        return classPathURL;
    }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy