diff --git a/org.graalvm.python.embedding/src/main/java/org/graalvm/python/embedding/VirtualFileSystem.java b/org.graalvm.python.embedding/src/main/java/org/graalvm/python/embedding/VirtualFileSystem.java index f74ab3f..b5c4392 100644 --- a/org.graalvm.python.embedding/src/main/java/org/graalvm/python/embedding/VirtualFileSystem.java +++ b/org.graalvm.python.embedding/src/main/java/org/graalvm/python/embedding/VirtualFileSystem.java @@ -107,7 +107,8 @@ public static final class Builder { private HostIO allowHostIO = HostIO.READ_WRITE; private boolean caseInsensitive = VirtualFileSystemImpl.isWindows(); - private Class resourceLoadingClass; + private ClassLoader resourceClassLoader; + private String resourceDirectory; private Builder() { @@ -238,7 +239,7 @@ public Builder unixMountPoint(String unixMountPoint) { /** * By default, virtual filesystem resources are loaded by delegating to - * VirtualFileSystem.class.getResource(name). Use + * VirtualFileSystem.class.getClassLoader().getResource(name). Use * resourceLoadingClass to determine where to locate resources in * cases when for example VirtualFileSystem is on module path and * the jar containing the resources is on class path. @@ -249,7 +250,24 @@ public Builder unixMountPoint(String unixMountPoint) { * @since 24.2.0 */ public Builder resourceLoadingClass(Class c) { - resourceLoadingClass = c; + resourceClassLoader = c.getClassLoader(); + return this; + } + + /** + * By default, virtual filesystem resources are loaded by delegating to + * VirtualFileSystem.class.getClassLoader().getResource(name). Use + * resourceClassLoader to determine where to locate resources in + * cases when for example VirtualFileSystem is on module path and + * the jar containing the resources is on class path. + * + * @param cl + * the classloader used to load resources + * @return this builder + * @since 26.0.0 + */ + public Builder resourceClassLoader(ClassLoader cl) { + resourceClassLoader = cl; return this; } @@ -292,8 +310,8 @@ public VirtualFileSystem build() { ? Path.of(DEFAULT_WINDOWS_MOUNT_POINT) : Path.of(DEFAULT_UNIX_MOUNT_POINT); } - return new VirtualFileSystem(extractFilter, mountPoint, allowHostIO, resourceLoadingClass, - resourceDirectory, caseInsensitive); + return new VirtualFileSystem(extractFilter, mountPoint, allowHostIO, resourceClassLoader, resourceDirectory, + caseInsensitive); } } @@ -308,10 +326,10 @@ private static Path getMountPointAsPath(String mp) { } private VirtualFileSystem(Predicate extractFilter, Path mountPoint, HostIO allowHostIO, - Class resourceLoadingClass, String resourceDirectory, boolean caseInsensitive) { + ClassLoader resourceClassLoader, String resourceDirectory, boolean caseInsensitive) { this.impl = new VirtualFileSystemImpl(extractFilter, mountPoint, resourceDirectory, allowHostIO, - resourceLoadingClass, caseInsensitive); + resourceClassLoader, caseInsensitive); this.delegatingFileSystem = VirtualFileSystemImpl.createDelegatingFileSystem(impl); } diff --git a/org.graalvm.python.embedding/src/main/java/org/graalvm/python/embedding/VirtualFileSystemImpl.java b/org.graalvm.python.embedding/src/main/java/org/graalvm/python/embedding/VirtualFileSystemImpl.java index 1bfa25c..8f5a8f6 100644 --- a/org.graalvm.python.embedding/src/main/java/org/graalvm/python/embedding/VirtualFileSystemImpl.java +++ b/org.graalvm.python.embedding/src/main/java/org/graalvm/python/embedding/VirtualFileSystemImpl.java @@ -171,10 +171,10 @@ private static String absoluteResourcePath(String... components) { private final Map vfsEntries = new HashMap<>(); /** - * Class used to read resources with getResource(name). By default + * Classloader used to read resources. By defaut, the classloader of * VirtualFileSystem.class. */ - private Class resourceLoadingClass; + private final ClassLoader resourceClassLoader; static final String PLATFORM_SEPARATOR = Paths.get("").getFileSystem().getSeparator(); private static final char RESOURCE_SEPARATOR_CHAR = '/'; @@ -310,11 +310,11 @@ private void removeExtractDir() { * argument may be {@code null} causing that no extraction will happen. */ VirtualFileSystemImpl(Predicate extractFilter, Path mountPoint, String resourceDirectory, HostIO allowHostIO, - Class resourceLoadingClass, boolean caseInsensitive) { - if (resourceLoadingClass != null) { - this.resourceLoadingClass = resourceLoadingClass; + ClassLoader resourceClassLoader, boolean caseInsensitive) { + if (resourceClassLoader != null) { + this.resourceClassLoader = resourceClassLoader; } else { - this.resourceLoadingClass = VirtualFileSystem.class; + this.resourceClassLoader = VirtualFileSystem.class.getClassLoader(); } this.caseInsensitive = caseInsensitive; this.mountPoint = mountPoint; @@ -323,10 +323,14 @@ private void removeExtractDir() { this.platformVenvPath = resourcePathToPlatformPath(absoluteResourcePath(vfsRoot, VFS_VENV)); this.platformSrcPath = resourcePathToPlatformPath(absoluteResourcePath(vfsRoot, VFS_SRC)); - fine("VirtualFilesystem %s, allowHostIO: %s, resourceLoadingClass: %s, caseInsensitive: %s, extractOnStartup: %s%s", - mountPoint, allowHostIO.toString(), this.resourceLoadingClass.getName(), caseInsensitive, - extractOnStartup, extractFilter != null ? "" : ", extractFilter: null"); - + if (LOGGER.isLoggable(Level.FINE)) { + var classLoaderLabel = this.resourceClassLoader == VirtualFileSystem.class.getClassLoader() + ? "VirtualFileSystem" + : "custom"; + fine("VirtualFilesystem %s, allowHostIO: %s, resourceClassLoader: %s, caseInsensitive: %s, extractOnStartup: %s%s", + mountPoint, allowHostIO.toString(), classLoaderLabel, caseInsensitive, extractOnStartup, + extractFilter != null ? "" : ", extractFilter: null"); + } this.extractFilter = extractFilter; if (extractFilter != null) { try { @@ -670,7 +674,7 @@ public boolean equals(Object obj) { private List getFilelistURLs(String filelistPath) { List filelistUrls; try { - filelistUrls = Collections.list(this.resourceLoadingClass.getClassLoader().getResources(filelistPath)); + filelistUrls = Collections.list(resourceClassLoader.getResources(filelistPath)); } catch (IOException e) { throw new IllegalStateException("IO error during reading the VirtualFileSystem metadata", e); } @@ -745,8 +749,7 @@ private void validateMultipleVFSLocations(List filelistUrls) { // by the Maven/Gradle plugin and should contain "pip freeze" of the venv ArrayList installedUrls; try { - installedUrls = Collections.list( - this.resourceLoadingClass.getClassLoader().getResources(resourcePath(vfsRoot, INSTALLED_FILE))); + installedUrls = Collections.list(resourceClassLoader.getResources(resourcePath(vfsRoot, INSTALLED_FILE))); } catch (IOException e) { warn("Cannot check compatibility of the merged virtual environments. Cannot read list of packages installed in the virtual environments. IOException: " + e.getMessage()); @@ -790,8 +793,7 @@ private void validateMultipleVFSLocations(List filelistUrls) { // Check compatibility of GraalPy versions that were used to create the VFSs ArrayList contentsUrls; try { - contentsUrls = Collections.list( - this.resourceLoadingClass.getClassLoader().getResources(resourcePath(vfsRoot, CONTENTS_FILE))); + contentsUrls = Collections.list(resourceClassLoader.getResources(resourcePath(vfsRoot, CONTENTS_FILE))); } catch (IOException e) { warn("Cannot check compatibility of the merged virtual environments. Cannot read GraalPy version of the virtual environments. IOException: " + e.getMessage()); @@ -831,7 +833,7 @@ private void validateMultipleVFSLocations(List filelistUrls) { } private URL getResourceUrl(String path) throws IOException { - List urls = Collections.list(this.resourceLoadingClass.getClassLoader().getResources(path.substring(1))); + List urls = Collections.list(resourceClassLoader.getResources(path.substring(1))); if (vfsRootURL != null) { urls = getURLInRoot(urls); }