8193192: jdeps --generate-module-info does not look at module path
Reviewed-by: dfuchs
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Graph.java Tue Dec 12 11:10:12 2017 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Graph.java Tue Dec 12 11:31:38 2017 -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<T> dfs(Set<T> roots) {
- Deque<T> deque = new LinkedList<>(roots);
+ Deque<T> deque = new ArrayDeque<>(roots);
Set<T> visited = new HashSet<>();
while (!deque.isEmpty()) {
T u = deque.pop();
@@ -197,7 +193,7 @@
if (includeAdjacent && isAdjacent(u, v)) {
return true;
}
- Deque<T> stack = new LinkedList<>();
+ Deque<T> stack = new ArrayDeque<>();
Set<T> visited = new HashSet<>();
stack.push(u);
while (!stack.isEmpty()) {
@@ -292,12 +288,10 @@
* Topological sort
*/
static class TopoSorter<T> {
- final Deque<T> result = new LinkedList<>();
- final Deque<T> nodes;
+ final Deque<T> result = new ArrayDeque<>();
final Graph<T> graph;
TopoSorter(Graph<T> graph) {
this.graph = graph;
- this.nodes = new LinkedList<>(graph.nodes);
sort();
}
@@ -310,17 +304,16 @@
}
private void sort() {
- Deque<T> visited = new LinkedList<>();
- Deque<T> done = new LinkedList<>();
- T node;
- while ((node = nodes.poll()) != null) {
+ Set<T> visited = new HashSet<>();
+ Set<T> done = new HashSet<>();
+ for (T node : graph.nodes()) {
if (!visited.contains(node)) {
visit(node, visited, done);
}
}
}
- private void visit(T node, Deque<T> visited, Deque<T> done) {
+ private void visit(T node, Set<T> visited, Set<T> 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);
}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Tue Dec 12 11:10:12 2017 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Tue Dec 12 11:31:38 2017 -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<String> roots,
List<Path> classpaths,
List<Archive> initialArchives,
- boolean allDefaultModules,
- boolean allSystemModules,
+ Set<String> tokens,
Runtime.Version version)
throws IOException
{
@@ -104,16 +102,13 @@
// build root set for resolution
Set<String> 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<Archive> initialArchives = new ArrayList<>();
final List<Path> paths = new ArrayList<>();
final List<Path> classPaths = new ArrayList<>();
+ final Set<String> 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<String> 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);
}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Tue Dec 12 11:10:12 2017 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Tue Dec 12 11:31:38 2017 -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<String> 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<String> 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<String> addModules() {
+ return Set.of("ALL-SYSTEM", "ALL-MODULE-PATH");
}
}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java Tue Dec 12 11:10:12 2017 -0800
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java Tue Dec 12 11:31:38 2017 -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) {
--- a/test/langtools/tools/jdeps/lib/JdepsUtil.java Tue Dec 12 11:10:12 2017 -0800
+++ b/test/langtools/tools/jdeps/lib/JdepsUtil.java Tue Dec 12 11:31:38 2017 -0800
@@ -175,7 +175,7 @@
public ModuleAnalyzer getModuleAnalyzer(Set<String> 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);
}
--- a/test/langtools/tools/jdeps/modules/GenModuleInfo.java Tue Dec 12 11:10:12 2017 -0800
+++ b/test/langtools/tools/jdeps/modules/GenModuleInfo.java Tue Dec 12 11:31:38 2017 -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<String> 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<Path> 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<Path> 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<String> files = MODULES.stream()
.map(mn -> LIBS_DIR.resolve(mn + ".jar"))
.map(Path::toString);
Stream<String> 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);
+ }
+ }
+
+ @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));
- try (InputStream in1 = Files.newInputStream(p1);
- InputStream in2 = Files.newInputStream(p2)) {
- verify(ModuleDescriptor.read(in1),
- ModuleDescriptor.read(in2, () -> packages(MODS_DIR.resolve(mn))));
- }
+ // 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))));
}
}
--- a/test/langtools/tools/jdeps/modules/GenOpenModule.java Tue Dec 12 11:10:12 2017 -0800
+++ b/test/langtools/tools/jdeps/modules/GenOpenModule.java Tue Dec 12 11:31:38 2017 -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<String> files = MODULES.stream()
.map(mn -> LIBS_DIR.resolve(mn + ".jar"))
.map(Path::toString);
Stream<String> 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 Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/jdeps/modules/src/test/jdk/test/Main.java Tue Dec 12 11:31:38 2017 -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 Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/jdeps/modules/src/test/module-info.java Tue Dec 12 11:31:38 2017 -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;
+}