/** * Basic test for detecting cycles involving a service provider module */ @Test(expectedExceptions = { ResolutionException.class }) public void testCycleInProvider() { ModuleDescriptor descriptor1 = newBuilder("m1") .exports("p") .uses("p.S") .build(); ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .requires("m3") .provides("p.S", List.of("q.T")) .build(); ModuleDescriptor descriptor3 = newBuilder("m3") .requires("m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); // should throw ResolutionException because of the m2 <--> m3 cycle resolveAndBind(finder, "m1"); }
/** * Basic test to detect reading a module with the same name as itself * * The test consists of three configurations: * - Configuration cf1: m1, m2 requires transitive m1 * - Configuration cf2: m1 requires m2 */ @Test(expectedExceptions = { ResolutionException.class }) public void testReadModuleWithSameNameAsSelf() { ModuleDescriptor descriptor1_v1 = newBuilder("m1") .build(); ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleDescriptor descriptor1_v2 = newBuilder("m1") .requires("m2") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1_v1, descriptor2); Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 2); // resolve should throw ResolutionException ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1_v2); resolve(cf1, finder2, "m1"); }
/** * Test two modules exporting package p to a module that reads both. */ @Test(expectedExceptions = { ResolutionException.class }) public void testPackageSuppliedByTwoOthers() { ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .requires("m3") .build(); ModuleDescriptor descriptor2 = newBuilder("m2") .exports("p") .build(); ModuleDescriptor descriptor3 = newBuilder("m3") .exports("p", Set.of("m1")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); // m2 and m3 export package p to module m1 resolve(finder, "m1"); }
/** * Test the scenario where a module contains a package p and reads * a module that exports package p. */ @Test(expectedExceptions = { ResolutionException.class }) public void testPackageSuppliedBySelfAndOther() { ModuleDescriptor descriptor1 = newBuilder("m1") .requires("m2") .packages(Set.of("p")) .build(); ModuleDescriptor descriptor2 = newBuilder("m2") .exports("p") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m1 contains package p, module m2 exports package p to m1 resolve(finder, "m1"); }
/** * Test "uses p.S" where p is contained in a different module. */ @Test(expectedExceptions = { ResolutionException.class }) public void testContainsService2() { ModuleDescriptor descriptor1 = newBuilder("m1") .packages(Set.of("p")) .build(); ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .uses("p.S") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m2 does not read a module that exports p resolve(finder, "m2"); }
/** * Test "provides p.S" where p is contained in a different module. */ @Test(expectedExceptions = { ResolutionException.class }) public void testContainsService4() { ModuleDescriptor descriptor1 = newBuilder("m1") .packages(Set.of("p")) .build(); ModuleDescriptor descriptor2 = newBuilder("m2") .requires("m1") .provides("p.S", List.of("q.S1")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m2 does not read a module that exports p resolve(finder, "m2"); }
/** * Basic test of a configuration created with automatic modules * a requires b* and c* * b* contains p * c* contains p */ @Test(expectedExceptions = { ResolutionException.class }) public void testDuplicateSuppliers1() throws IOException { ModuleDescriptor descriptor = ModuleDescriptor.newModule("a") .requires("b") .requires("c") .build(); // c and d are automatic modules with the same package Path dir = Files.createTempDirectory(USER_DIR, "mods"); createDummyJarFile(dir.resolve("b.jar"), "p/T.class"); createDummyJarFile(dir.resolve("c.jar"), "p/T.class"); // module finder locates 'a' and the modules in the directory ModuleFinder finder = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), ModuleFinder.of(dir)); Configuration parent = ModuleLayer.boot().configuration(); resolve(parent, finder, "a"); }
/** * Basic test of a configuration created with automatic modules * a contains p, requires b* * b* contains p */ @Test(expectedExceptions = { ResolutionException.class }) public void testDuplicateSuppliers2() throws IOException { ModuleDescriptor descriptor = ModuleDescriptor.newModule("a") .packages(Set.of("p")) .requires("b") .build(); // c and d are automatic modules with the same package Path dir = Files.createTempDirectory(USER_DIR, "mods"); createDummyJarFile(dir.resolve("b.jar"), "p/T.class"); // module finder locates 'a' and the modules in the directory ModuleFinder finder = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), ModuleFinder.of(dir)); Configuration parent = ModuleLayer.boot().configuration(); resolve(parent, finder, "a"); }
Hasher(ModuleFinder finder) { this.moduleFinder = finder; // Determine the modules that matches the pattern {@code modulesToHash} this.modules = moduleFinder.findAll().stream() .map(mref -> mref.descriptor().name()) .filter(mn -> options.modulesToHash.matcher(mn).find()) .collect(Collectors.toSet()); // a map from a module name to Path of the packaged module this.moduleNameToPath = moduleFinder.findAll().stream() .map(mref -> mref.descriptor().name()) .collect(Collectors.toMap(Function.identity(), mn -> moduleToPath(mn))); // get a resolved module graph Configuration config = null; try { config = Configuration.empty() .resolveRequires(ModuleFinder.ofSystem(), moduleFinder, modules); } catch (ResolutionException e) { warning("warn.module.resolution.fail", e.getMessage()); } this.configuration = config; }
/** * Service provider dependency not found */ @Test(expectedExceptions = { ResolutionException.class }) public void testServiceProviderDependencyNotFound() { // service provider dependency (on m3) not found ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1") .exports("p") .uses("p.S") .build(); ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder("m2") .requires("m1") .requires("m3") .conceals("q") .provides("p.S", "q.T") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // should throw ResolutionException because m3 is not found Configuration cf = resolveRequiresAndUses(finder, "m1"); }
/** * Test two modules exporting package p to a module that reads both. */ @Test(expectedExceptions = { ResolutionException.class }) public void testPackageSuppliedByTwoOthers() { ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1") .requires("m2") .requires("m3") .build(); ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder("m2") .exports("p") .build(); ModuleDescriptor descriptor3 = new ModuleDescriptor.Builder("m3") .exports("p", "m1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); // m2 and m3 export package p to module m1 resolveRequires(finder, "m1"); }
/** * Test the scenario where a module has a concealed package p and reads * a module that exports package p. */ @Test(expectedExceptions = { ResolutionException.class }) public void testPackageSuppliedBySelfAndOther() { ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1") .requires("m2") .conceals("p") .build(); ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder("m2") .exports("p") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m1 contains package p, module m2 exports package p to m1 resolveRequires(finder, "m1"); }
/** * Test the scenario where a module that exports a package that is also * exported by a module that it reads in a parent layer. */ @Test(expectedExceptions = { ResolutionException.class }) public void testExportSamePackageAsBootLayer() { ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1") .requires("java.base") .exports("java.lang") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor); Configuration bootConfiguration = Layer.boot().configuration(); // m1 contains package java.lang, java.base exports package java.lang to m1 resolveRequires(bootConfiguration, finder, "m1"); }
/** * Test "uses p.S" where p is a concealed package in a different module. */ @Test(expectedExceptions = { ResolutionException.class }) public void testConcealedService2() { ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1") .conceals("p") .build(); ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder("m2") .requires("m1") .uses("p.S") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m2 does not read a module that exports p resolveRequires(finder, "m2"); }
/** * Test "provides p.S" where p is a concealed package in a different module. */ @Test(expectedExceptions = { ResolutionException.class }) public void testConcealedService4() { ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1") .conceals("p") .build(); ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder("m2") .requires("m1") .conceals("q") .provides("p.S", "q.S1") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // m2 does not read a module that exports p resolveRequires(finder, "m2"); }
/** * Test "provides p.S" where p is not local */ @Test(expectedExceptions = { ResolutionException.class }) public void testProviderPackageNotLocal() { ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1") .exports("p") .exports("q") .build(); ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder("m2") .requires("m1") .provides("p.S", "q.T") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); // q.T not in module m2 resolveRequires(finder, "m2"); }
/** * Constructs a Hasher to compute hashes. * * If a module name `M` is specified, it will compute the hashes of * modules that depend upon M directly or indirectly matching the * specified --hash-modules pattern and record in the ModuleHashes * attribute in M's module-info.class. * * @param name name of the module to record hashes * @param finder module finder for the specified --module-path */ Hasher(String name, ModuleFinder finder) { // Determine the modules that matches the pattern {@code modulesToHash} Set<String> roots = finder.findAll().stream() .map(mref -> mref.descriptor().name()) .filter(mn -> options.modulesToHash.matcher(mn).find()) .collect(Collectors.toSet()); // use system module path unless it creates a JMOD file for // a module that is present in the system image e.g. upgradeable // module ModuleFinder system; if (name != null && ModuleFinder.ofSystem().find(name).isPresent()) { system = ModuleFinder.of(); } else { system = ModuleFinder.ofSystem(); } // get a resolved module graph Configuration config = null; try { config = Configuration.empty().resolve(system, finder, roots); } catch (FindException | ResolutionException e) { throw new CommandException("err.module.resolution.fail", e.getMessage()); } this.moduleName = name; this.configuration = config; // filter modules resolved from the system module finder this.modules = config.modules().stream() .map(ResolvedModule::name) .filter(mn -> roots.contains(mn) && !system.find(mn).isPresent()) .collect(Collectors.toSet()); this.hashesBuilder = new ModuleHashesBuilder(config, modules); }
/** * Simple cycle. */ @Test(expectedExceptions = { ResolutionException.class }) public void testSimpleCycle() { ModuleDescriptor descriptor1 = newBuilder("m1").requires("m2").build(); ModuleDescriptor descriptor2 = newBuilder("m2").requires("m3").build(); ModuleDescriptor descriptor3 = newBuilder("m3").requires("m1").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); resolve(finder, "m1"); }
/** * Basic test to detect reading two modules with the same name * * The test consists of three configurations: * - Configuration cf1: m1, m2 requires transitive m1 * - Configuration cf2: m1, m3 requires transitive m1 * - Configuration cf3(cf1,cf2): m4 requires m2, m3 */ @Test(expectedExceptions = { ResolutionException.class }) public void testReadTwoModuleWithSameName() { ModuleDescriptor descriptor1 = newBuilder("m1") .build(); ModuleDescriptor descriptor2 = newBuilder("m2") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleDescriptor descriptor3 = newBuilder("m3") .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1") .build(); ModuleDescriptor descriptor4 = newBuilder("m4") .requires("m2") .requires("m3") .build(); ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); Configuration cf1 = resolve(finder1, "m2"); assertTrue(cf1.modules().size() == 2); ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3); Configuration cf2 = resolve(finder2, "m3"); assertTrue(cf2.modules().size() == 2); // should throw ResolutionException as m4 will read modules named "m1". ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4); Configuration.resolve(finder3, List.of(cf1, cf2), ModuleFinder.of(), Set.of("m4")); }
/** * Test the scenario where a module that exports a package that is also * exported by a module that it reads in a parent layer. */ @Test(expectedExceptions = { ResolutionException.class }) public void testExportSamePackageAsBootLayer() { ModuleDescriptor descriptor = newBuilder("m1") .requires("java.base") .exports("java.lang") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor); Configuration bootConfiguration = ModuleLayer.boot().configuration(); // m1 contains package java.lang, java.base exports package java.lang to m1 resolve(bootConfiguration, finder, "m1"); }
/** * Test "uses p.S" where p is not exported to the module. */ @Test(expectedExceptions = { ResolutionException.class }) public void testServiceTypePackageNotExported1() { ModuleDescriptor descriptor1 = newBuilder("m1") .uses("p.S") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); // m1 does not read a module that exports p resolve(finder, "m1"); }
/** * Test "provides p.S" where p is not exported to the module. */ @Test(expectedExceptions = { ResolutionException.class }) public void testServiceTypePackageNotExported2() { ModuleDescriptor descriptor1 = newBuilder("m1") .provides("p.S", List.of("q.T")) .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); // m1 does not read a module that exports p resolve(finder, "m1"); }
/** * Direct dependency not found */ @Test(expectedExceptions = { ResolutionException.class }) public void testDirectDependencyNotFound() { ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1").requires("m2").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); resolveRequires(finder, "m1"); }
/** * Transitive dependency not found */ @Test(expectedExceptions = { ResolutionException.class }) public void testTransitiveDependencyNotFound() { ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1").requires("m2").build(); ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder("m2").requires("m3").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); resolveRequires(finder, "m1"); }
/** * Simple cycle. */ @Test(expectedExceptions = { ResolutionException.class }) public void testSimpleCycle() { ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1").requires("m2").build(); ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder("m2").requires("m3").build(); ModuleDescriptor descriptor3 = new ModuleDescriptor.Builder("m3").requires("m1").build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); resolveRequires(finder, "m1"); }
/** * Basic test for detecting cycles involving a service provider module */ @Test(expectedExceptions = { ResolutionException.class }) public void testCycleInProvider() { ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1") .exports("p") .uses("p.S") .build(); ModuleDescriptor descriptor2 = new ModuleDescriptor.Builder("m2") .requires("m1") .requires("m3") .conceals("q") .provides("p.S", "q.T") .build(); ModuleDescriptor descriptor3 = new ModuleDescriptor.Builder("m3") .requires("m2") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); // should throw ResolutionException because of the m2 <--> m3 cycle resolveRequiresAndUses(finder, "m1"); }
/** * Test "uses p.S" where p is not exported to the module. */ @Test(expectedExceptions = { ResolutionException.class }) public void testServiceTypePackageNotExported1() { ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1") .uses("p.S") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); // m1 does not read a module that exports p resolveRequires(finder, "m1"); }
/** * Test "provides p.S" where p is not exported to the module. */ @Test(expectedExceptions = { ResolutionException.class }) public void testServiceTypePackageNotExported2() { ModuleDescriptor descriptor1 = new ModuleDescriptor.Builder("m1") .conceals("q") .provides("p.S", "q.T") .build(); ModuleFinder finder = ModuleUtils.finderOf(descriptor1); // m1 does not read a module that exports p resolveRequires(finder, "m1"); }
Hasher(ModuleDescriptor descriptor, String fname) throws IOException { // Create a module finder that finds the modular JAR // being created/updated URI uri = Paths.get(fname).toUri(); ModuleReference mref = new ModuleReference(descriptor, uri, new Supplier<>() { @Override public ModuleReader get() { throw new UnsupportedOperationException("should not reach here"); } }); // Compose a module finder with the module path and // the modular JAR being created or updated this.finder = ModuleFinder.compose(moduleFinder, new ModuleFinder() { @Override public Optional<ModuleReference> find(String name) { if (descriptor.name().equals(name)) return Optional.of(mref); else return Optional.empty(); } @Override public Set<ModuleReference> findAll() { return Collections.singleton(mref); } }); // Determine the modules that matches the modulesToHash pattern this.modules = moduleFinder.findAll().stream() .map(moduleReference -> moduleReference.descriptor().name()) .filter(mn -> modulesToHash.matcher(mn).find()) .collect(Collectors.toSet()); // a map from a module name to Path of the modular JAR this.moduleNameToPath = moduleFinder.findAll().stream() .map(ModuleReference::descriptor) .map(ModuleDescriptor::name) .collect(Collectors.toMap(Function.identity(), mn -> moduleToPath(mn))); Configuration config = null; try { config = Configuration.empty() .resolveRequires(ModuleFinder.ofSystem(), finder, modules); } catch (ResolutionException e) { // should it throw an error? or emit a warning System.out.println("warning: " + e.getMessage()); } this.configuration = config; }
/** * Root module not found */ @Test(expectedExceptions = { ResolutionException.class }) public void testRootNotFound() { resolveRequires(ModuleFinder.of(), "m1"); }
/** * Test attempting to create a configuration with modules for different * platforms. */ @Test(dataProvider = "platformmismatch", expectedExceptions = ResolutionException.class ) public void testPlatformMisMatch(String s1, String s2) { testPlatformMatch(s1, s2); }