8189777: jlink --module-path default value and automatic addition of $JAVA_HOME/jmods if java.base is missing
Reviewed-by: alanb, mchung
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java Thu Oct 26 18:04:29 2017 -0700
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Jlink.java Fri Oct 27 08:21:53 2017 +0530
@@ -27,7 +27,9 @@
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.nio.ByteOrder;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -146,10 +148,8 @@
*/
public static final class JlinkConfiguration {
- private final List<Path> modulepaths;
private final Path output;
private final Set<String> modules;
- private final Set<String> limitmods;
private final ByteOrder endian;
private final ModuleFinder finder;
@@ -157,33 +157,18 @@
* jlink configuration,
*
* @param output Output directory, must not exist.
- * @param modulepaths Modules paths
* @param modules The possibly-empty set of root modules to resolve
- * @param limitmods Limit the universe of observable modules
* @param endian Jimage byte order. Native order by default
+ * @param finder the ModuleFinder for this configuration
*/
public JlinkConfiguration(Path output,
- List<Path> modulepaths,
Set<String> modules,
- Set<String> limitmods,
- ByteOrder endian) {
- if (Objects.requireNonNull(modulepaths).isEmpty()) {
- throw new IllegalArgumentException("Empty module path");
- }
-
+ ByteOrder endian,
+ ModuleFinder finder) {
this.output = output;
- this.modulepaths = modulepaths;
this.modules = Objects.requireNonNull(modules);
- this.limitmods = Objects.requireNonNull(limitmods);
this.endian = Objects.requireNonNull(endian);
- this.finder = moduleFinder();
- }
-
- /**
- * @return the modulepaths
- */
- public List<Path> getModulepaths() {
- return modulepaths;
+ this.finder = finder;
}
/**
@@ -208,13 +193,6 @@
}
/**
- * @return the limitmods
- */
- public Set<String> getLimitmods() {
- return limitmods;
- }
-
- /**
* Returns {@link ModuleFinder} that finds all observable modules
* for this jlink configuration.
*/
@@ -244,37 +222,16 @@
modules);
}
- private ModuleFinder moduleFinder() {
- Path[] entries = modulepaths.toArray(new Path[0]);
- ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
- if (!limitmods.isEmpty()) {
- finder = JlinkTask.limitFinder(finder, limitmods, modules);
- }
- return finder;
- }
-
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("output=").append(output).append("\n");
- StringBuilder pathsBuilder = new StringBuilder();
- for (Path p : modulepaths) {
- pathsBuilder.append(p).append(",");
- }
- builder.append("modulepaths=").append(pathsBuilder).append("\n");
-
StringBuilder modsBuilder = new StringBuilder();
for (String p : modules) {
modsBuilder.append(p).append(",");
}
builder.append("modules=").append(modsBuilder).append("\n");
-
- StringBuilder limitsBuilder = new StringBuilder();
- for (String p : limitmods) {
- limitsBuilder.append(p).append(",");
- }
- builder.append("limitmodules=").append(limitsBuilder).append("\n");
builder.append("endian=").append(endian).append("\n");
return builder.toString();
}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Thu Oct 26 18:04:29 2017 -0700
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java Fri Oct 27 08:21:53 2017 +0530
@@ -251,9 +251,18 @@
return EXIT_OK;
}
+
if (options.modulePath.isEmpty()) {
- throw taskHelper.newBadArgs("err.modulepath.must.be.specified")
- .showUsage(true);
+ // no --module-path specified - try to set $JAVA_HOME/jmods if that exists
+ Path jmods = getDefaultModulePath();
+ if (jmods != null) {
+ options.modulePath.add(jmods);
+ }
+
+ if (options.modulePath.isEmpty()) {
+ throw taskHelper.newBadArgs("err.modulepath.must.be.specified")
+ .showUsage(true);
+ }
}
JlinkConfiguration config = initJlinkConfig();
@@ -347,14 +356,7 @@
Set<String> roots = new HashSet<>();
for (String mod : options.addMods) {
if (mod.equals(ALL_MODULE_PATH)) {
- Path[] entries = options.modulePath.toArray(new Path[0]);
- ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
- if (!options.limitMods.isEmpty()) {
- // finder for the observable modules specified in
- // the --module-path and --limit-modules options
- finder = limitFinder(finder, options.limitMods, Collections.emptySet());
- }
-
+ ModuleFinder finder = newModuleFinder(options.modulePath, options.limitMods, Set.of());
// all observable modules are roots
finder.findAll()
.stream()
@@ -366,11 +368,19 @@
}
}
+ ModuleFinder finder = newModuleFinder(options.modulePath, options.limitMods, roots);
+ if (!finder.find("java.base").isPresent()) {
+ Path defModPath = getDefaultModulePath();
+ if (defModPath != null) {
+ options.modulePath.add(defModPath);
+ }
+ finder = newModuleFinder(options.modulePath, options.limitMods, roots);
+ }
+
return new JlinkConfiguration(options.output,
- options.modulePath,
roots,
- options.limitMods,
- options.endian);
+ options.endian,
+ finder);
}
private void createImage(JlinkConfiguration config) throws Exception {
@@ -398,6 +408,14 @@
stack.operate(imageProvider);
}
+ /**
+ * @return the system module path or null
+ */
+ public static Path getDefaultModulePath() {
+ Path jmods = Paths.get(System.getProperty("java.home"), "jmods");
+ return Files.isDirectory(jmods)? jmods : null;
+ }
+
/*
* Returns a module finder of the given module path that limits
* the observable modules to those in the transitive closure of
@@ -408,12 +426,15 @@
Set<String> limitMods,
Set<String> roots)
{
+ if (Objects.requireNonNull(paths).isEmpty()) {
+ throw new IllegalArgumentException("Empty module path");
+ }
Path[] entries = paths.toArray(new Path[0]);
ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
// if limitmods is specified then limit the universe
- if (!limitMods.isEmpty()) {
- finder = limitFinder(finder, limitMods, roots);
+ if (limitMods != null && !limitMods.isEmpty()) {
+ finder = limitFinder(finder, limitMods, Objects.requireNonNull(roots));
}
return finder;
}
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java Thu Oct 26 18:04:29 2017 -0700
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java Fri Oct 27 08:21:53 2017 +0530
@@ -96,10 +96,10 @@
// jlink main arguments
Jlink.JlinkConfiguration jlinkConfig =
new Jlink.JlinkConfiguration(new File("").toPath(), // Unused
- modulePath,
addModules,
- limitModules,
- ByteOrder.nativeOrder());
+ ByteOrder.nativeOrder(),
+ moduleFinder(modulePath,
+ limitModules, addModules));
// plugin configuration
List<Plugin> plugins = new ArrayList<Plugin>();
--- a/test/jdk/tools/jlink/IntegrationTest.java Thu Oct 26 18:04:29 2017 -0700
+++ b/test/jdk/tools/jlink/IntegrationTest.java Fri Oct 27 08:21:53 2017 +0530
@@ -39,6 +39,7 @@
import java.util.Set;
import java.util.function.Function;
import jdk.tools.jlink.internal.Jlink;
+import jdk.tools.jlink.internal.JlinkTask;
import jdk.tools.jlink.builder.DefaultImageBuilder;
import jdk.tools.jlink.plugin.ResourcePool;
import jdk.tools.jlink.plugin.ResourcePoolBuilder;
@@ -159,7 +160,8 @@
Set<String> limits = new HashSet<>();
limits.add("java.management");
JlinkConfiguration config = new Jlink.JlinkConfiguration(output,
- modulePaths, mods, limits, ByteOrder.nativeOrder());
+ mods, ByteOrder.nativeOrder(),
+ JlinkTask.newModuleFinder(modulePaths, limits, mods));
List<Plugin> lst = new ArrayList<>();
--- a/test/jdk/tools/jlink/JLinkTest.java Thu Oct 26 18:04:29 2017 -0700
+++ b/test/jdk/tools/jlink/JLinkTest.java Fri Oct 27 08:21:53 2017 +0530
@@ -42,6 +42,7 @@
/*
* @test
* @summary Test image creation
+ * @bug 8189777
* @author Jean-Francois Denise
* @library ../lib
* @modules java.base/jdk.internal.jimage
@@ -106,6 +107,37 @@
}
{
+ // No --module-path specified. $JAVA_HOME/jmods should be assumed.
+ // The following should succeed as it uses only system modules.
+ String imageDir = "bug818977-no-modulepath";
+ JImageGenerator.getJLinkTask()
+ .output(helper.createNewImageDir(imageDir))
+ .addMods("jdk.scripting.nashorn")
+ .call().assertSuccess();
+ }
+
+ {
+ // invalid --module-path specified. java.base not found it it.
+ // $JAVA_HOME/jmods should be added automatically.
+ // The following should succeed as it uses only system modules.
+ String imageDir = "bug8189777-invalid-modulepath";
+ JImageGenerator.getJLinkTask()
+ .modulePath("does_not_exist_path")
+ .output(helper.createNewImageDir(imageDir))
+ .addMods("jdk.scripting.nashorn")
+ .call().assertSuccess();
+ }
+
+ {
+ // No --module-path specified. --add-modules ALL-MODULE-PATH specified.
+ String imageDir = "bug8189777-all-module-path";
+ JImageGenerator.getJLinkTask()
+ .output(helper.createNewImageDir(imageDir))
+ .addMods("ALL-MODULE-PATH")
+ .call().assertSuccess();
+ }
+
+ {
String moduleName = "bug8134651";
JImageGenerator.getJLinkTask()
.modulePath(helper.defaultModulePath())
@@ -122,6 +154,17 @@
.output(helper.createNewImageDir(moduleName))
.addMods("leaf1")
.call().assertFailure("Error: no value given for --module-path");
+ // do not include standard module path - should be added automatically
+ JImageGenerator.getJLinkTask()
+ .modulePath(helper.defaultModulePath(false))
+ .output(helper.createNewImageDir(moduleName))
+ .addMods("leaf1")
+ .call().assertSuccess();
+ // no --module-path. default sys mod path is assumed - but that won't contain 'leaf1' module
+ JImageGenerator.getJLinkTask()
+ .output(helper.createNewImageDir(moduleName))
+ .addMods("leaf1")
+ .call().assertFailure("Error: Module leaf1 not found");
}
{
--- a/test/jdk/tools/lib/tests/Helper.java Thu Oct 26 18:04:29 2017 -0700
+++ b/test/jdk/tools/lib/tests/Helper.java Fri Oct 27 08:21:53 2017 +0530
@@ -136,7 +136,11 @@
}
public String defaultModulePath() {
- return stdjmods.toAbsolutePath().toString() + File.pathSeparator
+ return defaultModulePath(true);
+ }
+
+ public String defaultModulePath(boolean includeStdMods) {
+ return (includeStdMods? stdjmods.toAbsolutePath().toString() : "") + File.pathSeparator
+ jmods.toAbsolutePath().toString() + File.pathSeparator
+ jars.toAbsolutePath().toString() + File.pathSeparator
+ explodedmodsclasses.toAbsolutePath().toString();