--- old/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java 2017-03-14 15:10:04.000000000 +0000 +++ new/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java 2017-03-14 15:10:04.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-14 15:10:08.000000000 +0000 +++ new/src/jdk.jartool/share/classes/sun/tools/jar/Main.java 2017-03-14 15:10:08.000000000 +0000 @@ -26,19 +26,12 @@ package sun.tools.jar; import java.io.*; -import java.lang.module.Configuration; -import java.lang.module.InvalidModuleDescriptorException; -import java.lang.module.ModuleDescriptor; +import java.lang.module.*; import java.lang.module.ModuleDescriptor.Exports; import java.lang.module.ModuleDescriptor.Provides; import java.lang.module.ModuleDescriptor.Opens; import java.lang.module.ModuleDescriptor.Requires; import java.lang.module.ModuleDescriptor.Version; -import java.lang.module.ModuleFinder; -import java.lang.module.ModuleReader; -import java.lang.module.ModuleReference; -import java.lang.module.ResolutionException; -import java.lang.module.ResolvedModule; import java.net.URI; import java.nio.ByteBuffer; import java.nio.file.Path; @@ -408,7 +401,7 @@ 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)) { @@ -604,7 +597,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; } @@ -1729,18 +1722,34 @@ .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.size() != 1) + fatalError(formatMsg("error.expected.find.module", fn)); + String nv = mref.iterator().next().descriptor().toNameAndVersion(); + output(formatMsg("out.automodule.name", nv)); + } 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)) { + printModuleDescriptor(is, ze.getName()); + } } } return true; --- old/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties 2017-03-14 15:10:13.000000000 +0000 +++ new/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties 2017-03-14 15:10:12.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=\ @@ -58,10 +58,14 @@ incorrect length while processing: {0} error.create.tempfile=\ Could not create a temporary file +error.expected.find.module=\ + Expected to find automatic module at {0} error.hash.dep=\ 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 +133,8 @@ added manifest out.added.module-info=\ added module-info: {0} +out.automodule.name=\ + No module descriptor found. Derived automatic module name: {0} out.update.manifest=\ updated manifest out.update.module-info=\ @@ -224,8 +230,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-14 15:10:17.000000000 +0000 +++ new/test/tools/jar/modularJar/Basic.java 2017-03-14 15:10:17.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; @@ -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,49 @@ } } + + @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 name: " + mid), + "Expected to find ", mid, " in [", r.output, "]"); + } + ); + } + } + // -- Infrastructure static Result jarWithStdin(File stdinSource, String... args) {