Path: blob/master/test/jdk/java/lang/module/AutomaticModulesTest.java
41149 views
/*1* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @bug 8142968 825375126* @library /test/lib27* @build AutomaticModulesTest28* jdk.test.lib.util.JarUtils29* jdk.test.lib.util.ModuleUtils30* @run testng AutomaticModulesTest31* @summary Basic tests for automatic modules32*/3334import java.io.IOException;35import java.lang.module.Configuration;36import java.lang.module.FindException;37import java.lang.module.ModuleDescriptor;38import java.lang.module.ModuleDescriptor.Requires.Modifier;39import java.lang.module.ModuleFinder;40import java.lang.module.ModuleReference;41import java.lang.module.ResolutionException;42import java.lang.module.ResolvedModule;43import java.nio.file.Files;44import java.nio.file.Path;45import java.util.Optional;46import java.util.Set;47import java.util.jar.Attributes;48import java.util.jar.Manifest;49import java.util.stream.Collectors;50import java.util.stream.Stream;5152import jdk.test.lib.util.JarUtils;53import jdk.test.lib.util.ModuleUtils;5455import org.testng.annotations.DataProvider;56import org.testng.annotations.Test;57import static org.testng.Assert.*;5859@Test60public class AutomaticModulesTest {6162private static final Path USER_DIR = Path.of(System.getProperty("user.dir"));6364@DataProvider(name = "jarnames")65public Object[][] createJarNames() {66return new Object[][] {6768// JAR file name module-name[/version]6970{ "foo.jar", "foo" },71{ "foo4j.jar", "foo4j", },7273{ "foo1.jar", "foo1" },74{ "foo10.jar", "foo10" },7576{ "foo-1.jar", "foo/1" },77{ "foo-1.2.jar", "foo/1.2" },78{ "foo-1.2.3.jar", "foo/1.2.3" },79{ "foo-1.2.3.4.jar", "foo/1.2.3.4" },8081{ "foo-10.jar", "foo/10" },82{ "foo-10.20.jar", "foo/10.20" },83{ "foo-10.20.30.jar", "foo/10.20.30" },84{ "foo-10.20.30.40.jar", "foo/10.20.30.40" },8586{ "foo-bar.jar", "foo.bar" },87{ "foo-bar-1.jar", "foo.bar/1" },88{ "foo-bar-1.2.jar", "foo.bar/1.2"},89{ "foo-bar-10.jar", "foo.bar/10" },90{ "foo-bar-10.20.jar", "foo.bar/10.20" },9192{ "foo.bar1.jar", "foo.bar1" },93{ "foo.bar10.jar", "foo.bar10" },9495{ "foo-1.2-SNAPSHOT.jar", "foo/1.2-SNAPSHOT" },96{ "foo-bar-1.2-SNAPSHOT.jar", "foo.bar/1.2-SNAPSHOT" },9798{ "foo--bar-1.0.jar", "foo.bar/1.0" },99{ "-foo-bar-1.0.jar", "foo.bar/1.0" },100{ "foo-bar--1.0.jar", "foo.bar/1.0" },101102};103}104105// JAR file names that do not map to a legal module name106@DataProvider(name = "badjarnames")107public Object[][] createBadNames() {108return new Object[][]{109110{ ".jar", null },111{ "_.jar", null },112113{ "foo.1.jar", null },114{ "1foo.jar", null },115{ "foo.1bar.jar", null },116117};118}119120/**121* Test mapping of JAR file names to module names122*/123@Test(dataProvider = "jarnames")124public void testNames(String fn, String mid) throws IOException {125String[] s = mid.split("/");126String mn = s[0];127String vs = (s.length == 2) ? s[1] : null;128129Path dir = Files.createTempDirectory(USER_DIR, "mods");130Path jf = dir.resolve(fn);131132// create empty JAR file133createDummyJarFile(jf);134135// create a ModuleFinder to find modules in the directory136ModuleFinder finder = ModuleFinder.of(dir);137138// a module with the expected name should be found139Optional<ModuleReference> mref = finder.find(mn);140assertTrue(mref.isPresent(), mn + " not found");141142ModuleDescriptor descriptor = mref.get().descriptor();143assertTrue(descriptor.isAutomatic());144assertEquals(descriptor.name(), mn);145if (vs == null) {146assertFalse(descriptor.version().isPresent());147} else {148assertEquals(descriptor.version().get().toString(), vs);149}150}151152/**153* Test impossible mapping of JAR files to modules names154*/155@Test(dataProvider = "badjarnames", expectedExceptions = FindException.class)156public void testBadNames(String fn, String ignore) throws IOException {157Path dir = Files.createTempDirectory(USER_DIR, "mods");158Path jf = dir.resolve(fn);159160// create empty JAR file161createDummyJarFile(jf);162163// should throw FindException164ModuleFinder.of(dir).findAll();165}166167@DataProvider(name = "modulenames")168public Object[][] createModuleNames() {169return new Object[][] {170{ "foo", null },171{ "foo", "1.0" },172{ "foo.bar", null },173{ "foo.bar", "1.0" },174{ "class_", null },175{ "class_", "1.0" },176};177}178179@DataProvider(name = "badmodulenames")180public Object[][] createBadModuleNames() {181return new Object[][] {182{ "", null },183{ "", "1.0" },184{ "666", null },185{ "666", "1.0" },186{ "foo.class", null },187{ "foo.class", "1.0" },188};189}190191/**192* Test JAR files with the Automatic-Module-Name attribute193*/194@Test(dataProvider = "modulenames")195public void testAutomaticModuleNameAttribute(String name, String vs)196throws IOException197{198Manifest man = new Manifest();199Attributes attrs = man.getMainAttributes();200attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");201attrs.put(new Attributes.Name("Automatic-Module-Name"), name);202203Path dir = Files.createTempDirectory(USER_DIR, "mods");204String jar;205if (vs == null) {206jar = "m.jar";207} else {208jar = "m-" + vs + ".jar";209}210createDummyJarFile(dir.resolve(jar), man);211212ModuleFinder finder = ModuleFinder.of(dir);213214assertTrue(finder.findAll().size() == 1);215assertTrue(finder.find(name).isPresent());216217ModuleReference mref = finder.find(name).get();218ModuleDescriptor descriptor = mref.descriptor();219assertEquals(descriptor.name(), name);220assertEquals(descriptor.version()221.map(ModuleDescriptor.Version::toString)222.orElse(null), vs);223}224225/**226* Test JAR files with the Automatic-Module-Name attribute with a value227* that is not a legal module name.228*/229@Test(dataProvider = "badmodulenames", expectedExceptions = FindException.class)230public void testBadAutomaticModuleNameAttribute(String name, String ignore)231throws IOException232{233// should throw FindException234testAutomaticModuleNameAttribute(name, null);235}236237/**238* Test all packages are exported239*/240public void testPackages() throws IOException {241Path dir = Files.createTempDirectory(USER_DIR, "mods");242createDummyJarFile(dir.resolve("m.jar"),243"p/C1.class", "p/C2.class", "q/C1.class");244245ModuleFinder finder = ModuleFinder.of(dir);246Optional<ModuleReference> mref = finder.find("m");247assertTrue(mref.isPresent(), "m not found");248249ModuleDescriptor descriptor = mref.get().descriptor();250assertTrue(descriptor.isAutomatic());251252assertTrue(descriptor.packages().size() == 2);253assertTrue(descriptor.packages().contains("p"));254assertTrue(descriptor.packages().contains("q"));255256assertTrue(descriptor.exports().isEmpty());257assertTrue(descriptor.opens().isEmpty());258}259260/**261* Test class files in JAR file where the entry does not correspond to a262* legal package name.263*/264public void testBadPackage() throws IOException {265Path dir = Files.createTempDirectory(USER_DIR, "mods");266createDummyJarFile(dir.resolve("m.jar"), "p/C1.class", "p-/C2.class");267268ModuleFinder finder = ModuleFinder.of(dir);269Optional<ModuleReference> mref = finder.find("m");270assertTrue(mref.isPresent(), "m not found");271272ModuleDescriptor descriptor = mref.get().descriptor();273assertTrue(descriptor.isAutomatic());274275assertTrue(descriptor.packages().size() == 1);276assertTrue(descriptor.packages().contains("p"));277278assertTrue(descriptor.exports().isEmpty());279assertTrue(descriptor.opens().isEmpty());280}281282/**283* Test non-class resources in a JAR file.284*/285public void testNonClassResources() throws IOException {286Path dir = Files.createTempDirectory(USER_DIR, "mods");287createDummyJarFile(dir.resolve("m.jar"),288"LICENSE",289"README",290"WEB-INF/tags",291"p/Type.class",292"p/resources/m.properties");293294ModuleFinder finder = ModuleFinder.of(dir);295Optional<ModuleReference> mref = finder.find("m");296assertTrue(mref.isPresent(), "m not found");297298ModuleDescriptor descriptor = mref.get().descriptor();299assertTrue(descriptor.isAutomatic());300301assertTrue(descriptor.packages().size() == 1);302assertTrue(descriptor.packages().contains("p"));303}304305/**306* Test .class file in unnamed package (top-level directory)307*/308@Test(expectedExceptions = FindException.class)309public void testClassInUnnamedPackage() throws IOException {310Path dir = Files.createTempDirectory(USER_DIR, "mods");311createDummyJarFile(dir.resolve("m.jar"), "Mojo.class");312ModuleFinder finder = ModuleFinder.of(dir);313finder.findAll();314}315316/**317* Test JAR file with META-INF/services configuration file318*/319public void testServicesConfiguration() throws IOException {320String service = "p.S";321String provider = "p.S1";322323Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");324325// provider class326Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class");327Files.createDirectories(providerClass.getParent());328Files.createFile(providerClass);329330// services configuration file331Path services = tmpdir.resolve("META-INF").resolve("services");332Files.createDirectories(services);333Files.write(services.resolve(service), Set.of(provider));334335Path dir = Files.createTempDirectory(USER_DIR, "mods");336JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);337338ModuleFinder finder = ModuleFinder.of(dir);339340Optional<ModuleReference> mref = finder.find("m");341assertTrue(mref.isPresent(), "m not found");342343ModuleDescriptor descriptor = mref.get().descriptor();344assertTrue(descriptor.provides().size() == 1);345ModuleDescriptor.Provides provides = descriptor.provides().iterator().next();346assertEquals(provides.service(), service);347assertTrue(provides.providers().size() == 1);348assertTrue(provides.providers().contains((provider)));349}350351// META-INF/services files that don't map to legal service names352@DataProvider(name = "badservices")353public Object[][] createBadServices() {354return new Object[][] {355356// service type provider type357{ "-", "p.S1" },358{ ".S", "p.S1" },359};360}361362/**363* Test JAR file with META-INF/services configuration file with bad364* values or names.365*/366@Test(dataProvider = "badservices")367public void testBadServicesNames(String service, String provider)368throws IOException369{370Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");371Path services = tmpdir.resolve("META-INF").resolve("services");372Files.createDirectories(services);373Files.write(services.resolve(service), Set.of(provider));374Path dir = Files.createTempDirectory(USER_DIR, "mods");375JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);376377Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");378assertTrue(omref.isPresent());379ModuleDescriptor descriptor = omref.get().descriptor();380assertTrue(descriptor.provides().isEmpty());381}382383// META-INF/services configuration file entries that are not legal384@DataProvider(name = "badproviders")385public Object[][] createBadProviders() {386return new Object[][] {387388// service type provider type389{ "p.S", "-" },390{ "p.S", "p..S1" },391{ "p.S", "S1." },392};393}394395/**396* Test JAR file with META-INF/services configuration file with bad397* values or names.398*/399@Test(dataProvider = "badproviders", expectedExceptions = FindException.class)400public void testBadProviderNames(String service, String provider)401throws IOException402{403Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");404405// provider class406Path providerClass = tmpdir.resolve(provider.replace('.', '/') + ".class");407Files.createDirectories(providerClass.getParent());408Files.createFile(providerClass);409410// services configuration file411Path services = tmpdir.resolve("META-INF").resolve("services");412Files.createDirectories(services);413Files.write(services.resolve(service), Set.of(provider));414415Path dir = Files.createTempDirectory(USER_DIR, "mods");416JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);417418// should throw FindException419ModuleFinder.of(dir).findAll();420}421422/**423* Test JAR file with META-INF/services configuration file listing a424* provider that is not in the module.425*/426@Test(expectedExceptions = FindException.class)427public void testMissingProviderPackage() throws IOException {428Path tmpdir = Files.createTempDirectory(USER_DIR, "tmp");429430// services configuration file431Path services = tmpdir.resolve("META-INF").resolve("services");432Files.createDirectories(services);433Files.write(services.resolve("p.S"), Set.of("q.P"));434435Path dir = Files.createTempDirectory(USER_DIR, "mods");436JarUtils.createJarFile(dir.resolve("m.jar"), tmpdir);437438// should throw FindException439ModuleFinder.of(dir).findAll();440}441442/**443* Test that a JAR file with a Main-Class attribute results444* in a module with a main class.445*/446public void testMainClass() throws IOException {447String mainClass = "p.Main";448449Manifest man = new Manifest();450Attributes attrs = man.getMainAttributes();451attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");452attrs.put(Attributes.Name.MAIN_CLASS, mainClass);453454Path dir = Files.createTempDirectory(USER_DIR, "mods");455String entry = mainClass.replace('.', '/') + ".class";456createDummyJarFile(dir.resolve("m.jar"), man, entry);457458ModuleFinder finder = ModuleFinder.of(dir);459460Configuration parent = ModuleLayer.boot().configuration();461Configuration cf = resolve(parent, finder, "m");462463ModuleDescriptor descriptor = findDescriptor(cf, "m");464465assertTrue(descriptor.mainClass().isPresent());466assertEquals(descriptor.mainClass().get(), mainClass);467}468469// Main-Class files that do not map to a legal qualified type name470@DataProvider(name = "badmainclass")471public Object[][] createBadMainClass() {472return new Object[][] {473{ "p..Main", null },474{ "p-.Main", null },475476};477}478479/**480* Test that a JAR file with a Main-Class attribute that is not a qualified481* type name.482*/483@Test(dataProvider = "badmainclass")484public void testBadMainClass(String mainClass, String ignore) throws IOException {485Manifest man = new Manifest();486Attributes attrs = man.getMainAttributes();487attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");488attrs.put(Attributes.Name.MAIN_CLASS, mainClass);489490Path dir = Files.createTempDirectory(USER_DIR, "mods");491String entry = mainClass.replace('.', '/') + ".class";492createDummyJarFile(dir.resolve("m.jar"), man, entry);493494// bad Main-Class value should be ignored495Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");496assertTrue(omref.isPresent());497ModuleDescriptor descriptor = omref.get().descriptor();498assertFalse(descriptor.mainClass().isPresent());499}500501/**502* Test that a JAR file with a Main-Class attribute that is not in the module503*/504public void testMissingMainClassPackage() throws IOException {505Manifest man = new Manifest();506Attributes attrs = man.getMainAttributes();507attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");508attrs.put(Attributes.Name.MAIN_CLASS, "p.Main");509510Path dir = Files.createTempDirectory(USER_DIR, "mods");511createDummyJarFile(dir.resolve("m.jar"), man);512513// Main-Class should be ignored because package p is not in module514Optional<ModuleReference> omref = ModuleFinder.of(dir).find("m");515assertTrue(omref.isPresent());516ModuleDescriptor descriptor = omref.get().descriptor();517assertFalse(descriptor.mainClass().isPresent());518}519520/**521* Basic test of a configuration created with automatic modules.522* a requires b*523* a requires c*524* b*525* c*526*/527public void testConfiguration1() throws Exception {528ModuleDescriptor descriptor1529= ModuleDescriptor.newModule("a")530.requires("b")531.requires("c")532.requires("java.base")533.build();534535// b and c are automatic modules536Path dir = Files.createTempDirectory(USER_DIR, "mods");537createDummyJarFile(dir.resolve("b.jar"), "p/T.class");538createDummyJarFile(dir.resolve("c.jar"), "q/T.class");539540// module finder locates a and the modules in the directory541ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);542ModuleFinder finder2 = ModuleFinder.of(dir);543ModuleFinder finder = ModuleFinder.compose(finder1, finder2);544545Configuration parent = ModuleLayer.boot().configuration();546Configuration cf = resolve(parent, finder, "a");547548assertTrue(cf.modules().size() == 3);549assertTrue(cf.findModule("a").isPresent());550assertTrue(cf.findModule("b").isPresent());551assertTrue(cf.findModule("c").isPresent());552553ResolvedModule base = cf.findModule("java.base").get();554assertTrue(base.configuration() == ModuleLayer.boot().configuration());555ResolvedModule a = cf.findModule("a").get();556ResolvedModule b = cf.findModule("b").get();557ResolvedModule c = cf.findModule("c").get();558559// b && c only require java.base560assertTrue(b.reference().descriptor().requires().size() == 1);561assertTrue(c.reference().descriptor().requires().size() == 1);562563// readability564565assertTrue(a.reads().size() == 3);566assertTrue(a.reads().contains(base));567assertTrue(a.reads().contains(b));568assertTrue(a.reads().contains(c));569570assertTrue(b.reads().contains(a));571assertTrue(b.reads().contains(c));572testReadAllBootModules(cf, "b"); // b reads all modules in boot layer573574assertTrue(c.reads().contains(a));575assertTrue(c.reads().contains(b));576testReadAllBootModules(cf, "c"); // c reads all modules in boot layer577578}579580/**581* Basic test of a configuration created with automatic modules582* a requires b583* b requires c*584* c*585* d*586*/587public void testInConfiguration2() throws IOException {588ModuleDescriptor descriptor1589= ModuleDescriptor.newModule("a")590.requires("b")591.requires("java.base")592.build();593594ModuleDescriptor descriptor2595= ModuleDescriptor.newModule("b")596.requires("c")597.requires("java.base")598.build();599600// c and d are automatic modules601Path dir = Files.createTempDirectory(USER_DIR, "mods");602createDummyJarFile(dir.resolve("c.jar"), "p/T.class");603createDummyJarFile(dir.resolve("d.jar"), "q/T.class");604605// module finder locates a and the modules in the directory606ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);607ModuleFinder finder2 = ModuleFinder.of(dir);608ModuleFinder finder = ModuleFinder.compose(finder1, finder2);609610Configuration parent = ModuleLayer.boot().configuration();611Configuration cf = resolve(parent, finder, "a", "d");612613assertTrue(cf.modules().size() == 4);614assertTrue(cf.findModule("a").isPresent());615assertTrue(cf.findModule("b").isPresent());616assertTrue(cf.findModule("c").isPresent());617assertTrue(cf.findModule("d").isPresent());618619// c && d should only require java.base620assertTrue(findDescriptor(cf, "c").requires().size() == 1);621assertTrue(findDescriptor(cf, "d").requires().size() == 1);622623// readability624625ResolvedModule base = cf.findModule("java.base").get();626assertTrue(base.configuration() == ModuleLayer.boot().configuration());627ResolvedModule a = cf.findModule("a").get();628ResolvedModule b = cf.findModule("b").get();629ResolvedModule c = cf.findModule("c").get();630ResolvedModule d = cf.findModule("d").get();631632assertTrue(a.reads().size() == 2);633assertTrue(a.reads().contains(b));634assertTrue(a.reads().contains(base));635636assertTrue(b.reads().size() == 3);637assertTrue(b.reads().contains(c));638assertTrue(b.reads().contains(d));639assertTrue(b.reads().contains(base));640641assertTrue(c.reads().contains(a));642assertTrue(c.reads().contains(b));643assertTrue(c.reads().contains(d));644testReadAllBootModules(cf, "c"); // c reads all modules in boot layer645646assertTrue(d.reads().contains(a));647assertTrue(d.reads().contains(b));648assertTrue(d.reads().contains(c));649testReadAllBootModules(cf, "d"); // d reads all modules in boot layer650}651652/**653* Basic test of a configuration created with automatic modules654* a requires b655* b requires transitive c*656* c*657* d*658*/659public void testInConfiguration3() throws IOException {660ModuleDescriptor descriptor1661= ModuleDescriptor.newModule("a")662.requires("b")663.requires("java.base")664.build();665666ModuleDescriptor descriptor2667= ModuleDescriptor.newModule("b")668.requires(Set.of(Modifier.TRANSITIVE), "c")669.requires("java.base")670.build();671672// c and d are automatic modules673Path dir = Files.createTempDirectory(USER_DIR, "mods");674createDummyJarFile(dir.resolve("c.jar"), "p/T.class");675createDummyJarFile(dir.resolve("d.jar"), "q/T.class");676677// module finder locates a and the modules in the directory678ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);679ModuleFinder finder2 = ModuleFinder.of(dir);680ModuleFinder finder = ModuleFinder.compose(finder1, finder2);681682Configuration parent = ModuleLayer.boot().configuration();683Configuration cf = resolve(parent, finder, "a", "d");684685assertTrue(cf.modules().size() == 4);686assertTrue(cf.findModule("a").isPresent());687assertTrue(cf.findModule("b").isPresent());688assertTrue(cf.findModule("c").isPresent());689assertTrue(cf.findModule("d").isPresent());690691ResolvedModule base = cf.findModule("java.base").get();692assertTrue(base.configuration() == ModuleLayer.boot().configuration());693ResolvedModule a = cf.findModule("a").get();694ResolvedModule b = cf.findModule("b").get();695ResolvedModule c = cf.findModule("c").get();696ResolvedModule d = cf.findModule("d").get();697698// c && d should only require java.base699assertTrue(findDescriptor(cf, "c").requires().size() == 1);700assertTrue(findDescriptor(cf, "d").requires().size() == 1);701702// readability703704assertTrue(a.reads().size() == 4);705assertTrue(a.reads().contains(b));706assertTrue(a.reads().contains(c));707assertTrue(a.reads().contains(d));708assertTrue(a.reads().contains(base));709710assertTrue(b.reads().size() == 3);711assertTrue(b.reads().contains(c));712assertTrue(b.reads().contains(d));713assertTrue(b.reads().contains(base));714715assertTrue(reads(cf, "b", "c"));716assertTrue(reads(cf, "b", "d"));717assertTrue(reads(cf, "b", "java.base"));718719assertTrue(c.reads().contains(a));720assertTrue(c.reads().contains(b));721assertTrue(c.reads().contains(d));722testReadAllBootModules(cf, "c"); // c reads all modules in boot layer723724assertTrue(d.reads().contains(a));725assertTrue(d.reads().contains(b));726assertTrue(d.reads().contains(c));727testReadAllBootModules(cf, "d"); // d reads all modules in boot layer728}729730/**731* Basic test to ensure that no automatic modules are resolved when732* an automatic module is not a root or required by other modules.733*/734public void testInConfiguration4() throws IOException {735ModuleDescriptor descriptor1736= ModuleDescriptor.newModule("m1")737.requires("java.base")738.build();739740// automatic modules741Path dir = Files.createTempDirectory(USER_DIR, "mods");742createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");743createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");744createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class");745746// module finder locates m1 and the modules in the directory747ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);748ModuleFinder finder2 = ModuleFinder.of(dir);749ModuleFinder finder = ModuleFinder.compose(finder1, finder2);750751Configuration parent = ModuleLayer.boot().configuration();752Configuration cf = resolve(parent, finder, "m1");753754// ensure that no automatic module is resolved755assertTrue(cf.modules().size() == 1);756assertTrue(cf.findModule("m1").isPresent());757}758759/**760* Basic test to ensure that if an automatic module is resolved then761* all observable automatic modules are resolved.762*/763public void testInConfiguration5() throws IOException {764// m1 requires m2765ModuleDescriptor descriptor1766= ModuleDescriptor.newModule("m1")767.requires("m2").build();768769// m2 requires automatic module770ModuleDescriptor descriptor2771= ModuleDescriptor.newModule("m2")772.requires("auto1")773.build();774775// automatic modules776Path dir = Files.createTempDirectory(USER_DIR, "mods");777createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");778createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");779createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class");780781// module finder locates m1, m2, and the modules in the directory782ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);783ModuleFinder finder2 = ModuleFinder.of(dir);784ModuleFinder finder = ModuleFinder.compose(finder1, finder2);785786Configuration parent = ModuleLayer.boot().configuration();787Configuration cf = resolve(parent, finder, "m1");788789// all automatic modules should be resolved790assertTrue(cf.modules().size() == 5);791assertTrue(cf.findModule("m1").isPresent());792assertTrue(cf.findModule("m2").isPresent());793assertTrue(cf.findModule("auto1").isPresent());794assertTrue(cf.findModule("auto2").isPresent());795assertTrue(cf.findModule("auto3").isPresent());796797ResolvedModule base = parent.findModule("java.base")798.orElseThrow(() -> new RuntimeException());799ResolvedModule m1 = cf.findModule("m1").get();800ResolvedModule m2 = cf.findModule("m2").get();801ResolvedModule auto1 = cf.findModule("auto1").get();802ResolvedModule auto2 = cf.findModule("auto2").get();803ResolvedModule auto3 = cf.findModule("auto3").get();804805// m1 does not read the automatic modules806assertTrue(m1.reads().size() == 2);807assertTrue(m1.reads().contains(m2));808assertTrue(m1.reads().contains(base));809810// m2 should read all the automatic modules811assertTrue(m2.reads().size() == 4);812assertTrue(m2.reads().contains(auto1));813assertTrue(m2.reads().contains(auto2));814assertTrue(m2.reads().contains(auto3));815assertTrue(m2.reads().contains(base));816817assertTrue(auto1.reads().contains(m1));818assertTrue(auto1.reads().contains(m2));819assertTrue(auto1.reads().contains(auto2));820assertTrue(auto1.reads().contains(auto3));821assertTrue(auto1.reads().contains(base));822823assertTrue(auto2.reads().contains(m1));824assertTrue(auto2.reads().contains(m2));825assertTrue(auto2.reads().contains(auto1));826assertTrue(auto2.reads().contains(auto3));827assertTrue(auto2.reads().contains(base));828829assertTrue(auto3.reads().contains(m1));830assertTrue(auto3.reads().contains(m2));831assertTrue(auto3.reads().contains(auto1));832assertTrue(auto3.reads().contains(auto2));833assertTrue(auto3.reads().contains(base));834}835836/**837* Basic test of automatic modules in a child configuration. All automatic838* modules that are found with the before finder should be resolved. The839* automatic modules that are found by the after finder and not shadowed840* by the before finder, or parent configurations, should also be resolved.841*/842public void testInConfiguration6() throws IOException {843// m1 requires auto1844ModuleDescriptor descriptor1845= ModuleDescriptor.newModule("m1")846.requires("auto1")847.build();848849Path dir = Files.createTempDirectory(USER_DIR, "mods");850createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");851852// module finder locates m1 and auto1853ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);854ModuleFinder finder2 = ModuleFinder.of(dir);855ModuleFinder finder = ModuleFinder.compose(finder1, finder2);856857Configuration parent = ModuleLayer.boot().configuration();858Configuration cf1 = resolve(parent, finder, "m1");859860assertTrue(cf1.modules().size() == 2);861assertTrue(cf1.findModule("m1").isPresent());862assertTrue(cf1.findModule("auto1").isPresent());863864ResolvedModule base = parent.findModule("java.base")865.orElseThrow(() -> new RuntimeException());866ResolvedModule m1 = cf1.findModule("m1").get();867ResolvedModule auto1 = cf1.findModule("auto1").get();868869assertTrue(m1.reads().size() == 2);870assertTrue(m1.reads().contains(auto1));871assertTrue(m1.reads().contains(base));872873assertTrue(auto1.reads().contains(m1));874assertTrue(auto1.reads().contains(base));875876877// create child configuration - the after finder locates auto1878879dir = Files.createTempDirectory(USER_DIR, "mods");880createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");881ModuleFinder beforeFinder = ModuleFinder.of(dir);882883dir = Files.createTempDirectory(USER_DIR, "mods");884createDummyJarFile(dir.resolve("auto1.jar"), "p1/C.class");885createDummyJarFile(dir.resolve("auto2.jar"), "p2/C.class");886createDummyJarFile(dir.resolve("auto3.jar"), "p3/C.class");887ModuleFinder afterFinder = ModuleFinder.of(dir);888889Configuration cf2 = cf1.resolve(beforeFinder, afterFinder, Set.of("auto2"));890891// auto1 should be found in parent and should not be in cf2892assertTrue(cf2.modules().size() == 2);893assertTrue(cf2.findModule("auto2").isPresent());894assertTrue(cf2.findModule("auto3").isPresent());895896ResolvedModule auto2 = cf2.findModule("auto2").get();897ResolvedModule auto3 = cf2.findModule("auto3").get();898899assertTrue(auto2.reads().contains(m1));900assertTrue(auto2.reads().contains(auto1));901assertTrue(auto2.reads().contains(auto3));902assertTrue(auto2.reads().contains(base));903904assertTrue(auto3.reads().contains(m1));905assertTrue(auto3.reads().contains(auto1));906assertTrue(auto3.reads().contains(auto2));907assertTrue(auto3.reads().contains(base));908}909910/**911* Basic test for a module requiring an automatic module in a parent912* configuration. If an explicit module in a child configuration reads an913* automatic module in a parent configuration then it should read all914* automatic modules in the parent configuration.915*/916public void testInConfiguration7() throws Exception {917// m1 requires auto1918ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1")919.requires("auto1")920.build();921922Path dir1 = Files.createTempDirectory(USER_DIR, "mods");923createDummyJarFile(dir1.resolve("auto1.jar"), "p1/C.class");924createDummyJarFile(dir1.resolve("auto2.jar"), "p2/C.class");925926// module finder locates m1, auto1, and auto2927ModuleFinder finder1 = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1),928ModuleFinder.of(dir1));929930Configuration parent = ModuleLayer.boot().configuration();931ResolvedModule base = parent.findModule("java.base").orElseThrow();932933Configuration cf1 = resolve(parent, finder1, "m1");934assertTrue(cf1.modules().size() == 3);935936ResolvedModule m1 = cf1.findModule("m1").orElseThrow();937ResolvedModule auto1 = cf1.findModule("auto1").orElseThrow();938ResolvedModule auto2 = cf1.findModule("auto2").orElseThrow();939940assertTrue(m1.reads().size() == 3);941assertTrue(m1.reads().contains(base));942assertTrue(m1.reads().contains(auto1));943assertTrue(m1.reads().contains(auto2));944945assertTrue(auto1.reads().contains(base));946assertTrue(auto1.reads().contains(m1));947assertTrue(auto1.reads().contains(auto2));948949assertTrue(auto2.reads().contains(base));950assertTrue(auto2.reads().contains(m1));951assertTrue(auto2.reads().contains(auto1));952953// m2 requires auto1954ModuleDescriptor descriptor2 = ModuleDescriptor.newModule("m2")955.requires("auto1")956.build();957958Path dir2 = Files.createTempDirectory(USER_DIR, "mods");959createDummyJarFile(dir1.resolve("auto3.jar"), "p3/C.class");960961// module finder locates m2 and auto3962ModuleFinder finder2 = ModuleFinder.compose(ModuleUtils.finderOf(descriptor2),963ModuleFinder.of(dir2));964965Configuration cf2 = resolve(cf1, finder2, "m2");966assertTrue(cf2.modules().size() == 1); // auto3 should not be resolved967968ResolvedModule m2 = cf2.findModule("m2").orElseThrow();969970assertTrue(m2.reads().size() == 3);971assertTrue(m2.reads().contains(base));972assertTrue(m2.reads().contains(auto1));973assertTrue(m2.reads().contains(auto2));974}975976/**977* Basic test of a configuration created with automatic modules978* a requires b* and c*979* b* contains p980* c* contains p981*/982@Test(expectedExceptions = { ResolutionException.class })983public void testDuplicateSuppliers1() throws IOException {984ModuleDescriptor descriptor985= ModuleDescriptor.newModule("a")986.requires("b")987.requires("c")988.build();989990// c and d are automatic modules with the same package991Path dir = Files.createTempDirectory(USER_DIR, "mods");992createDummyJarFile(dir.resolve("b.jar"), "p/T.class");993createDummyJarFile(dir.resolve("c.jar"), "p/T.class");994995// module finder locates 'a' and the modules in the directory996ModuleFinder finder997= ModuleFinder.compose(ModuleUtils.finderOf(descriptor),998ModuleFinder.of(dir));9991000Configuration parent = ModuleLayer.boot().configuration();1001resolve(parent, finder, "a");1002}10031004/**1005* Basic test of a configuration created with automatic modules1006* a contains p, requires b*1007* b* contains p1008*/1009@Test(expectedExceptions = { ResolutionException.class })1010public void testDuplicateSuppliers2() throws IOException {1011ModuleDescriptor descriptor1012= ModuleDescriptor.newModule("a")1013.packages(Set.of("p"))1014.requires("b")1015.build();10161017// c and d are automatic modules with the same package1018Path dir = Files.createTempDirectory(USER_DIR, "mods");1019createDummyJarFile(dir.resolve("b.jar"), "p/T.class");10201021// module finder locates 'a' and the modules in the directory1022ModuleFinder finder1023= ModuleFinder.compose(ModuleUtils.finderOf(descriptor),1024ModuleFinder.of(dir));10251026Configuration parent = ModuleLayer.boot().configuration();1027resolve(parent, finder, "a");1028}10291030/**1031* Basic test of layer containing automatic modules1032*/1033public void testInLayer() throws IOException {1034ModuleDescriptor descriptor1035= ModuleDescriptor.newModule("a")1036.requires("b")1037.requires("c")1038.build();10391040// b and c are simple JAR files1041Path dir = Files.createTempDirectory(USER_DIR, "mods");1042createDummyJarFile(dir.resolve("b.jar"), "p/T.class");1043createDummyJarFile(dir.resolve("c.jar"), "q/T2.class");10441045// module finder locates a and the modules in the directory1046ModuleFinder finder1047= ModuleFinder.compose(ModuleUtils.finderOf(descriptor),1048ModuleFinder.of(dir));10491050Configuration parent = ModuleLayer.boot().configuration();1051Configuration cf = resolve(parent, finder, "a");1052assertTrue(cf.modules().size() == 3);10531054// each module gets its own loader1055ModuleLayer layer = ModuleLayer.boot().defineModules(cf, mn -> new ClassLoader() { });10561057// an unnamed module1058Module unnamed = (new ClassLoader() { }).getUnnamedModule();10591060Module b = layer.findModule("b").get();1061assertTrue(b.isNamed());1062assertTrue(b.canRead(unnamed));1063testsReadsAll(b, layer);10641065Module c = layer.findModule("c").get();1066assertTrue(c.isNamed());1067assertTrue(b.canRead(unnamed));1068testsReadsAll(c, layer);1069}10701071/**1072* Test miscellaneous methods.1073*/1074public void testMisc() throws IOException {1075Path dir = Files.createTempDirectory(USER_DIR, "mods");1076Path m_jar = createDummyJarFile(dir.resolve("m.jar"), "p/T.class");10771078ModuleFinder finder = ModuleFinder.of(m_jar);10791080assertTrue(finder.find("m").isPresent());1081ModuleDescriptor m = finder.find("m").get().descriptor();10821083// test miscellaneous methods1084assertTrue(m.isAutomatic());1085assertFalse(m.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC));1086}10871088/**1089* Invokes parent.resolve to resolve the given root modules.1090*/1091static Configuration resolve(Configuration parent,1092ModuleFinder finder,1093String... roots) {1094return parent.resolve(finder, ModuleFinder.of(), Set.of(roots));1095}10961097/**1098* Finds a module in the given configuration or its parents, returning1099* the module descriptor (or null if not found)1100*/1101static ModuleDescriptor findDescriptor(Configuration cf, String name) {1102Optional<ResolvedModule> om = cf.findModule(name);1103if (om.isPresent()) {1104return om.get().reference().descriptor();1105} else {1106return null;1107}1108}11091110/**1111* Test that a module in a configuration reads all modules in the boot1112* configuration.1113*/1114static void testReadAllBootModules(Configuration cf, String mn) {11151116Set<String> bootModules = ModuleLayer.boot().modules().stream()1117.map(Module::getName)1118.collect(Collectors.toSet());11191120bootModules.forEach(other -> assertTrue(reads(cf, mn, other)));11211122}11231124/**1125* Test that the given Module reads all module in the given layer1126* and its parent layers.1127*/1128static void testsReadsAll(Module m, ModuleLayer layer) {1129// check that m reads all modules in the layer1130layer.configuration().modules().stream()1131.map(ResolvedModule::name)1132.map(layer::findModule)1133.map(Optional::get)1134.forEach(other -> assertTrue(m.canRead(other)));11351136// also check parent layers1137layer.parents().forEach(l -> testsReadsAll(m, l));1138}11391140/**1141* Returns {@code true} if the configuration contains module mn11142* that reads module mn2.1143*/1144static boolean reads(Configuration cf, String mn1, String mn2) {1145Optional<ResolvedModule> om = cf.findModule(mn1);1146if (!om.isPresent())1147return false;11481149return om.get().reads().stream()1150.map(ResolvedModule::name)1151.anyMatch(mn2::equals);1152}11531154/**1155* Creates a JAR file, optionally with a manifest, and with the given1156* entries. The entries will be empty in the resulting JAR file.1157*/1158static Path createDummyJarFile(Path jarfile, Manifest man, String... entries)1159throws IOException1160{1161Path dir = Files.createTempDirectory(USER_DIR, "tmp");11621163for (String entry : entries) {1164Path file = dir.resolve(entry);1165Path parent = file.getParent();1166if (parent != null)1167Files.createDirectories(parent);1168Files.createFile(file);1169}11701171Path[] paths = Stream.of(entries).map(Path::of).toArray(Path[]::new);1172JarUtils.createJarFile(jarfile, man, dir, paths);1173return jarfile;1174}11751176/**1177* Creates a JAR file and with the given entries. The entries will be empty1178* in the resulting JAR file.1179*/1180static Path createDummyJarFile(Path jarfile, String... entries)1181throws IOException1182{1183return createDummyJarFile(jarfile, null, entries);1184}11851186}118711881189