On Sun, Sep 22, 2024 at 6:46 PM Rafael Winterhalter <rafael....@gmail.com> wrote:
Sorry, still not sure I understand the scenario.. That is only true for Class::getResource which resolves resources relative > to the loaded class's class file location. > Class:getResource simply adds the package name prefix and calls ClassLoader::getResource. It has no separate knowledge about the class file's location. > When loading a class, ClassLoader::findClass respects the multi-release > characteristic. But for ClassLoader::getResource, this is not the case. > ClassLoader as such has no concept of multi-release JAR files, that's entirely up to the class loader implementation. In OpenJDK, this is supported by URLClassLoader, or rather URLClassPath.JarLoader::getResource, which calls JarFile::getEntry which is where the version lookup happens. If you have a class loader which respects multi-release characteristics in ClassLoader::loadClass, but not in ClassLoader::getResource, then that is a strange way to implement a class loader. Is there some intricacy of class loader hierarchies that I'm missing here? The following unit test demonstrates how URLClassLoader::getResource resolves versions: @Test public void getVersionedClass() throws IOException { Path zip = Path.of("multi.zip"); Manifest man = new Manifest(); Attributes attrs = man.getMainAttributes(); attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0"); attrs.put(Attributes.Name.MULTI_RELEASE, "true"); try (JarOutputStream jo = new JarOutputStream(Files.newOutputStream(zip), man)) { jo.putNextEntry(new ZipEntry("META-INF/versions/21/com/example/HelloWorld.class")); jo.putNextEntry(new ZipEntry("com/example/HelloWorld.class")); } ClassLoader loader = new URLClassLoader(new URL[] {zip.toUri().toURL()}); URL resource = loader.getResource("com/example/HelloWorld.class"); String path = resource.getFile().substring(resource.getFile().indexOf("!/") + 2); assertEquals("META-INF/versions/21/com/example/HelloWorld.class", path); }