以下代码在Java 9+(Jigsaw /JPMS)中实现了模块路径扫描。它在调用堆栈中查找所有类,然后为每个类引用调用
classRef.getModule().getLayer().getConfiguration().modules(),它们返回aa
List<ResolvedModule>,而不仅仅是a
List<Module>。(
ResolvedModule可以访问模块资源,而
Module不能访问。)给定
ResolvedModule每个模块的引用,您可以调用
.reference()方法以获取
ModuleReference模块的。
ModuleReference#open()给你一个
ModuleReader,它允许你列出的资源模块中使用
ModuleReader#list(),或使用打开资源
Optional<InputStream>ModuleReader#open(resourcePath)或
Optional<ByteBuffer>ModuleReader#read(resourcePath)。然后关闭
ModuleReader完成模块后。我没有看到任何地方对此进行记录。很难弄清所有这些。但是这里是代码,希望其他人可以从中受益。
请注意,即使在JDK9
+中,您仍然可以将传统的classpath元素与模块路径元素一起使用,因此对于完整的模块路径+类路径扫描,您可能应该使用适当的类路径扫描解决方案,例如ClassGraph,该解决方案支持使用以下内容进行模块扫描机制(免责声明,我是作者)。您可以在此处找到以下代码的基于反射的版本。
还请注意,在JDK
9之后的几个JDK版本中,StackWalker中存在一个错误,必须解决,有关详细信息,请参见上面的基于反射的代码。
package main;import java.lang.StackWalker;import java.lang.StackWalker.Option;import java.lang.StackWalker.Stackframe;import java.lang.module.ModuleReader;import java.lang.module.ModuleReference;import java.lang.module.ResolvedModule;import java.net.URI;import java.security.AccessController;import java.security.PrivilegedAction;import java.util.AbstractMap.SimpleEntry;import java.util.ArrayDeque;import java.util.ArrayList;import java.util.Collections;import java.util.Deque;import java.util.HashSet;import java.util.List;import java.util.Map.Entry;import java.util.Optional;import java.util.Set;import java.util.stream.Stream;public class Java9Scanner { private static void findLayerOrder(ModuleLayer layer, Set<ModuleLayer> visited, Deque<ModuleLayer> layersOut) { if (visited.add(layer)) { List<ModuleLayer> parents = layer.parents(); for (int i = 0; i < parents.size(); i++) { findLayerOrder(parents.get(i), visited, layersOut); } layersOut.push(layer); } } private static List<Entry<ModuleReference, ModuleLayer>> findModuleRefs( Class<?>[] callStack) { Deque<ModuleLayer> layerOrder = new ArrayDeque<>(); Set<ModuleLayer> visited = new HashSet<>(); for (int i = 0; i < callStack.length; i++) { ModuleLayer layer = callStack[i].getModule().getLayer(); findLayerOrder(layer, visited, layerOrder); } Set<ModuleReference> addedModules = new HashSet<>(); List<Entry<ModuleReference, ModuleLayer>> moduleRefs = new ArrayList<>(); for (ModuleLayer layer : layerOrder) { Set<ResolvedModule> modulesInLayerSet = layer.configuration() .modules(); final List<Entry<ModuleReference, ModuleLayer>> modulesInLayer = new ArrayList<>(); for (ResolvedModule module : modulesInLayerSet) { modulesInLayer .add(new SimpleEntry<>(module.reference(), layer)); } // Sort modules in layer by name for consistency Collections.sort(modulesInLayer, (e1, e2) -> e1.getKey().descriptor().name() .compareTo(e2.getKey().descriptor().name())); // To be safe, dedup ModuleReferences, in case a module occurs in multiple // layers and reuses its ModuleReference (no idea if this can happen) for (Entry<ModuleReference, ModuleLayer> m : modulesInLayer) { if (addedModules.add(m.getKey())) { moduleRefs.add(m); } } } return moduleRefs; } private static Class<?>[] getCallStack() { // Try StackWalker (JDK 9+) PrivilegedAction<Class<?>[]> stackWalkerAction = (PrivilegedAction<Class<?>[]>) () -> StackWalker.getInstance( Option.RETAIN_CLASS_REFERENCE) .walk(s -> s.map( Stackframe::getDeclaringClass) .toArray(Class[]::new)); try { // Try with doPrivileged() return AccessController .doPrivileged(stackWalkerAction); } catch (Exception e) { } try { // Try without doPrivileged() return stackWalkerAction.run(); } catch (Exception e) { } // Try SecurityManager PrivilegedAction<Class<?>[]> callerResolverAction = (PrivilegedAction<Class<?>[]>) () -> new SecurityManager() { @Override public Class<?>[] getClassContext() { return super.getClassContext(); } }.getClassContext(); try { // Try with doPrivileged() return AccessController .doPrivileged(callerResolverAction); } catch (Exception e) { } try { // Try without doPrivileged() return callerResolverAction.run(); } catch (Exception e) { } // As a fallback, use getStackTrace() to try to get the call stack try { throw new Exception(); } catch (final Exception e) { final List<Class<?>> classes = new ArrayList<>(); for (final StackTraceElement elt : e.getStackTrace()) { try { classes.add(Class.forName(elt.getClassName())); } catch (final Throwable e2) { // Ignore } } if (classes.size() > 0) { return classes.toArray(new Class<?>[0]); } else { // Last-ditch effort -- include just this class return new Class<?>[] { Java9Scanner.class }; } } } private static boolean isSystemModule( final ModuleReference moduleReference) { String name = moduleReference.descriptor().name(); if (name == null) { return false; } return name.startsWith("java.") || name.startsWith("jdk.") || name.startsWith("javafx.") || name.startsWith("oracle."); } public static void main(String[] args) throws Exception { // Get ModuleReferences for modules of all classes in call stack, List<Entry<ModuleReference, ModuleLayer>> systemModuleRefs = new ArrayList<>(); List<Entry<ModuleReference, ModuleLayer>> nonSystemModuleRefs = new ArrayList<>(); Class<?>[] callStack = getCallStack(); List<Entry<ModuleReference, ModuleLayer>> moduleRefs = findModuleRefs( callStack); // Split module refs into system and non-system modules based on module name for (Entry<ModuleReference, ModuleLayer> m : moduleRefs) { (isSystemModule(m.getKey()) ? systemModuleRefs : nonSystemModuleRefs).add(m); } // List system modules System.out.println("nSYSTEM MODULES:n"); for (Entry<ModuleReference, ModuleLayer> e : systemModuleRefs) { ModuleReference ref = e.getKey(); System.out.println(" " + ref.descriptor().name()); } // Show info for non-system modules System.out.println("nNON-SYSTEM MODULES:"); for (Entry<ModuleReference, ModuleLayer> e : nonSystemModuleRefs) { ModuleReference ref = e.getKey(); ModuleLayer layer = e.getValue(); System.out.println("n " + ref.descriptor().name()); System.out.println( " Version: " + ref.descriptor().tonameAndVersion()); System.out.println( " Packages: " + ref.descriptor().packages()); System.out.println(" ClassLoader: " + layer.findLoader(ref.descriptor().name())); Optional<URI> location = ref.location(); if (location.isPresent()) { System.out.println(" Location: " + location.get()); } try (ModuleReader moduleReader = ref.open()) { Stream<String> stream = moduleReader.list(); stream.forEach(s -> System.out.println(" File: " + s)); } } }}


