--- old/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Graph.java 2017-12-07 09:06:20.000000000 -0800 +++ new/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Graph.java 2017-12-07 09:06:19.000000000 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -25,18 +25,14 @@ package com.sun.tools.jdeps; import java.io.PrintWriter; -import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleFinder; -import java.lang.module.ModuleReference; +import java.util.ArrayDeque; import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.function.Consumer; -import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -161,7 +157,7 @@ * Returns all nodes reachable from the given set of roots. */ public Set dfs(Set roots) { - Deque deque = new LinkedList<>(roots); + Deque deque = new ArrayDeque<>(roots); Set visited = new HashSet<>(); while (!deque.isEmpty()) { T u = deque.pop(); @@ -197,7 +193,7 @@ if (includeAdjacent && isAdjacent(u, v)) { return true; } - Deque stack = new LinkedList<>(); + Deque stack = new ArrayDeque<>(); Set visited = new HashSet<>(); stack.push(u); while (!stack.isEmpty()) { @@ -292,12 +288,10 @@ * Topological sort */ static class TopoSorter { - final Deque result = new LinkedList<>(); - final Deque nodes; + final Deque result = new ArrayDeque<>(); final Graph graph; TopoSorter(Graph graph) { this.graph = graph; - this.nodes = new LinkedList<>(graph.nodes); sort(); } @@ -310,17 +304,16 @@ } private void sort() { - Deque visited = new LinkedList<>(); - Deque done = new LinkedList<>(); - T node; - while ((node = nodes.poll()) != null) { + Set visited = new HashSet<>(); + Set done = new HashSet<>(); + for (T node : graph.nodes()) { if (!visited.contains(node)) { visit(node, visited, done); } } } - private void visit(T node, Deque visited, Deque done) { + private void visit(T node, Set visited, Set done) { if (visited.contains(node)) { if (!done.contains(node)) { throw new IllegalArgumentException("Cyclic detected: " + @@ -330,7 +323,7 @@ } visited.add(node); graph.edges().get(node).stream() - .forEach(x -> visit(x, visited, done)); + .forEach(x -> visit(x, visited, done)); done.add(node); result.addLast(node); } --- old/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java 2017-12-07 09:06:21.000000000 -0800 +++ new/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java 2017-12-07 09:06:21.000000000 -0800 @@ -38,8 +38,6 @@ import java.io.UncheckedIOException; import java.lang.module.Configuration; import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleDescriptor.Exports; -import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReader; import java.lang.module.ModuleReference; @@ -71,6 +69,7 @@ public static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; public static final String ALL_DEFAULT = "ALL-DEFAULT"; public static final String ALL_SYSTEM = "ALL-SYSTEM"; + public static final String MODULE_INFO = "module-info.class"; private final SystemModuleFinder system; @@ -91,8 +90,7 @@ Set roots, List classpaths, List initialArchives, - boolean allDefaultModules, - boolean allSystemModules, + Set tokens, Runtime.Version version) throws IOException { @@ -104,16 +102,13 @@ // build root set for resolution Set mods = new HashSet<>(roots); - - // add all system modules to the root set for unnamed module or set explicitly - boolean unnamed = !initialArchives.isEmpty() || !classpaths.isEmpty(); - if (allSystemModules || (unnamed && !allDefaultModules)) { + if (tokens.contains(ALL_SYSTEM)) { systemModulePath.findAll().stream() .map(mref -> mref.descriptor().name()) .forEach(mods::add); } - if (allDefaultModules) { + if (tokens.contains(ALL_DEFAULT)) { mods.addAll(systemModulePath.defaultSystemRoots()); } @@ -200,10 +195,10 @@ return m!= null ? Optional.of(m.descriptor()) : Optional.empty(); } - boolean isValidToken(String name) { + public static boolean isToken(String name) { return ALL_MODULE_PATH.equals(name) || - ALL_DEFAULT.equals(name) || - ALL_SYSTEM.equals(name); + ALL_DEFAULT.equals(name) || + ALL_SYSTEM.equals(name); } /** @@ -482,13 +477,10 @@ final List initialArchives = new ArrayList<>(); final List paths = new ArrayList<>(); final List classPaths = new ArrayList<>(); + final Set tokens = new HashSet<>(); ModuleFinder upgradeModulePath; ModuleFinder appModulePath; - boolean addAllApplicationModules; - boolean addAllDefaultModules; - boolean addAllSystemModules; - boolean allModules; Runtime.Version version; public Builder() { @@ -513,34 +505,15 @@ public Builder addmods(Set addmods) { for (String mn : addmods) { - switch (mn) { - case ALL_MODULE_PATH: - this.addAllApplicationModules = true; - break; - case ALL_DEFAULT: - this.addAllDefaultModules = true; - break; - case ALL_SYSTEM: - this.addAllSystemModules = true; - break; - default: - this.rootModules.add(mn); + if (isToken(mn)) { + tokens.add(mn); + } else { + rootModules.add(mn); } } return this; } - /* - * This method is for --check option to find all target modules specified - * in qualified exports. - * - * Include all system modules and modules found on modulepath - */ - public Builder allModules() { - this.allModules = true; - return this; - } - public Builder multiRelease(Runtime.Version version) { this.version = version; return this; @@ -579,7 +552,9 @@ .forEach(rootModules::add); } - if ((addAllApplicationModules || allModules) && appModulePath != null) { + // add all modules to the root set for unnamed module or set explicitly + boolean unnamed = !initialArchives.isEmpty() || !classPaths.isEmpty(); + if ((unnamed || tokens.contains(ALL_MODULE_PATH)) && appModulePath != null) { appModulePath.findAll().stream() .map(mref -> mref.descriptor().name()) .forEach(rootModules::add); @@ -587,7 +562,7 @@ // no archive is specified for analysis // add all system modules as root if --add-modules ALL-SYSTEM is specified - if (addAllSystemModules && rootModules.isEmpty() && + if (tokens.contains(ALL_SYSTEM) && rootModules.isEmpty() && initialArchives.isEmpty() && classPaths.isEmpty()) { systemModulePath.findAll() .stream() @@ -595,13 +570,16 @@ .forEach(rootModules::add); } + if (unnamed && !tokens.contains(ALL_DEFAULT)) { + tokens.add(ALL_SYSTEM); + } + return new JdepsConfiguration(systemModulePath, finder, rootModules, classPaths, initialArchives, - addAllDefaultModules, - allModules, + tokens, version); } --- old/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java 2017-12-07 09:06:23.000000000 -0800 +++ new/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java 2017-12-07 09:06:22.000000000 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -540,7 +540,7 @@ } boolean run() throws IOException { - try (JdepsConfiguration config = buildConfig(command.allModules())) { + try (JdepsConfiguration config = buildConfig()) { if (!options.nowarning) { // detect split packages config.splitPackages().entrySet() @@ -553,7 +553,7 @@ // check if any module specified in --add-modules, --require, and -m is missing options.addmods.stream() - .filter(mn -> !config.isValidToken(mn)) + .filter(mn -> !JdepsConfiguration.isToken(mn)) .forEach(mn -> config.findModule(mn).orElseThrow(() -> new UncheckedBadArgs(new BadArgs("err.module.not.found", mn)))); @@ -561,18 +561,14 @@ } } - private JdepsConfiguration buildConfig(boolean allModules) throws IOException { + private JdepsConfiguration buildConfig() throws IOException { JdepsConfiguration.Builder builder = new JdepsConfiguration.Builder(options.systemModulePath); builder.upgradeModulePath(options.upgradeModulePath) .appModulePath(options.modulePath) - .addmods(options.addmods); - - if (allModules) { - // check all system modules in the image - builder.allModules(); - } + .addmods(options.addmods) + .addmods(command.addModules()); if (options.classpath != null) builder.addClassPath(options.classpath); @@ -655,8 +651,8 @@ * only. The method should be overridden when this command should * analyze all modules instead. */ - boolean allModules() { - return false; + Set addModules() { + return Set.of(); } @Override @@ -871,8 +867,8 @@ * analyzed to find all modules that depend on the modules specified in the * --require option directly and indirectly */ - public boolean allModules() { - return options.requires.size() > 0; + Set addModules() { + return options.requires.size() > 0 ? Set.of("ALL-SYSTEM") : Set.of(); } } @@ -975,8 +971,8 @@ /* * Returns true to analyze all modules */ - public boolean allModules() { - return true; + Set addModules() { + return Set.of("ALL-SYSTEM", "ALL-MODULE-PATH"); } } --- old/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java 2017-12-07 09:06:25.000000000 -0800 +++ new/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java 2017-12-07 09:06:24.000000000 -0800 @@ -32,7 +32,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Optional; import java.util.Set; /** @@ -138,7 +137,7 @@ // for debugging public static void main(String[] args) throws IOException { // initialize Profiles - new JdepsConfiguration.Builder().allModules().build(); + new JdepsConfiguration.Builder().addmods(Set.of("ALL-SYSTEM")).build(); // find platform modules if (Profile.getProfileCount() == 0) { --- old/test/langtools/tools/jdeps/lib/JdepsUtil.java 2017-12-07 09:06:26.000000000 -0800 +++ new/test/langtools/tools/jdeps/lib/JdepsUtil.java 2017-12-07 09:06:26.000000000 -0800 @@ -175,7 +175,7 @@ public ModuleAnalyzer getModuleAnalyzer(Set mods) throws IOException { // if --check is set, add to the root set and all modules are observable addmods(mods); - builder.allModules(); + builder.addmods(Set.of("ALL-SYSTEM", "ALL-MODULE-PATH")); return new ModuleAnalyzer(configuration(), pw, mods); } --- old/test/langtools/tools/jdeps/modules/GenModuleInfo.java 2017-12-07 09:06:28.000000000 -0800 +++ new/test/langtools/tools/jdeps/modules/GenModuleInfo.java 2017-12-07 09:06:27.000000000 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -23,11 +23,12 @@ /* * @test - * @summary Tests jdeps --generate-module-info option + * @bug 8193192 * @library ../lib * @build CompilerUtils JdepsUtil JdepsRunner * @modules jdk.jdeps/com.sun.tools.jdeps * @run testng GenModuleInfo + * @summary Tests jdeps --generate-module-info option */ import java.io.File; @@ -58,15 +59,21 @@ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); private static final Path MODS_DIR = Paths.get("mods"); private static final Path LIBS_DIR = Paths.get("libs"); + private static final Path MLIBS_DIR = Paths.get("mlibs"); private static final Path DEST_DIR = Paths.get("moduleinfosrc"); private static final Path NEW_MODS_DIR = Paths.get("new_mods"); // the names of the modules in this test public static final String UNSUPPORTED = "unsupported"; public static final Set MODULES = Set.of( - "mI", "mII", "mIII", "provider", UNSUPPORTED + "mI", "mII", "mIII", "provider", "test", UNSUPPORTED ); + @BeforeTest + public void setup() throws Exception { + compileAndCreateJars(); + } + /** * Compile modules */ @@ -81,6 +88,21 @@ /** * Create JAR files with no module-info.class */ + public static void createModularJARs(Path mods, Path dest, String... modules) throws IOException { + Files.createDirectory(dest); + // create modular JAR + for (String mn : modules) { + Path root = mods.resolve(mn); + try (Stream stream = Files.find(root, Integer.MAX_VALUE, + (p, attr) -> { return attr.isRegularFile(); })) { + JdepsUtil.createJar(dest.resolve(mn + ".jar"), root, stream); + } + } + } + + /** + * Create JAR files with no module-info.class + */ public static List createJARFiles(Path mods, Path libs) throws IOException { Files.createDirectory(libs); @@ -141,18 +163,16 @@ } - /** - * Compiles all modules used by the test - */ - @BeforeTest - public void compileAll() throws Exception { + public static void compileAndCreateJars() throws Exception { CompilerUtils.cleanDir(MODS_DIR); CompilerUtils.cleanDir(LIBS_DIR); - CompilerUtils.cleanDir(DEST_DIR); - CompilerUtils.cleanDir(NEW_MODS_DIR); compileModules(MODS_DIR); + // create modular JARs except test + createModularJARs(MODS_DIR, MLIBS_DIR, MODULES.stream().filter(mn -> !mn.equals("test")) + .toArray(String[]::new)); + // create non-modular JARs createJARFiles(MODS_DIR, LIBS_DIR); } @@ -166,35 +186,67 @@ @Test public void test() throws IOException { - Files.createDirectory(DEST_DIR); + Path dest = DEST_DIR.resolve("case1"); + Path classes = NEW_MODS_DIR.resolve("case1"); + Files.createDirectories(dest); + Files.createDirectories(classes); Stream files = MODULES.stream() .map(mn -> LIBS_DIR.resolve(mn + ".jar")) .map(Path::toString); Stream options = Stream.concat( - Stream.of("--generate-module-info", DEST_DIR.toString()), files); + Stream.of("--generate-module-info", dest.toString()), files); JdepsRunner.run(options.toArray(String[]::new)); // check file exists MODULES.stream() - .map(mn -> DEST_DIR.resolve(mn).resolve("module-info.java")) + .map(mn -> dest.resolve(mn).resolve("module-info.java")) .forEach(f -> assertTrue(Files.exists(f))); // copy classes to a temporary directory // and then compile new module-info.java - copyClasses(MODS_DIR, NEW_MODS_DIR); - compileNewGenModuleInfo(DEST_DIR, NEW_MODS_DIR); + copyClasses(MODS_DIR, classes); + compileNewGenModuleInfo(dest, classes); for (String mn : MODULES) { - Path p1 = NEW_MODS_DIR.resolve(mn).resolve(MODULE_INFO); - Path p2 = MODS_DIR.resolve(mn).resolve(MODULE_INFO); + verify(mn, classes, MODS_DIR); + } + } - try (InputStream in1 = Files.newInputStream(p1); - InputStream in2 = Files.newInputStream(p2)) { - verify(ModuleDescriptor.read(in1), - ModuleDescriptor.read(in2, () -> packages(MODS_DIR.resolve(mn)))); - } + @Test + public void withModulePath() throws IOException { + Path dest = DEST_DIR.resolve("case2"); + Path classes = NEW_MODS_DIR.resolve("case2"); + Files.createDirectories(dest); + Files.createDirectories(classes); + + JdepsRunner.run("--module-path", MLIBS_DIR.toString(), + "--generate-module-info", dest.toString(), + LIBS_DIR.resolve("test.jar").toString()); + + String name = "test"; + Path gensrc = dest.resolve(name).resolve("module-info.java"); + assertTrue(Files.exists(gensrc)); + + // copy classes to a temporary directory + // and then compile new module-info.java + copyClasses(MODS_DIR.resolve(name), classes.resolve(name)); + assertTrue(CompilerUtils.compileModule(dest, classes, name, "-p", MLIBS_DIR.toString())); + + verify(name, classes, MODS_DIR); + } + + /** + * Verify the dependences from the given module-info.class files + */ + public void verify(String mn, Path mdir1, Path mdir2) throws IOException { + Path p1 = mdir1.resolve(mn).resolve(MODULE_INFO); + Path p2 = mdir2.resolve(mn).resolve(MODULE_INFO); + try (InputStream in1 = Files.newInputStream(p1); + InputStream in2 = Files.newInputStream(p2)) { + verify(ModuleDescriptor.read(in1), + ModuleDescriptor.read(in2, () -> packages(mdir2.resolve(mn)))); } } --- old/test/langtools/tools/jdeps/modules/GenOpenModule.java 2017-12-07 09:06:29.000000000 -0800 +++ new/test/langtools/tools/jdeps/modules/GenOpenModule.java 2017-12-07 09:06:29.000000000 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -54,41 +54,39 @@ private static final Path DEST_DIR = Paths.get("moduleinfosrc"); private static final Path NEW_MODS_DIR = Paths.get("new_mods"); - /** - * Compiles all modules used by the test - */ @BeforeTest - public void compileAll() throws Exception { - - compileModules(MODS_DIR); - - createJARFiles(MODS_DIR, LIBS_DIR); + public void setup() throws Exception { + compileAndCreateJars(); } @Test public void test() throws IOException { + Path dest = DEST_DIR.resolve("open"); + Path classes = NEW_MODS_DIR.resolve("open"); + Files.createDirectories(dest); + Files.createDirectories(classes); + Stream files = MODULES.stream() .map(mn -> LIBS_DIR.resolve(mn + ".jar")) .map(Path::toString); Stream options = Stream.concat( - Stream.of("--generate-open-module", DEST_DIR.toString()), files); + Stream.of("--generate-open-module", dest.toString()), files); JdepsRunner.run(options.toArray(String[]::new)); // check file exists MODULES.stream() - .map(mn -> DEST_DIR.resolve(mn).resolve("module-info.java")) + .map(mn -> dest.resolve(mn).resolve("module-info.java")) .forEach(f -> assertTrue(Files.exists(f))); // copy classes to a temporary directory // and then compile new module-info.java - copyClasses(MODS_DIR, NEW_MODS_DIR); - compileNewGenModuleInfo(DEST_DIR, NEW_MODS_DIR); + copyClasses(MODS_DIR, classes); + compileNewGenModuleInfo(dest, classes); for (String mn : MODULES) { - Path p1 = NEW_MODS_DIR.resolve(mn).resolve(MODULE_INFO); + Path p1 = classes.resolve(mn).resolve(MODULE_INFO); Path p2 = MODS_DIR.resolve(mn).resolve(MODULE_INFO); - try (InputStream in1 = Files.newInputStream(p1); InputStream in2 = Files.newInputStream(p2)) { verify(ModuleDescriptor.read(in1), --- /dev/null 2017-12-07 09:06:31.000000000 -0800 +++ new/test/langtools/tools/jdeps/modules/src/test/jdk/test/Main.java 2017-12-07 09:06:30.000000000 -0800 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test; + +import java.sql.Driver; + +import p1.Goo; +import p2.Bar; +import p3.Foo; + +public class Main { + public static void main(String... args) { + Goo goo = toGoo(new Bar()); + Driver driver = new Foo().getDriver(); + } + + public static Goo toGoo(Bar bar) { + return bar.toGoo(); + } +} --- /dev/null 2017-12-07 09:06:32.000000000 -0800 +++ new/test/langtools/tools/jdeps/modules/src/test/module-info.java 2017-12-07 09:06:31.000000000 -0800 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module test { + requires java.sql; + requires transitive mI; + requires transitive mII; + requires mIII; +}