--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java Mon Sep 26 13:18:11 2016 -0700
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Analyzer.java Mon Sep 26 13:39:50 2016 -0700
@@ -256,7 +256,7 @@
// return classname or package name depending on the level
private String getLocationName(Location o) {
if (level == Type.CLASS || level == Type.VERBOSE) {
- return o.getClassName();
+ return VersionHelper.get(o.getClassName());
} else {
String pkg = o.getPackageName();
return pkg.isEmpty() ? "<unnamed>" : pkg;
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Archive.java Mon Sep 26 13:18:11 2016 -0700
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Archive.java Mon Sep 26 13:39:50 2016 -0700
@@ -45,9 +45,9 @@
* Represents the source of the class files.
*/
public class Archive implements Closeable {
- public static Archive getInstance(Path p) {
+ public static Archive getInstance(Path p, Runtime.Version version) {
try {
- return new Archive(p, ClassFileReader.newInstance(p));
+ return new Archive(p, ClassFileReader.newInstance(p, version));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java Mon Sep 26 13:18:11 2016 -0700
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/ClassFileReader.java Mon Sep 26 13:39:50 2016 -0700
@@ -29,6 +29,8 @@
import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.classfile.Dependencies.ClassFileError;
+import jdk.internal.util.jar.VersionedStream;
+
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
@@ -50,6 +52,7 @@
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import java.util.zip.ZipFile;
/**
* ClassFileReader reads ClassFile(s) of a given path that can be
@@ -60,6 +63,13 @@
* Returns a ClassFileReader instance of a given path.
*/
public static ClassFileReader newInstance(Path path) throws IOException {
+ return newInstance(path, JarFile.baseVersion());
+ }
+
+ /**
+ * Returns a ClassFileReader instance of a given path.
+ */
+ public static ClassFileReader newInstance(Path path, Runtime.Version version) throws IOException {
if (Files.notExists(path)) {
throw new FileNotFoundException(path.toString());
}
@@ -67,20 +77,13 @@
if (Files.isDirectory(path)) {
return new DirectoryReader(path);
} else if (path.getFileName().toString().endsWith(".jar")) {
- return new JarFileReader(path);
+ return new JarFileReader(path, version);
} else {
return new ClassFileReader(path);
}
}
/**
- * Returns a ClassFileReader instance of a given JarFile.
- */
- public static ClassFileReader newInstance(Path path, JarFile jf) throws IOException {
- return new JarFileReader(path, jf);
- }
-
- /**
* Returns a ClassFileReader instance of a given FileSystem and path.
*
* This method is used for reading classes from jrtfs.
@@ -302,13 +305,16 @@
static class JarFileReader extends ClassFileReader {
private final JarFile jarfile;
- JarFileReader(Path path) throws IOException {
- this(path, new JarFile(path.toFile(), false));
+ private final Runtime.Version version;
+
+ JarFileReader(Path path, Runtime.Version version) throws IOException {
+ this(path, openJarFile(path.toFile(), version), version);
}
- JarFileReader(Path path, JarFile jf) throws IOException {
+ JarFileReader(Path path, JarFile jf, Runtime.Version version) throws IOException {
super(path);
this.jarfile = jf;
+ this.version = version;
}
@Override
@@ -316,9 +322,26 @@
jarfile.close();
}
+ private static JarFile openJarFile(File f, Runtime.Version version)
+ throws IOException {
+ JarFile jf;
+ if (version == null) {
+ jf = new JarFile(f, false);
+ if (jf.isMultiRelease()) {
+ throw new MultiReleaseException("err.multirelease.option.notfound", f.getName());
+ }
+ } else {
+ jf = new JarFile(f, false, ZipFile.OPEN_READ, version);
+ if (!jf.isMultiRelease()) {
+ throw new MultiReleaseException("err.multirelease.option.exists", f.getName());
+ }
+ }
+ return jf;
+ }
+
protected Set<String> scan() {
- try (JarFile jf = new JarFile(path.toFile())) {
- return jf.stream().map(JarEntry::getName)
+ try (JarFile jf = openJarFile(path.toFile(), version)) {
+ return VersionedStream.stream(jf).map(JarEntry::getName)
.filter(n -> n.endsWith(".class"))
.collect(Collectors.toSet());
} catch (IOException e) {
@@ -348,15 +371,14 @@
}
protected ClassFile readClassFile(JarFile jarfile, JarEntry e) throws IOException {
- InputStream is = null;
- try {
- is = jarfile.getInputStream(e);
- return ClassFile.read(is);
+ try (InputStream is = jarfile.getInputStream(e)) {
+ ClassFile cf = ClassFile.read(is);
+ if (jarfile.isMultiRelease()) {
+ VersionHelper.add(jarfile, e, cf);
+ }
+ return cf;
} catch (ConstantPoolException ex) {
throw new ClassFileError(ex);
- } finally {
- if (is != null)
- is.close();
}
}
@@ -370,6 +392,21 @@
}
}
+ Enumeration<JarEntry> versionedEntries(JarFile jf) {
+ Iterator<JarEntry> it = VersionedStream.stream(jf).iterator();
+ return new Enumeration<>() {
+ @Override
+ public boolean hasMoreElements() {
+ return it.hasNext();
+ }
+
+ @Override
+ public JarEntry nextElement() {
+ return it.next();
+ }
+ };
+ }
+
class JarFileIterator implements Iterator<ClassFile> {
protected final JarFileReader reader;
protected Enumeration<JarEntry> entries;
@@ -388,7 +425,7 @@
if (jarfile == null) return;
this.jf = jarfile;
- this.entries = jf.entries();
+ this.entries = versionedEntries(jf);
this.nextEntry = nextEntry();
}
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Mon Sep 26 13:18:11 2016 -0700
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsConfiguration.java Mon Sep 26 13:39:50 2016 -0700
@@ -81,19 +81,22 @@
private final List<Archive> initialArchives = new ArrayList<>();
private final Set<Module> rootModules = new HashSet<>();
private final Configuration configuration;
+ private final Runtime.Version version;
private JdepsConfiguration(SystemModuleFinder systemModulePath,
ModuleFinder finder,
Set<String> roots,
List<Path> classpaths,
List<Archive> initialArchives,
- boolean allDefaultModules)
+ boolean allDefaultModules,
+ Runtime.Version version)
throws IOException
{
trace("root: %s%n", roots);
this.system = systemModulePath;
this.finder = finder;
+ this.version = version;
// build root set for resolution
Set<String> mods = new HashSet<>(roots);
@@ -121,7 +124,7 @@
// classpath archives
for (Path p : classpaths) {
if (Files.exists(p)) {
- Archive archive = Archive.getInstance(p);
+ Archive archive = Archive.getInstance(p, version);
addPackagesInUnnamedModule(archive);
classpathArchives.add(archive);
}
@@ -292,7 +295,7 @@
if (location.getScheme().equals("jrt")) {
reader = system.getClassReader(mn);
} else {
- reader = ClassFileReader.newInstance(Paths.get(location));
+ reader = ClassFileReader.newInstance(Paths.get(location), version);
}
builder.classes(reader);
@@ -304,6 +307,10 @@
}
}
+ public Runtime.Version getVersion() {
+ return version;
+ }
+
/*
* Close all archives e.g. JarFile
*/
@@ -476,6 +483,7 @@
ModuleFinder appModulePath;
boolean addAllApplicationModules;
boolean addAllDefaultModules;
+ Runtime.Version version;
public Builder() {
this.systemModulePath = new SystemModuleFinder();
@@ -526,8 +534,13 @@
return this;
}
+ public Builder multiRelease(Runtime.Version version) {
+ this.version = version;
+ return this;
+ }
+
public Builder addRoot(Path path) {
- Archive archive = Archive.getInstance(path);
+ Archive archive = Archive.getInstance(path, version);
if (archive.contains(MODULE_INFO)) {
paths.add(path);
} else {
@@ -569,7 +582,8 @@
rootModules,
classPaths,
initialArchives,
- addAllDefaultModules);
+ addAllDefaultModules,
+ version);
}
private static ModuleFinder createModulePathFinder(String mpaths) {
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Mon Sep 26 13:18:11 2016 -0700
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java Mon Sep 26 13:39:50 2016 -0700
@@ -36,6 +36,7 @@
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.*;
+import java.util.jar.JarFile;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -389,6 +390,23 @@
}
}
},
+ new Option(true, "--multi-release") {
+ void process(JdepsTask task, String opt, String arg) throws BadArgs {
+ if (arg.equalsIgnoreCase("base")) {
+ task.options.multiRelease = JarFile.baseVersion();
+ } else {
+ try {
+ int v = Integer.parseInt(arg);
+ if (v < 9) {
+ throw new BadArgs("err.invalid.arg.for.option", arg);
+ }
+ } catch (NumberFormatException x) {
+ throw new BadArgs("err.invalid.arg.for.option", arg);
+ }
+ task.options.multiRelease = Runtime.Version.parse(arg);
+ }
+ }
+ },
};
private static final String PROGNAME = "jdeps";
@@ -481,6 +499,9 @@
} catch (IOException e) {
e.printStackTrace();
return EXIT_CMDERR;
+ } catch (MultiReleaseException e) {
+ reportError(e.getKey(), (Object)e.getMsg());
+ return EXIT_CMDERR; // could be EXIT_ABNORMAL sometimes
} finally {
log.flush();
}
@@ -541,11 +562,16 @@
if (options.classpath != null)
builder.addClassPath(options.classpath);
+ if (options.multiRelease != null)
+ builder.multiRelease(options.multiRelease);
+
// build the root set of archives to be analyzed
for (String s : inputArgs) {
Path p = Paths.get(s);
if (Files.exists(p)) {
builder.addRoot(p);
+ } else {
+ warning("warn.invalid.arg", s);
}
}
@@ -839,6 +865,7 @@
String modulePath;
String rootModule;
Set<String> addmods = new HashSet<>();
+ Runtime.Version multiRelease;
boolean hasFilter() {
return numFilters() > 0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/MultiReleaseException.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.jdeps;
+
+/**
+ * Signals that an exception of some sort has occurred while processing
+ * a multi-release jar file.
+ *
+ * @since 9
+ */
+class MultiReleaseException extends RuntimeException {
+ private static final long serialVersionUID = 4474870142461654108L;
+ private final String key;
+ private final String[] msg;
+
+ /**
+ * Constructs an {@code MultiReleaseException} with the specified detail
+ * error message array.
+ *
+ * @param key
+ * The key that identifies the message in the jdeps.properties file
+ * @param msg
+ * The detail message array
+ */
+ public MultiReleaseException(String key, String... msg) {
+ super();
+ this.key = key;
+ this.msg = msg;
+ }
+
+ /**
+ * Returns the resource message key
+ */
+ public String getKey() {
+ return key;
+ }
+
+ /**
+ * Returns the detailed error message array.
+ *
+ * @return the detailed error message array
+ */
+ public String[] getMsg() {
+ return msg;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/VersionHelper.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.jdeps;
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.ConstantPoolException;
+import jdk.internal.misc.SharedSecrets;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+public class VersionHelper {
+ private static final String META_INF_VERSIONS = "META-INF/versions/";
+ private static final Map<String,String> nameToVersion = new ConcurrentHashMap<>();
+
+ public static String get(String classname) {
+ if (nameToVersion.containsKey(classname)) {
+ return nameToVersion.get(classname) + "/" + classname;
+ }
+ return classname;
+ }
+
+ public static void add(JarFile jarfile, JarEntry e, ClassFile cf)
+ throws ConstantPoolException
+ {
+ String realName = SharedSecrets.javaUtilJarAccess().getRealName(jarfile, e);
+ if (realName.startsWith(META_INF_VERSIONS)) {
+ int len = META_INF_VERSIONS.length();
+ int n = realName.indexOf('/', len);
+ if (n > 0) {
+ String version = realName.substring(len, n);
+ assert (Integer.parseInt(version) > 8);
+ String name = cf.getName().replace('/', '.');
+ if (nameToVersion.containsKey(name)) {
+ if (!version.equals(nameToVersion.get(name))) {
+ throw new MultiReleaseException(
+ "err.multirelease.version.associated",
+ name, nameToVersion.get(name), version
+ );
+ }
+ } else {
+ nameToVersion.put(name, version);
+ }
+ } else {
+ throw new MultiReleaseException("err.multirelease.jar.malformed",
+ jarfile.getName(), realName);
+ }
+ }
+ }
+}
--- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Mon Sep 26 13:18:11 2016 -0700
+++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties Mon Sep 26 13:39:50 2016 -0700
@@ -150,6 +150,11 @@
\ -q -quiet Do not show missing dependencies from \n\
\ -genmoduleinfo output.
+main.opt.multi-release=\
+\ --multi-release <version> Specifies the version when processing\n\
+\ multi-release jar files. <version> should\n\
+\ be integer >= 9 or base.
+
err.unknown.option=unknown option: {0}
err.missing.arg=no value given for {0}
err.invalid.arg.for.option=invalid argument for option: {0}
@@ -164,7 +169,11 @@
err.root.module.not.set=root module set empty
err.invalid.inverse.option={0} cannot be used with -inverse option
err.inverse.filter.not.set={0} cannot be used with -inverse option
-warn.invalid.arg=Path not exist: {0}
+err.multirelease.option.exists={0} is not a multi-release jar file, but the --multi-release option is set
+err.multirelease.option.notfound={0} is a multi-release jar file, but the --multi-release option is not set
+err.multirelease.version.associated=class {0} already associated with version {1}, trying to add version {2}
+err.multirelease.jar.malformed=malformed multi-release jar, {0}, bad entry: {1}
+warn.invalid.arg=Path does not exist: {0}
warn.split.package=package {0} defined in {1} {2}
warn.replace.useJDKInternals=\
JDK internal APIs are unsupported and private to JDK implementation that are\n\
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/MultiReleaseJar.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+/*
+ * @test
+ * @bug 8153654
+ * @summary Tests for jdeps tool with multi-release jar files
+ * @modules jdk.jdeps/com.sun.tools.jdeps
+ * @library mrjar mrjar/base mrjar/9 mrjar/10 mrjar/v9 mrjar/v10
+ * @build test.* p.* q.*
+ * @run testng MultiReleaseJar
+ */
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.concurrent.TimeUnit;
+
+public class MultiReleaseJar {
+ Path mrjar;
+ String testJdk;
+ String fileSep;
+ Path cmdPath;
+
+ @BeforeClass
+ public void initialize() throws Exception {
+ mrjar = Paths.get(System.getProperty("test.classes", "."), "mrjar");
+ testJdk = System.getProperty("test.jdk");
+ fileSep = System.getProperty("file.separator");
+ cmdPath = Paths.get(testJdk, "bin");
+ }
+
+ @Test
+ public void basic() throws Exception {
+ // build the jar file
+ Result r = run("jar -cf Version.jar -C base test --release 9 -C 9 test --release 10 -C 10 test");
+ checkResult(r);
+
+ // try out a bunch of things
+ r = run("jdeps --multi-release 9 -v missing.jar");
+ checkResult(r, false, "Warning: Path does not exist: missing.jar");
+
+ r = run("jdeps -v Version.jar");
+ checkResult(r, false, "the --multi-release option is not set");
+
+ r = run("jdeps --multi-release base -v Version.jar");
+ checkResult(r, true,
+ "Version.jar ->",
+ "test.Version",
+ "test.Version"
+ );
+
+ r = run("jdeps --multi-release 9 -v Version.jar");
+ checkResult(r, true,
+ "Version.jar ->",
+ "9/test.NonPublic",
+ "9/test.NonPublic",
+ "9/test.Version",
+ "9/test.Version",
+ "9/test.Version",
+ "9/test.Version"
+ );
+
+ r = run("jdeps --multi-release 10 -v Version.jar");
+ checkResult(r, true,
+ "Version.jar ->",
+ "10/test.Version",
+ "10/test.Version",
+ "10/test.Version",
+ "10/test.Version",
+ "9/test.NonPublic",
+ "9/test.NonPublic"
+ );
+
+ r = run("jdeps --multi-release 8 -v Version.jar");
+ checkResult(r, false, "Error: invalid argument for option: 8");
+
+ r = run("jdeps --multi-release 9.1 -v Version.jar");
+ checkResult(r, false, "Error: invalid argument for option: 9.1");
+
+ r = run("jdeps -v -R -cp Version.jar test/Main.class");
+ checkResult(r, false, "the --multi-release option is not set");
+
+ r = run("jdeps -v -R -cp Version.jar -multi-release 9 test/Main.class");
+ checkResult(r, false,
+ "Error: unknown option: -multi-release",
+ "Usage: jdeps <options> <path",
+ "use -h, -?, -help, or --help"
+ );
+
+ r = run("jdeps -v -R -cp Version.jar --multi-release 9 test/Main.class");
+ checkResult(r, true,
+ "Main.class ->",
+ "Main.class ->",
+ "test.Main",
+ "test.Main",
+ "test.Main",
+ "Version.jar ->",
+ "9/test.NonPublic",
+ "9/test.NonPublic",
+ "9/test.Version",
+ "9/test.Version",
+ "9/test.Version",
+ "9/test.Version"
+ );
+
+ r = run("jdeps -v -R -cp Version.jar --multi-release 10 test/Main.class");
+ checkResult(r, true,
+ "Main.class ->",
+ "Main.class ->",
+ "test.Main",
+ "test.Main",
+ "test.Main",
+ "Version.jar ->",
+ "10/test.Version",
+ "10/test.Version",
+ "10/test.Version",
+ "10/test.Version",
+ "9/test.NonPublic",
+ "9/test.NonPublic"
+ );
+
+ r = run("jdeps -v -R -cp Version.jar --multi-release base test/Main.class");
+ checkResult(r, true,
+ "Main.class ->",
+ "Main.class ->",
+ "test.Main",
+ "test.Main",
+ "test.Main",
+ "Version.jar ->",
+ "test.Version",
+ "test.Version"
+ );
+
+ r = run("jdeps -v -R -cp Version.jar --multi-release 9.1 test/Main.class");
+ checkResult(r, false, "Error: invalid argument for option: 9.1");
+
+ // Rebuild jar without version 10
+ r = run("jar -cf Version.jar -C base test --release 9 -C 9 test");
+ checkResult(r);
+
+ // but ask for version 10
+ r = run("jdeps -v -R -cp Version.jar --multi-release 10 test/Main.class");
+ checkResult(r, true,
+ "Main.class ->",
+ "Main.class ->",
+ "test.Main",
+ "test.Main",
+ "test.Main",
+ "Version.jar ->",
+ "9/test.NonPublic",
+ "9/test.NonPublic",
+ "9/test.Version",
+ "9/test.Version",
+ "9/test.Version",
+ "9/test.Version"
+ );
+ }
+
+ @Test
+ public void ps_and_qs() throws Exception {
+ // build the jar file
+ Result r = run("jar -cf PQ.jar -C base p --release 9 -C v9 p -C v9 q --release 10 -C v10 q");
+ checkResult(r);
+
+ r = run("jdeps -v -R -cp PQ.jar --multi-release base PQ.jar");
+ checkResult(r, true,
+ "PQ.jar -> java.base",
+ "p.Foo"
+ );
+
+ r = run("jdeps -v -R -cp PQ.jar --multi-release 9 PQ.jar");
+ checkResult(r, true,
+ "PQ.jar -> java.base",
+ "9/p.Foo",
+ "9/p.Foo",
+ "9/q.Bar"
+ );
+
+
+ r = run("jdeps -v -R -cp PQ.jar --multi-release 10 PQ.jar");
+ checkResult(r, true,
+ "PQ.jar -> java.base",
+ "10/q.Bar",
+ "10/q.Bar",
+ "10/q.Gee",
+ "9/p.Foo",
+ "9/p.Foo"
+ );
+ }
+
+ static class Result {
+ final String cmd;
+ final int rc;
+ final String out;
+ final String err;
+ Result(String cmd, int rc, String out, String err) {
+ this.cmd = cmd;
+ this.rc = rc;
+ this.out = out;
+ this.err = err;
+ }
+ }
+
+ Result run(String cmd) throws Exception {
+ String[] cmds = cmd.split(" +");
+ cmds[0] = cmdPath.resolve(cmds[0]).toString();
+ ProcessBuilder pb = new ProcessBuilder(cmds);
+ pb.directory(mrjar.toFile());
+ Process p = pb.start();
+ p.waitFor(10, TimeUnit.SECONDS);
+ String out;
+ try (InputStream is = p.getInputStream()) {
+ out = new String(is.readAllBytes());
+ }
+ String err;
+ try (InputStream is = p.getErrorStream()) {
+ err = new String(is.readAllBytes());
+ }
+ return new Result(cmd, p.exitValue(), out, err);
+ }
+
+ void checkResult(Result r) throws Exception {
+ System.out.println(r.cmd);
+ System.out.println(r.out);
+ if (r.rc != 0) {
+ System.out.println(r.err);
+ throw new Exception("rc=" + r.rc);
+ }
+ System.out.println();
+ }
+
+ void checkResult(Result r, boolean checkrc, String... lines) throws Exception {
+ System.out.println(r.cmd);
+ System.out.println(r.out);
+ if (checkrc && r.rc != 0) {
+ System.out.println(r.err);
+ throw new Exception("rc=" + r.rc);
+ }
+ String[] out = r.out.split("\r?\n");
+ Assert.assertEquals(out.length, lines.length);
+ int n = 0;
+ for (String line : lines) {
+ Assert.assertTrue(out[n++].contains(line), "\"" + line + "\"");
+ }
+ System.out.println();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/mrjar/10/test/Version.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, 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 test;
+
+public class Version {
+ public int getVersion() {
+ NonPublic np = new NonPublic();
+ String ignore = np.toString();
+ return 10;
+ }
+
+ private String getStringVersion() {
+ return "10";
+ }
+
+ private void foo() {
+ if (getStringVersion() == null) throw new NullPointerException();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/mrjar/9/test/NonPublic.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, 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 test;
+
+class NonPublic {
+ public String toString() {
+ return "NonPublic";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/mrjar/9/test/Version.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, 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 test;
+
+public class Version {
+ public int getVersion() {
+ NonPublic np = new NonPublic();
+ String ignore = np.toString();
+ return 9;
+ }
+
+ private void foo() {
+ if (getVersion() != 9) throw new RuntimeException();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/mrjar/base/p/Foo.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, 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 p;
+
+// dependencies: Object
+public class Foo {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/mrjar/base/test/Version.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, 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 test;
+
+public class Version {
+ public int getVersion() {
+ return 8;
+ }
+
+ private void foo() {
+ if (getVersion() != 8) throw new IllegalStateException();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/mrjar/test/Main.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, 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 test;
+
+public class Main {
+ public void run() {
+ Version v = new Version();
+ v.getVersion();
+ }
+
+ public static void main(String[] args) {
+ (new Main()).run();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/mrjar/v10/q/Bar.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016, 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 q;
+
+// dependencies: Object, q.Gee
+class Bar {
+ Gee gee = new Gee();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/mrjar/v10/q/Gee.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, 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 q;
+
+// dependencies: Object
+class Gee {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/mrjar/v9/p/Foo.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, 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 p;
+
+// dependencies: Object, q.Bar
+public class Foo {
+ void crash() {
+ throw new RuntimeException();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/jdeps/mrjar/v9/q/Bar.java Mon Sep 26 13:39:50 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, 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 q;
+
+// dependecies: Object
+class Bar {
+}