[core] Cache moduleName to URLs in ClasspathClassLoader

This commit is contained in:
Andreas Dangel 2024-08-13 11:43:17 +01:00
parent 13b8556bf6
commit b51be09795
No known key found for this signature in database
GPG Key ID: 93450DF2DF9A3FA3

View File

@ -20,6 +20,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -206,6 +207,8 @@ public class ClasspathClassLoader extends URLClassLoader {
private static final String MODULE_INFO_SUFFIX = "module-info.class"; private static final String MODULE_INFO_SUFFIX = "module-info.class";
private static final String MODULE_INFO_SUFFIX_SLASH = "/" + MODULE_INFO_SUFFIX; private static final String MODULE_INFO_SUFFIX_SLASH = "/" + MODULE_INFO_SUFFIX;
// this is lazily initialized on first query of a module-info.class
private Map<String, URL> moduleNameToModuleInfoUrls;
@Nullable @Nullable
private static String extractModuleName(String name) { private static String extractModuleName(String name) {
@ -263,10 +266,10 @@ public class ClasspathClassLoader extends URLClassLoader {
} }
} }
private static class ModuleFinder extends ClassVisitor { private static class ModuleNameExtractor extends ClassVisitor {
private String moduleName; private String moduleName;
protected ModuleFinder() { protected ModuleNameExtractor() {
super(Opcodes.ASM9); super(Opcodes.ASM9);
} }
@ -281,21 +284,39 @@ public class ClasspathClassLoader extends URLClassLoader {
} }
} }
private URL findModule(Enumeration<URL> moduleInfoUrls, String moduleName) throws IOException { private void collectAllModules() {
if (moduleNameToModuleInfoUrls != null) {
return;
}
Map<String, URL> allModules = new HashMap<>();
try {
Enumeration<URL> moduleInfoUrls = findResources(MODULE_INFO_SUFFIX);
collectModules(allModules, moduleInfoUrls);
// also search in parents
moduleInfoUrls = getParent().getResources(MODULE_INFO_SUFFIX);
collectModules(allModules, moduleInfoUrls);
LOG.debug("Found {} modules on auxclasspath", allModules.size());
moduleNameToModuleInfoUrls = Collections.unmodifiableMap(allModules);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void collectModules(Map<String, URL> allModules, Enumeration<URL> moduleInfoUrls) throws IOException {
while (moduleInfoUrls.hasMoreElements()) { while (moduleInfoUrls.hasMoreElements()) {
URL url = moduleInfoUrls.nextElement(); URL url = moduleInfoUrls.nextElement();
ModuleFinder finder = new ModuleFinder(); ModuleNameExtractor finder = new ModuleNameExtractor();
try (InputStream inputStream = url.openStream()) { try (InputStream inputStream = url.openStream()) {
ClassReader classReader = new ClassReader(inputStream); ClassReader classReader = new ClassReader(inputStream);
classReader.accept(finder, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); classReader.accept(finder, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
} }
if (moduleName.equals(finder.getModuleName())) { allModules.putIfAbsent(finder.getModuleName(), url);
return url;
}
} }
return null;
} }
@Override @Override
@ -306,20 +327,9 @@ public class ClasspathClassLoader extends URLClassLoader {
String moduleName = extractModuleName(name); String moduleName = extractModuleName(name);
if (moduleName != null) { if (moduleName != null) {
try { collectAllModules();
Enumeration<URL> moduleInfoUrls = findResources(MODULE_INFO_SUFFIX); assert moduleNameToModuleInfoUrls != null : "Modules should have been detected by collectAllModules()";
URL moduleUrl = findModule(moduleInfoUrls, moduleName); return moduleNameToModuleInfoUrls.get(moduleName);
// no match in this classloader, search in parents
if (moduleUrl == null) {
moduleInfoUrls = getParent().getResources(MODULE_INFO_SUFFIX);
moduleUrl = findModule(moduleInfoUrls, moduleName);
}
return moduleUrl;
} catch (IOException e) {
throw new RuntimeException(e);
}
} }
URL url = findResource(name); URL url = findResource(name);