--- old/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java 2017-03-16 12:50:14.000000000 +0000 +++ new/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java 2017-03-16 12:50:13.000000000 +0000 @@ -95,7 +95,7 @@ tool.xflag = true; } }, - new Option(false, OptionType.MAIN_OPERATION, "--print-module-descriptor", "-d") { + new Option(false, OptionType.MAIN_OPERATION, "--describe-module", "-d") { void process(Main tool, String opt, String arg) throws BadArgs { if (tool.cflag || tool.iflag || tool.tflag || tool.uflag || tool.xflag) throw new BadArgs("error.multiple.main.operations").showUsage(true); --- old/src/jdk.jartool/share/classes/sun/tools/jar/Main.java 2017-03-16 12:50:19.000000000 +0000 +++ new/src/jdk.jartool/share/classes/sun/tools/jar/Main.java 2017-03-16 12:50:18.000000000 +0000 @@ -27,6 +27,7 @@ import java.io.*; import java.lang.module.Configuration; +import java.lang.module.FindException; import java.lang.module.InvalidModuleDescriptorException; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleDescriptor.Exports; @@ -407,11 +408,11 @@ boolean found; if (fname != null) { try (ZipFile zf = new ZipFile(fname)) { - found = printModuleDescriptor(zf); + found = describeModule(zf); } } else { try (FileInputStream fin = new FileInputStream(FileDescriptor.in)) { - found = printModuleDescriptor(fin); + found = describeModule(fin); } } if (!found) @@ -603,7 +604,7 @@ int n = args.length - count; if (n > 0) { if (dflag) { - // "--print-module-descriptor/-d" does not require file argument(s) + // "--describe-module/-d" does not require file argument(s) usageError(formatMsg("error.bad.dflag", args[count])); return false; } @@ -1728,24 +1729,43 @@ .collect(joining(", ", prefix, suffix)); } - private boolean printModuleDescriptor(ZipFile zipFile) - throws IOException - { + private boolean describeModule(ZipFile zipFile) throws IOException { ZipEntry[] zes = zipFile.stream() .filter(e -> isModuleInfoEntry(e.getName())) .sorted(Validator.ENTRY_COMPARATOR) .toArray(ZipEntry[]::new); - if (zes.length == 0) - return false; - for (ZipEntry ze : zes) { - try (InputStream is = zipFile.getInputStream(ze)) { - printModuleDescriptor(is, ze.getName()); + + if (zes.length == 0) { + // No module descriptor found, derive the automatic module name + String fn = zipFile.getName(); + ModuleFinder mf = ModuleFinder.of(Paths.get(fn)); + try { + Set mref = mf.findAll(); + if (mref.isEmpty()) { + output(formatMsg("error.unable.derive.automodule", fn)); + return true; + } + ModuleDescriptor md = mref.iterator().next().descriptor(); + output(getMsg("out.automodule")); + describeModule(md, null, "automatic"); + } catch (FindException e) { + String msg = formatMsg("error.unable.derive.automodule", fn); + Throwable t = e.getCause(); + if (t != null) + msg = msg + "\n" + t.getMessage(); + output(msg); + } + } else { + for (ZipEntry ze : zes) { + try (InputStream is = zipFile.getInputStream(ze)) { + describeModule(is, ze.getName()); + } } } return true; } - private boolean printModuleDescriptor(FileInputStream fis) + private boolean describeModule(FileInputStream fis) throws IOException { try (BufferedInputStream bis = new BufferedInputStream(fis); @@ -1764,7 +1784,7 @@ .sorted(Validator.ENTRYNAME_COMPARATOR) .toArray(String[]::new); for (String name : names) { - printModuleDescriptor(new ByteArrayInputStream(moduleInfos.get(name)), name); + describeModule(new ByteArrayInputStream(moduleInfos.get(name)), name); } return true; } @@ -1775,13 +1795,21 @@ .collect(joining(" ")); } - private void printModuleDescriptor(InputStream entryInputStream, String ename) + private void describeModule(InputStream entryInputStream, String ename) throws IOException { ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null); ModuleDescriptor md = attrs.descriptor(); ModuleHashes hashes = attrs.recordedHashes(); + describeModule(md, hashes, ename); + } + + private void describeModule(ModuleDescriptor md, + ModuleHashes hashes, + String ename) + throws IOException + { StringBuilder sb = new StringBuilder(); sb.append("\nmodule ") .append(md.toNameAndVersion()) --- old/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties 2017-03-16 12:50:24.000000000 +0000 +++ new/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties 2017-03-16 12:50:23.000000000 +0000 @@ -45,7 +45,7 @@ 'e' flag and manifest with the 'Main-Class' attribute cannot be specified \n\ together! error.bad.dflag=\ - '-d, --print-module-descriptor' option requires no input file(s) to be specified: {0} + '-d, --describe-module' option requires no input file(s) to be specified: {0} error.bad.reason=\ bad reason: {0}, must be one of deprecated, deprecated-for-removal, or incubating error.nosuch.fileordir=\ @@ -62,6 +62,8 @@ Hashing module {0} dependences, unable to find module {1} on module path error.module.options.without.info=\ One of --module-version or --hash-modules without module-info.class +error.unable.derive.automodule=\ + Unable to derive module descriptor for: {0} error.unexpected.module-info=\ Unexpected module descriptor {0} error.module.descriptor.not.found=\ @@ -129,6 +131,8 @@ added manifest out.added.module-info=\ added module-info: {0} +out.automodule=\ + No module descriptor found. Derived automatic module. out.update.manifest=\ updated manifest out.update.module-info=\ @@ -224,8 +228,8 @@ \ -u, --update Update an existing jar archive main.help.opt.main.extract=\ \ -x, --extract Extract named (or all) files from the archive -main.help.opt.main.print-module-descriptor=\ -\ -d, --print-module-descriptor Print the module descriptor +main.help.opt.main.describe-module=\ +\ -d, --describe-module Print the module descriptor, or automatic module name main.help.opt.any=\ \ Operation modifiers valid in any mode:\n\ \n\ --- old/test/tools/jar/modularJar/Basic.java 2017-03-16 12:50:28.000000000 +0000 +++ new/test/tools/jar/modularJar/Basic.java 2017-03-16 12:50:27.000000000 +0000 @@ -39,6 +39,7 @@ import jdk.testlibrary.FileUtils; import jdk.testlibrary.JDKToolFinder; import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static java.lang.String.format; @@ -46,7 +47,7 @@ /* * @test - * @bug 8167328 8171830 8165640 8174248 + * @bug 8167328 8171830 8165640 8174248 8176772 * @library /lib/testlibrary * @modules jdk.compiler * jdk.jartool @@ -754,7 +755,7 @@ .assertSuccess(); - for (String option : new String[] {"--print-module-descriptor", "-d" }) { + for (String option : new String[] {"--describe-module", "-d" }) { jar(option, "--file=" + modularJar.toString()) @@ -801,8 +802,8 @@ } @Test - public void printModuleDescriptorFoo() throws IOException { - Path mp = Paths.get("printModuleDescriptorFoo"); + public void describeModuleFoo() throws IOException { + Path mp = Paths.get("describeModuleFoo"); createTestDir(mp); Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); Path modularJar = mp.resolve(FOO.moduleName + ".jar"); @@ -815,7 +816,7 @@ "-C", modClasses.toString(), ".") .assertSuccess(); - for (String option : new String[] {"--print-module-descriptor", "-d" }) { + for (String option : new String[] {"--describe-module", "-d" }) { jar(option, "--file=" + modularJar.toString()) .assertSuccess() @@ -836,8 +837,8 @@ } @Test - public void printModuleDescriptorFooFromStdin() throws IOException { - Path mp = Paths.get("printModuleDescriptorFooFromStdin"); + public void describeModuleFooFromStdin() throws IOException { + Path mp = Paths.get("describeModuleFooFromStdin"); createTestDir(mp); Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); Path modularJar = mp.resolve(FOO.moduleName + ".jar"); @@ -850,7 +851,7 @@ "-C", modClasses.toString(), ".") .assertSuccess(); - for (String option : new String[] {"--print-module-descriptor", "-d" }) { + for (String option : new String[] {"--describe-module", "-d" }) { jarWithStdin(modularJar.toFile(), option) .assertSuccess() @@ -862,6 +863,50 @@ } } + + @DataProvider(name = "autoNames") + public Object[][] autoNames() { + return new Object[][] { + // JAR file name module-name[@version] + { "foo.jar", "foo" }, + { "foo4j.jar", "foo4j", }, + { "foo1.2.3.jar", "foo" }, + { "foo-1.2.3.4.jar", "foo@1.2.3.4" }, + { "foo-bar.jar", "foo.bar" }, + { "foo-1.2-SNAPSHOT.jar", "foo@1.2-SNAPSHOT" }, + }; + } + + @Test(dataProvider = "autoNames") + public void describeAutomaticModule(String jarName, String mid) + throws IOException + { + Path mp = Paths.get("describeAutomaticModule"); + createTestDir(mp); + Path regularJar = mp.resolve(jarName); + Path t = Paths.get("t"); + if (Files.notExists(t)) + Files.createFile(t); + + jar("--create", + "--file=" + regularJar.toString(), + t.toString()) + .assertSuccess(); + + for (String option : new String[] {"--describe-module", "-d" }) { + jar(option, + "--file=" + regularJar.toString()) + .assertSuccess() + .resultChecker(r -> { + assertTrue(r.output.contains("No module descriptor found")); + assertTrue(r.output.contains("Derived automatic module")); + assertTrue(r.output.contains("module " + mid), + "Expected [", "module " + mid,"] in [", r.output, "]"); + } + ); + } + } + // -- Infrastructure static Result jarWithStdin(File stdinSource, String... args) {