1

I refer to this article (https://www.baeldung.com/java-find-all-classes-in-package),

under Java11: work only to the package like "com.xxx", if i test "java.util", not work(return 0 size set, see test code below).

under Java8: both work.

test code:

public class AccessingAllClassesInPackage {

    public Set<Class> findAllClassesUsingClassLoader(String packageName) {
        InputStream stream = ClassLoader.getSystemClassLoader()
                .getResourceAsStream(packageName.replaceAll("[.]", "/"));
        BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
        return reader.lines()
                .filter(line -> line.endsWith(".class"))
                .map(line -> getClass(line, packageName))
                .collect(Collectors.toSet());
    }

    private Class getClass(String className, String packageName) {
        try {
            return Class.forName(packageName + "."
                    + className.substring(0, className.lastIndexOf('.')));
        } catch (ClassNotFoundException e) {
            // handle the exception
        }
        return null;
    }

    public Set<Class> findAllClassesUsingReflectionsLibrary(String packageName) {
        Reflections reflections = new Reflections(packageName, new SubTypesScanner(false));
        return reflections.getSubTypesOf(Object.class)
                .stream()
                .collect(Collectors.toSet());
    }

    public Set<Class> findAllClassesUsingGoogleGuice(String packageName) throws IOException {
        return ClassPath.from(ClassLoader.getSystemClassLoader())
                .getAllClasses()
                .stream()
                .filter(clazz -> clazz.getPackageName()
                        .equalsIgnoreCase(packageName))
                .map(clazz -> clazz.load())
                .collect(Collectors.toSet());
    }
}

public class DemoApplication {

    public static void main(String[] args) throws IOException {

        String packageA = "com.google.common.reflect";
        String packageB = "java.util";

        AccessingAllClassesInPackage instance = new AccessingAllClassesInPackage();

        Set<Class> classesA = instance.findAllClassesUsingClassLoader(packageB);

        Set<Class> classesB = instance.findAllClassesUsingReflectionsLibrary(packageB);

        Set<Class> classesC = instance.findAllClassesUsingGoogleGuice(packageB);

        System.out.println("args = " + Arrays.deepToString(args));
    }
}

Andrej Istomin
  • 2,527
  • 2
  • 15
  • 22

1 Answers1

0
private static List<Path> findClasses(Path module) throws IOException {
        List<Path> classes = new ArrayList<>();
        Files.walkFileTree(module, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                String fileName = file.getFileName().toString();
                if (fileName.endsWith(".class") && !fileName.contains("$")) {
                    classes.add(file);
                }
                return FileVisitResult.CONTINUE;
            }
        });
        return classes;
    }
FileSystem fileSystem = FileSystems.getFileSystem(URI.create("jrt:/"));
Path modules = fileSystem.getPath("/modules/java.base/java/util");
List<Path> classes = findClasses(modules);
  • 1
    You can achieve the same using `Path p = Paths.get(Collection.class.getResource( "Collection.class").toURI()).getParent(); List classes = Files.walk(p) .filter(file -> { String fileName = file.getFileName().toString(); return fileName .endsWith(".class") && !fileName.contains("$"); }) .collect(Collectors.toList());` Combined with [this solution](https://stackoverflow.com/a/36021165/2711488) you can even use it to scan classes in JREs before the introduction of the module system. – Holger Oct 11 '22 at 08:33
  • 1
    But your actual goal might be closer to `List classes = Files.walk(p) .map(file -> p.relativize(file).toString().replace(p.getFileSystem().getSeparator(), ".")) .filter(fileName -> fileName.endsWith(".class") && !fileName.contains("$")) .map(name -> "java.util." + name.substring(0, name.length() - 6)) .collect(Collectors.toList());` Note further, that if you want to get the particular package only, rather than “sub-packages”, you have to use `Files.list(p)` instead of `Files.walk(p)` (`Files.walk(p)` behaves like your `Files.walkFileTree(…)`). – Holger Oct 11 '22 at 08:39