8192986: Inconsistent handling of exploded modules in jlink
Reviewed-by: redestad, jlaskey
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java Fri Dec 08 14:28:51 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java Fri Dec 08 20:46:40 2017 +0530
@@ -267,15 +267,17 @@
assert !mainClassName.isEmpty();
}
- String path = "/" + module + "/module-info.class";
- Optional<ResourcePoolEntry> res = imageContent.findEntry(path);
- if (!res.isPresent()) {
- throw new IOException("module-info.class not found for " + module + " module");
- }
- ByteArrayInputStream stream = new ByteArrayInputStream(res.get().contentBytes());
- Optional<String> mainClass = ModuleDescriptor.read(stream).mainClass();
- if (mainClassName == null && mainClass.isPresent()) {
- mainClassName = mainClass.get();
+ if (mainClassName == null) {
+ String path = "/" + module + "/module-info.class";
+ Optional<ResourcePoolEntry> res = imageContent.findEntry(path);
+ if (!res.isPresent()) {
+ throw new IOException("module-info.class not found for " + module + " module");
+ }
+ ByteArrayInputStream stream = new ByteArrayInputStream(res.get().contentBytes());
+ Optional<String> mainClass = ModuleDescriptor.read(stream).mainClass();
+ if (mainClass.isPresent()) {
+ mainClassName = mainClass.get();
+ }
}
if (mainClassName != null) {
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/DirArchive.java Fri Dec 08 14:28:51 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/DirArchive.java Fri Dec 08 20:46:40 2017 +0530
@@ -85,17 +85,17 @@
private static final Consumer<String> noopConsumer = (String t) -> {
};
- public DirArchive(Path dirPath) {
- this(dirPath, noopConsumer);
+ public DirArchive(Path dirPath, String moduleName) {
+ this(dirPath, moduleName, noopConsumer);
}
- public DirArchive(Path dirPath, Consumer<String> log) {
+ public DirArchive(Path dirPath, String moduleName, Consumer<String> log) {
Objects.requireNonNull(dirPath);
if (!Files.isDirectory(dirPath)) {
throw new IllegalArgumentException(dirPath + " is not a directory");
}
chop = dirPath.toString().length() + 1;
- this.moduleName = Objects.requireNonNull(dirPath.getFileName()).toString();
+ this.moduleName = Objects.requireNonNull(moduleName);
this.dirPath = dirPath;
this.log = log;
}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Fri Dec 08 14:28:51 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Fri Dec 08 20:46:40 2017 +0530
@@ -24,6 +24,7 @@
*/
package jdk.tools.jlink.internal;
+import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
@@ -824,13 +825,29 @@
return modularJarArchive;
} else if (Files.isDirectory(path)) {
- return new DirArchive(path);
+ Path modInfoPath = path.resolve("module-info.class");
+ if (Files.isRegularFile(modInfoPath)) {
+ return new DirArchive(path, findModuleName(modInfoPath));
+ } else {
+ throw new IllegalArgumentException(
+ taskHelper.getMessage("err.not.a.module.directory", path));
+ }
} else {
throw new IllegalArgumentException(
taskHelper.getMessage("err.not.modular.format", module, path));
}
}
+ private static String findModuleName(Path modInfoPath) {
+ try (BufferedInputStream bis = new BufferedInputStream(
+ Files.newInputStream(modInfoPath))) {
+ return ModuleDescriptor.read(bis).name();
+ } catch (IOException exp) {
+ throw new IllegalArgumentException(taskHelper.getMessage(
+ "err.cannot.read.module.info", modInfoPath), exp);
+ }
+ }
+
@Override
public ExecutableImage retrieve(ImagePluginStack stack) throws IOException {
ExecutableImage image = ImageFileCreator.create(archives, order, stack);
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties Fri Dec 08 14:28:51 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties Fri Dec 08 20:46:40 2017 +0530
@@ -135,6 +135,8 @@
err.config.defaults=property {0} is missing from configuration
err.config.defaults.value=wrong value in defaults property: {0}
err.bom.generation=bom file generation failed: {0}
+err.not.a.module.directory=directory {0} does not contain module-info.class file under it
+err.cannot.read.module.info=cannot read module descriptor from {0}
err.not.modular.format=selected module {0} ({1}) not in jmod or modular JAR format
err.signing=signed modular JAR {0} is currently not supported,\
\ use --ignore-signing-information to suppress error
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/tools/jlink/ExplodedModuleNameTest.java Fri Dec 08 20:46:40 2017 +0530
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.Files;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.util.spi.ToolProvider;
+
+import tests.Helper;
+import tests.JImageGenerator;
+import tests.Result;
+
+/*
+ * @test
+ * @bug 8192986
+ * @summary Inconsistent handling of exploded modules in jlink
+ * @library ../lib
+ * @modules java.base/jdk.internal.jimage
+ * jdk.jdeps/com.sun.tools.classfile
+ * jdk.jlink/jdk.tools.jlink.internal
+ * jdk.jlink/jdk.tools.jmod
+ * jdk.jlink/jdk.tools.jimage
+ * jdk.compiler
+ * @build tests.*
+ * @run main ExplodedModuleNameTest
+ */
+public class ExplodedModuleNameTest {
+ static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink")
+ .orElseThrow(() ->
+ new RuntimeException("jlink tool not found")
+ );
+
+ public static void main(String[] args) throws Exception {
+ Helper helper = Helper.newHelper();
+ if (helper == null) {
+ System.err.println("Test not run");
+ return;
+ }
+
+ // generate a new exploded module
+ String modName = "mod8192986";
+ Path modDir = helper.generateDefaultExplodedModule(modName).getFile();
+ // rename the module containing directory
+ Path renamedModDir = modDir.resolveSibling("modified_mod8192986");
+ // copy the content from original directory to modified name directory
+ copyDir(modDir, renamedModDir);
+
+ Path outputDir = helper.createNewImageDir("image8192986");
+ JImageGenerator.getJLinkTask()
+ .modulePath(renamedModDir.toAbsolutePath().toString())
+ .output(outputDir)
+ .addMods(modName)
+ .launcher(modName + "=" + modName + "/" + modName +".Main")
+ .call().assertSuccess();
+ }
+
+ private static void copyDir(Path srcDir, Path destDir) throws IOException {
+ Files.walkFileTree(srcDir, new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ Path target = destDir.resolve(srcDir.relativize(dir));
+ Files.createDirectory(target);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Files.copy(file, destDir.resolve(srcDir.relativize(file)));
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+}
--- a/test/jdk/tools/lib/tests/Helper.java Fri Dec 08 14:28:51 2017 +0000
+++ b/test/jdk/tools/lib/tests/Helper.java Fri Dec 08 20:46:40 2017 +0530
@@ -219,7 +219,7 @@
generateModuleCompiledClasses(explodedmodssrc, explodedmodsclasses,
moduleName, classNames, dependencies);
- Path dir = explodedmods.resolve(moduleName);
+ Path dir = explodedmods.resolve("classes").resolve(moduleName);
return new Result(0, "", dir);
}
--- a/test/jdk/tools/lib/tests/JImageGenerator.java Fri Dec 08 14:28:51 2017 +0000
+++ b/test/jdk/tools/lib/tests/JImageGenerator.java Fri Dec 08 20:46:40 2017 +0530
@@ -110,6 +110,7 @@
private static final String ADD_MODULES_OPTION = "--add-modules";
private static final String LIMIT_MODULES_OPTION = "--limit-modules";
private static final String PLUGIN_MODULE_PATH = "--plugin-module-path";
+ private static final String LAUNCHER = "--launcher";
private static final String CMDS_OPTION = "--cmds";
private static final String CONFIG_OPTION = "--config";
@@ -579,12 +580,18 @@
private String repeatedLimitMods;
private Path output;
private Path existing;
+ private String launcher; // optional
public JLinkTask modulePath(String modulePath) {
this.modulePath = modulePath;
return this;
}
+ public JLinkTask launcher(String cmd) {
+ launcher = Objects.requireNonNull(cmd);
+ return this;
+ }
+
public JLinkTask repeatedModulePath(String modulePath) {
this.repeatedModulePath = modulePath;
return this;
@@ -682,6 +689,10 @@
options.add(PLUGIN_MODULE_PATH);
options.add(toPath(pluginModulePath));
}
+ if (launcher != null && !launcher.isEmpty()) {
+ options.add(LAUNCHER);
+ options.add(launcher);
+ }
options.addAll(this.options);
return options.toArray(new String[options.size()]);
}