Can you find all classes in a package using reflection?

前端 未结 27 2212
不知归路
不知归路 2020-11-21 05:24

Is it possible to find all classes or interfaces in a given package? (Quickly looking at e.g. Package, it would seem like no.)

相关标签:
27条回答
  • 2020-11-21 05:45

    The most robust mechanism for listing all classes in a given package is currently ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author.)

    List<String> classNames = new ArrayList<>();
    try (ScanResult scanResult = new ClassGraph().acceptPackages("my.package")
            .enableClassInfo().scan()) {
        classNames.addAll(scanResult.getAllClasses().getNames());
    }
    
    0 讨论(0)
  • 2020-11-21 05:46

    I couldn't find a short working snipped for something so simple. So here it is, I made it myself after screwing around for a while:

        Reflections reflections =
            new Reflections(new ConfigurationBuilder()
                    .filterInputsBy(new FilterBuilder().includePackage(packagePath))
                    .setUrls(ClasspathHelper.forPackage(packagePath))
                    .setScanners(new SubTypesScanner(false)));
    
        Set<String> typeList = reflections.getAllTypes(); 
    
    0 讨论(0)
  • 2020-11-21 05:47

    You should probably take a look at the open source Reflections library. With it you can easily achieve what you want.

    First, setup the reflections index (it's a bit messy since searching for all classes is disabled by default):

    List<ClassLoader> classLoadersList = new LinkedList<ClassLoader>();
    classLoadersList.add(ClasspathHelper.contextClassLoader());
    classLoadersList.add(ClasspathHelper.staticClassLoader());
    
    Reflections reflections = new Reflections(new ConfigurationBuilder()
        .setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
        .setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0])))
        .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("org.your.package"))));
    

    Then you can query for all objects in a given package:

    Set<Class<?>> classes = reflections.getSubTypesOf(Object.class);
    
    0 讨论(0)
  • 2020-11-21 05:49

    Google Guava 14 includes a new class ClassPath with three methods to scan for top level classes:

    • getTopLevelClasses()
    • getTopLevelClasses(String packageName)
    • getTopLevelClassesRecursive(String packageName)

    See the ClassPath javadocs for more info.

    0 讨论(0)
  • 2020-11-21 05:49

    I just wrote a util class, it include test methods, you can have a check ~

    IteratePackageUtil.java:

    package eric.j2se.reflect;
    
    import java.util.Set;
    
    import org.reflections.Reflections;
    import org.reflections.scanners.ResourcesScanner;
    import org.reflections.scanners.SubTypesScanner;
    import org.reflections.util.ClasspathHelper;
    import org.reflections.util.ConfigurationBuilder;
    import org.reflections.util.FilterBuilder;
    
    /**
     * an util to iterate class in a package,
     * 
     * @author eric
     * @date Dec 10, 2013 12:36:46 AM
     */
    public class IteratePackageUtil {
        /**
         * <p>
         * Get set of all class in a specified package recursively. this only support lib
         * </p>
         * <p>
         * class of sub package will be included, inner class will be included,
         * </p>
         * <p>
         * could load class that use the same classloader of current class, can't load system packages,
         * </p>
         * 
         * @param pkg
         *            path of a package
         * @return
         */
        public static Set<Class<? extends Object>> getClazzSet(String pkg) {
            // prepare reflection, include direct subclass of Object.class
            Reflections reflections = new Reflections(new ConfigurationBuilder().setScanners(new SubTypesScanner(false), new ResourcesScanner())
                    .setUrls(ClasspathHelper.forClassLoader(ClasspathHelper.classLoaders(new ClassLoader[0])))
                    .filterInputsBy(new FilterBuilder().includePackage(pkg)));
    
            return reflections.getSubTypesOf(Object.class);
        }
    
        public static void test() {
            String pkg = "org.apache.tomcat.util";
    
            Set<Class<? extends Object>> clazzSet = getClazzSet(pkg);
            for (Class<? extends Object> clazz : clazzSet) {
                System.out.println(clazz.getName());
            }
        }
    
        public static void main(String[] args) {
            test();
        }
    }
    
    0 讨论(0)
  • 2020-11-21 05:49

    Based on @Staale's answer, and in an attempt not to rely on third party libraries, I would implement the File System approach by inspecting first package physical location with:

    import java.io.File;
    import java.io.FileFilter;
    import java.util.ArrayList;
    ...
    Class<?>[] foundClasses = new Class<?>[0];
    final ArrayList<Class<?>> foundClassesDyn = new ArrayList<Class<?>>();
    
    new java.io.File(
        klass.getResource(
            "/" + curPackage.replace( "." , "/")
        ).getFile()
    ).listFiles(
        new java.io.FileFilter() {
            public boolean accept(java.io.File file) {
                final String classExtension = ".class";
    
                if ( file.isFile()
                    && file.getName().endsWith(classExtension)
                    // avoid inner classes
                    && ! file.getName().contains("$") )
                {
                    try {
                        String className = file.getName();
                        className = className.substring(0, className.length() - classExtension.length());
                        foundClassesDyn.add( Class.forName( curPackage + "." + className ) );
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace(System.out);
                    }
                }
    
                return false;
            }
        }
    );
    
    foundClasses = foundClassesDyn.toArray(foundClasses);
    
    0 讨论(0)
提交回复
热议问题