# HG changeset patch # User alanb # Date 1512549369 0 # Node ID 794cbfa7a309fedafc6c2891e2bc5089302c43c7 # Parent c51f9eea6d2bfd97324df9cd6fb2bcebe700bbb5 8182742: ClassLoader.getResourceXXX throws NPE when ClassLoader created by defineModulesWithXXX Reviewed-by: redestad, mchung diff -r c51f9eea6d2b -r 794cbfa7a309 src/java.base/share/classes/jdk/internal/loader/Loader.java --- a/src/java.base/share/classes/jdk/internal/loader/Loader.java Wed Dec 06 08:33:04 2017 +0000 +++ b/src/java.base/share/classes/jdk/internal/loader/Loader.java Wed Dec 06 08:36:09 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ import java.io.File; import java.io.FilePermission; import java.io.IOException; -import java.io.UncheckedIOException; import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleReader; @@ -58,12 +57,8 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.Spliterator; -import java.util.Spliterators; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; import java.util.stream.Stream; -import java.util.stream.StreamSupport; import jdk.internal.misc.SharedSecrets; import jdk.internal.module.Resources; @@ -403,12 +398,15 @@ // this loader URL url = findResource(name); - if (url != null) { - return url; - } else { + if (url == null) { // parent loader - return parent.getResource(name); + if (parent != null) { + url = parent.getResource(name); + } else { + url = BootLoader.findResource(name); + } } + return url; } @Override @@ -419,7 +417,12 @@ List urls = findResourcesAsList(name); // parent loader - Enumeration e = parent.getResources(name); + Enumeration e; + if (parent != null) { + e = parent.getResources(name); + } else { + e = BootLoader.findResources(name); + } // concat the URLs with the URLs returned by the parent return new Enumeration<>() { @@ -439,25 +442,6 @@ }; } - @Override - public Stream resources(String name) { - Objects.requireNonNull(name); - // ordering not specified - int characteristics = (Spliterator.NONNULL | Spliterator.IMMUTABLE | - Spliterator.SIZED | Spliterator.SUBSIZED); - Supplier> supplier = () -> { - try { - List urls = findResourcesAsList(name); - return Spliterators.spliterator(urls, characteristics); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }; - Stream s1 = StreamSupport.stream(supplier, characteristics, false); - Stream s2 = parent.resources(name); - return Stream.concat(s1, s2); - } - /** * Finds the resources with the given name in this class loader. */ diff -r c51f9eea6d2b -r 794cbfa7a309 test/jdk/java/lang/ModuleLayer/LayerAndLoadersTest.java --- a/test/jdk/java/lang/ModuleLayer/LayerAndLoadersTest.java Wed Dec 06 08:33:04 2017 +0000 +++ b/test/jdk/java/lang/ModuleLayer/LayerAndLoadersTest.java Wed Dec 06 08:36:09 2017 +0000 @@ -52,6 +52,7 @@ import java.util.ServiceLoader; import java.util.Set; import java.util.stream.Collectors; + import jdk.test.lib.compiler.CompilerUtils; import org.testng.annotations.BeforeTest; @@ -78,7 +79,7 @@ * Basic test of ModuleLayer.defineModulesWithOneLoader * * Test scenario: - * m1 requires m2 and m3 + * m1 requires m2 and m3 */ public void testWithOneLoader() throws Exception { Configuration cf = resolve("m1"); @@ -105,7 +106,7 @@ * Basic test of ModuleLayer.defineModulesWithManyLoaders * * Test scenario: - * m1 requires m2 and m3 + * m1 requires m2 and m3 */ public void testWithManyLoaders() throws Exception { Configuration cf = resolve("m1"); @@ -136,9 +137,9 @@ * modules is a service provider module. * * Test scenario: - * m1 requires m2 and m3 - * m1 uses S - * m4 provides S with ... + * m1 requires m2 and m3 + * m1 uses S + * m4 provides S with ... */ public void testServicesWithOneLoader() throws Exception { Configuration cf = resolveAndBind("m1"); @@ -175,9 +176,9 @@ * modules is a service provider module. * * Test scenario: - * m1 requires m2 and m3 - * m1 uses S - * m4 provides S with ... + * m1 requires m2 and m3 + * m1 uses S + * m4 provides S with ... */ public void testServicesWithManyLoaders() throws Exception { Configuration cf = resolveAndBind("m1"); @@ -234,7 +235,7 @@ ModuleLayer layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, parent); testLoad(layer, cn); - // one loader with boot loader as parent + // one loader with boot loader as parent layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, null); testLoadFail(layer, cn); @@ -252,21 +253,21 @@ * Test defineModulesWithXXX when modules that have overlapping packages. * * Test scenario: - * m1 exports p - * m2 exports p + * m1 exports p + * m2 exports p */ public void testOverlappingPackages() { ModuleDescriptor descriptor1 - = ModuleDescriptor.newModule("m1").exports("p").build(); + = ModuleDescriptor.newModule("m1").exports("p").build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.newModule("m2").exports("p").build(); + = ModuleDescriptor.newModule("m2").exports("p").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); Configuration cf = ModuleLayer.boot() - .configuration() - .resolve(finder, ModuleFinder.of(), Set.of("m1", "m2")); + .configuration() + .resolve(finder, ModuleFinder.of(), Set.of("m1", "m2")); // cannot define both module m1 and m2 to the same class loader try { @@ -284,35 +285,35 @@ * Test ModuleLayer.defineModulesWithXXX with split delegation. * * Test scenario: - * layer1: m1 exports p, m2 exports p - * layer2: m3 reads m1, m4 reads m2 + * layer1: m1 exports p, m2 exports p + * layer2: m3 reads m1, m4 reads m2 */ public void testSplitDelegation() { ModuleDescriptor descriptor1 - = ModuleDescriptor.newModule("m1").exports("p").build(); + = ModuleDescriptor.newModule("m1").exports("p").build(); ModuleDescriptor descriptor2 - = ModuleDescriptor.newModule("m2").exports("p").build(); + = ModuleDescriptor.newModule("m2").exports("p").build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); Configuration cf1 = ModuleLayer.boot() - .configuration() - .resolve(finder1, ModuleFinder.of(), Set.of("m1", "m2")); + .configuration() + .resolve(finder1, ModuleFinder.of(), Set.of("m1", "m2")); ModuleLayer layer1 = ModuleLayer.boot().defineModulesWithManyLoaders(cf1, null); checkLayer(layer1, "m1", "m2"); ModuleDescriptor descriptor3 - = ModuleDescriptor.newModule("m3").requires("m1").build(); + = ModuleDescriptor.newModule("m3").requires("m1").build(); ModuleDescriptor descriptor4 - = ModuleDescriptor.newModule("m4").requires("m2").build(); + = ModuleDescriptor.newModule("m4").requires("m2").build(); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); Configuration cf2 = cf1.resolve(finder2, ModuleFinder.of(), - Set.of("m3", "m4")); + Set.of("m3", "m4")); // package p cannot be supplied by two class loaders try { @@ -331,8 +332,8 @@ * named modules in the parent layer. * * Test scenario: - * layer1: m1, m2, m3 => same loader - * layer2: m1, m2, m4 => same loader + * layer1: m1, m2, m3 => same loader + * layer2: m1, m2, m4 => same loader */ public void testOverriding1() throws Exception { Configuration cf1 = resolve("m1"); @@ -342,7 +343,7 @@ ModuleFinder finder = ModuleFinder.of(MODS_DIR); Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), - Set.of("m1")); + Set.of("m1")); ModuleLayer layer2 = layer1.defineModulesWithOneLoader(cf2, null); checkLayer(layer2, "m1", "m2", "m3"); @@ -378,8 +379,8 @@ * named modules in the parent layer. * * Test scenario: - * layer1: m1, m2, m3 => loader pool - * layer2: m1, m2, m3 => loader pool + * layer1: m1, m2, m3 => loader pool + * layer2: m1, m2, m3 => loader pool */ public void testOverriding2() throws Exception { Configuration cf1 = resolve("m1"); @@ -389,7 +390,7 @@ ModuleFinder finder = ModuleFinder.of(MODS_DIR); Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), - Set.of("m1")); + Set.of("m1")); ModuleLayer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); checkLayer(layer2, "m1", "m2", "m3"); @@ -482,7 +483,7 @@ ModuleFinder finder = finderFor("m1", "m3"); Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), - Set.of("m1")); + Set.of("m1")); ModuleLayer layer2 = layer1.defineModulesWithOneLoader(cf2, null); checkLayer(layer2, "m1", "m3"); @@ -517,7 +518,7 @@ ModuleFinder finder = finderFor("m1", "m3"); Configuration cf2 = cf1.resolve(finder, ModuleFinder.of(), - Set.of("m1")); + Set.of("m1")); ModuleLayer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); checkLayer(layer2, "m1", "m3"); @@ -550,18 +551,27 @@ assertTrue(loader6.loadClass("w.Hello").getClassLoader() == loader6); } - /** * Basic test for locating resources with a class loader created by * defineModulesWithOneLoader. */ public void testResourcesWithOneLoader() throws Exception { + testResourcesWithOneLoader(ClassLoader.getSystemClassLoader()); + testResourcesWithOneLoader(null); + } + + /** + * Test locating resources with the class loader created by + * defineModulesWithOneLoader. The class loader has the given class + * loader as its parent. + */ + void testResourcesWithOneLoader(ClassLoader parent) throws Exception { Configuration cf = resolve("m1"); - ClassLoader scl = ClassLoader.getSystemClassLoader(); - ModuleLayer layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, scl); + ModuleLayer layer = ModuleLayer.boot().defineModulesWithOneLoader(cf, parent); ClassLoader loader = layer.findLoader("m1"); assertNotNull(loader); + assertTrue(loader.getParent() == parent); // check that getResource and getResources are consistent URL url1 = loader.getResource("module-info.class"); @@ -607,14 +617,24 @@ * defineModulesWithManyLoaders. */ public void testResourcesWithManyLoaders() throws Exception { + testResourcesWithManyLoaders(ClassLoader.getSystemClassLoader()); + testResourcesWithManyLoaders(null); + } + + /** + * Test locating resources with class loaders created by + * defineModulesWithManyLoaders. The class loaders have the given class + * loader as their parent. + */ + void testResourcesWithManyLoaders(ClassLoader parent) throws Exception { Configuration cf = resolve("m1"); - ClassLoader scl = ClassLoader.getSystemClassLoader(); - ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, scl); + ModuleLayer layer = ModuleLayer.boot().defineModulesWithManyLoaders(cf, parent); for (Module m : layer.modules()) { String name = m.getName(); ClassLoader loader = m.getClassLoader(); assertNotNull(loader); + assertTrue(loader.getParent() == parent); // getResource should find the module-info.class for the module URL url = loader.getResource("module-info.class");