diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java index 466c5d0a14c..9e05fe31aa9 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java @@ -32,6 +32,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.io.UncheckedIOException; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -56,7 +57,6 @@ import jdk.tools.jlink.internal.runtimelink.JimageDiffGenerator; import jdk.tools.jlink.internal.runtimelink.JimageDiffGenerator.ImageResource; import jdk.tools.jlink.internal.runtimelink.ResourceDiff; import jdk.tools.jlink.internal.runtimelink.ResourcePoolReader; -import jdk.tools.jlink.internal.runtimelink.RuntimeImageLinkException; import jdk.tools.jlink.plugin.PluginException; import jdk.tools.jlink.plugin.ResourcePool; import jdk.tools.jlink.plugin.ResourcePoolBuilder; @@ -91,14 +91,11 @@ public final class ImageFileCreator { private final Map> entriesForModule = new HashMap<>(); private final ImagePluginStack plugins; private final boolean generateRuntimeImage; - private final TaskHelper helper; private ImageFileCreator(ImagePluginStack plugins, - boolean generateRuntimeImage, - TaskHelper taskHelper) { + boolean generateRuntimeImage) { this.plugins = Objects.requireNonNull(plugins); this.generateRuntimeImage = generateRuntimeImage; - this.helper = taskHelper; } /** @@ -118,24 +115,20 @@ public final class ImageFileCreator { public static ExecutableImage create(Set archives, ByteOrder byteOrder, ImagePluginStack plugins, - boolean generateRuntimeImage, - TaskHelper taskHelper) + boolean generateRuntimeImage) throws IOException { ImageFileCreator image = new ImageFileCreator(plugins, - generateRuntimeImage, - taskHelper); + generateRuntimeImage); try { image.readAllEntries(archives); // write to modular image image.writeImage(archives, byteOrder); - } catch (RuntimeImageLinkException e) { - // readAllEntries() might throw this exception. - // Propagate as IOException with appropriate message for - // jlink runs from the run-time image. This handles better - // error messages for the case of modified files in the run-time - // image. - throw image.newIOException(e); + } catch (UncheckedIOException e) { + // When linking from the run-time image, readAllEntries() might + // throw this exception for a modified runtime. Unpack and + // re-throw as IOException. + throw e.getCause(); } finally { // Close all archives for (Archive a : archives) { @@ -200,11 +193,6 @@ public final class ImageFileCreator { ResourcePool result = null; try (DataOutputStream out = plugins.getJImageFileOutputStream()) { result = generateJImage(allContent, writer, plugins, out, generateRuntimeImage); - } catch (RuntimeImageLinkException e) { - // Propagate as IOException with appropriate message for - // jlink runs from the run-time image. This handles better - // error messages for the case of --patch-module. - throw newIOException(e); } //Handle files. @@ -218,18 +206,6 @@ public final class ImageFileCreator { } } - private IOException newIOException(RuntimeImageLinkException e) throws IOException { - if (JlinkTask.DEBUG) { - e.printStackTrace(); - } - String message = switch (e.getReason()) { - case PATCH_MODULE -> helper.getMessage("err.runtime.link.patched.module", e.getFile()); - case MODIFIED_FILE -> helper.getMessage("err.runtime.link.modified.file", e.getFile()); - default -> throw new AssertionError("Unexpected value: " + e.getReason()); - }; - throw new IOException(message); - } - /** * Create a jimage based on content of the given ResourcePoolManager, * optionally creating a runtime that can be used for linking from the diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java index 755afea8c60..df7d35ac777 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JRTArchive.java @@ -26,8 +26,6 @@ package jdk.tools.jlink.internal; import static jdk.tools.jlink.internal.LinkableRuntimeImage.RESPATH_PATTERN; -import static jdk.tools.jlink.internal.runtimelink.RuntimeImageLinkException.Reason.MODIFIED_FILE; -import static jdk.tools.jlink.internal.runtimelink.RuntimeImageLinkException.Reason.PATCH_MODULE; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -37,7 +35,6 @@ import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.security.MessageDigest; @@ -56,7 +53,6 @@ import java.util.stream.Stream; import jdk.internal.util.OperatingSystem; import jdk.tools.jlink.internal.Archive.Entry.EntryType; import jdk.tools.jlink.internal.runtimelink.ResourceDiff; -import jdk.tools.jlink.internal.runtimelink.RuntimeImageLinkException; import jdk.tools.jlink.plugin.ResourcePoolEntry; import jdk.tools.jlink.plugin.ResourcePoolEntry.Type; @@ -223,7 +219,9 @@ public class JRTArchive implements Archive { Path path = BASE.resolve(m.resPath); if (shaSumMismatch(path, m.hashOrTarget, m.symlink)) { if (errorOnModifiedFile) { - throw new RuntimeImageLinkException(path.toString(), MODIFIED_FILE); + String msg = taskHelper.getMessage("err.runtime.link.modified.file", path.toString()); + IOException cause = new IOException(msg); + throw new UncheckedIOException(cause); } else { taskHelper.warning("err.runtime.link.modified.file", path.toString()); } @@ -460,16 +458,7 @@ public class JRTArchive implements Archive { // the underlying base path is a JrtPath with the // JrtFileSystem underneath which is able to handle // this size query. - try { - return Files.size(archive.getPath().resolve(resPath)); - } catch (NoSuchFileException file) { - // This indicates that we don't find the class in the - // modules image using the JRT FS provider. Yet, we find - // the class using the system module finder. Therefore, - // we have a patched module. Mention that module patching - // is not supported. - throw new RuntimeImageLinkException(file.getFile(), PATCH_MODULE); - } + return Files.size(archive.getPath().resolve(resPath)); } } catch (IOException e) { throw new UncheckedIOException(e); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java index 15998d6b929..0eda0b5d455 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java @@ -63,6 +63,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.internal.module.ModuleBootstrap; import jdk.internal.module.ModulePath; import jdk.internal.module.ModuleReferenceImpl; import jdk.internal.module.ModuleResolution; @@ -73,7 +74,6 @@ import jdk.tools.jlink.internal.Jlink.PluginsConfiguration; import jdk.tools.jlink.internal.TaskHelper.BadArgs; import jdk.tools.jlink.internal.TaskHelper.Option; import jdk.tools.jlink.internal.TaskHelper.OptionsHelper; -import jdk.tools.jlink.internal.runtimelink.RuntimeImageLinkException; import jdk.tools.jlink.plugin.PluginException; /** @@ -309,7 +309,7 @@ public class JlinkTask { } cleanupOutput(outputPath); return EXIT_ERROR; - } catch (IllegalArgumentException | ResolutionException | RuntimeImageLinkException e) { + } catch (IllegalArgumentException | ResolutionException e) { log.println(taskHelper.getMessage("error.prefix") + " " + e.getMessage()); if (DEBUG) { e.printStackTrace(log); @@ -620,6 +620,12 @@ public class JlinkTask { String msg = taskHelper.getMessage("err.runtime.link.jdk.jlink.prohibited"); throw new IllegalArgumentException(msg); } + // Do not permit linking from run-time image when the current image + // is being patched. + if (ModuleBootstrap.patcher().hasPatches()) { + String msg = taskHelper.getMessage("err.runtime.link.patched.module"); + throw new IllegalArgumentException(msg); + } // Print info message indicating linking from the run-time image if (verbose && log != null) { @@ -1039,7 +1045,7 @@ public class JlinkTask { @Override public ExecutableImage retrieve(ImagePluginStack stack) throws IOException { ExecutableImage image = ImageFileCreator.create(archives, - targetPlatform.arch().byteOrder(), stack, generateRuntimeImage, taskHelper); + targetPlatform.arch().byteOrder(), stack, generateRuntimeImage); if (packagedModulesPath != null) { // copy the packaged modules to the given path Files.createDirectories(packagedModulesPath); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/runtimelink/RuntimeImageLinkException.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/runtimelink/RuntimeImageLinkException.java deleted file mode 100644 index 9f54fd63476..00000000000 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/runtimelink/RuntimeImageLinkException.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2024, Red Hat, Inc. - * 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 jdk.tools.jlink.internal.runtimelink; - -import java.util.Objects; - -/** - * Exception thrown when linking from the run-time image - */ -public class RuntimeImageLinkException extends RuntimeException { - - private static final long serialVersionUID = -1848914673073119403L; - - public static enum Reason { - PATCH_MODULE, /* link exception due to patched module */ - MODIFIED_FILE, /* link exception due to modified file */ - } - - private final String file; - private final Reason reason; - - public RuntimeImageLinkException(String file, Reason reason) { - this.file = Objects.requireNonNull(file); - this.reason = Objects.requireNonNull(reason); - } - - public String getFile() { - return file; - } - - public Reason getReason() { - return reason; - } - - @Override - public String getMessage() { - return reason + ", file: " + file; - } -} diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties index 9e18177d9c8..b5880a35561 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties @@ -125,8 +125,8 @@ err.runtime.link.jdk.jlink.prohibited=This JDK does not contain packaged modules err.runtime.link.packaged.mods=This JDK has no packaged modules.\ \ --keep-packaged-modules is not supported err.runtime.link.modified.file={0} has been modified -err.runtime.link.patched.module=File {0} not found in the modules image.\ -\ --patch-module is not supported when linking from the run-time image +err.runtime.link.patched.module=jlink does not support linking from the run-time image\ +\ when running on a patched runtime with --patch-module err.empty.module.path=empty module path err.jlink.version.mismatch=jlink version {0}.{1} does not match target java.base version {2}.{3} err.automatic.module:automatic module cannot be used with jlink: {0} from {1} diff --git a/test/jdk/tools/jlink/ImageFileCreatorTest.java b/test/jdk/tools/jlink/ImageFileCreatorTest.java index b6466c6a4d9..52a878e566a 100644 --- a/test/jdk/tools/jlink/ImageFileCreatorTest.java +++ b/test/jdk/tools/jlink/ImageFileCreatorTest.java @@ -224,6 +224,6 @@ public class ImageFileCreatorTest { ImagePluginStack stack = new ImagePluginStack(noopBuilder, Collections.emptyList(), null, false); - ImageFileCreator.create(archives, ByteOrder.nativeOrder(), stack, false, null); + ImageFileCreator.create(archives, ByteOrder.nativeOrder(), stack, false); } } diff --git a/test/jdk/tools/jlink/runtimeImage/ModifiedFilesExitTest.java b/test/jdk/tools/jlink/runtimeImage/ModifiedFilesExitTest.java index 90abe14c214..777ce302ce7 100644 --- a/test/jdk/tools/jlink/runtimeImage/ModifiedFilesExitTest.java +++ b/test/jdk/tools/jlink/runtimeImage/ModifiedFilesExitTest.java @@ -78,7 +78,7 @@ public class ModifiedFilesExitTest extends ModifiedFilesTest { } analyzer.stdoutShouldContain(modifiedFile.toString() + " has been modified"); // Verify the error message is reasonable - analyzer.stdoutShouldNotContain("jdk.tools.jlink.internal.RunImageLinkException"); + analyzer.stdoutShouldNotContain("IOException"); analyzer.stdoutShouldNotContain("java.lang.IllegalArgumentException"); } diff --git a/test/jdk/tools/jlink/runtimeImage/ModifiedFilesWarningTest.java b/test/jdk/tools/jlink/runtimeImage/ModifiedFilesWarningTest.java index 935d80dee4f..c871024f37c 100644 --- a/test/jdk/tools/jlink/runtimeImage/ModifiedFilesWarningTest.java +++ b/test/jdk/tools/jlink/runtimeImage/ModifiedFilesWarningTest.java @@ -70,6 +70,6 @@ public class ModifiedFilesWarningTest extends ModifiedFilesTest { // verify we get the warning message out.stdoutShouldMatch("Warning: .* has been modified"); out.stdoutShouldNotContain("java.lang.IllegalArgumentException"); - out.stdoutShouldNotContain("jdk.tools.jlink.internal.RunImageLinkException"); + out.stdoutShouldNotContain("IOException"); } } diff --git a/test/jdk/tools/jlink/runtimeImage/PatchedJDKModuleJlinkTest.java b/test/jdk/tools/jlink/runtimeImage/PatchedJDKModuleJlinkTest.java index f83c4c698f1..d4654ec98bd 100644 --- a/test/jdk/tools/jlink/runtimeImage/PatchedJDKModuleJlinkTest.java +++ b/test/jdk/tools/jlink/runtimeImage/PatchedJDKModuleJlinkTest.java @@ -97,10 +97,10 @@ public class PatchedJDKModuleJlinkTest extends AbstractLinkableRuntimeTest { if (analyzer.getExitValue() == 0) { throw new AssertionError("Expected jlink to fail due to patched module!"); } - analyzer.stdoutShouldContain("MyJlinkPatchInteger.class not found in the modules image."); - analyzer.stdoutShouldContain("--patch-module is not supported"); + analyzer.stdoutShouldContain("jlink does not support linking from the run-time image"); + analyzer.stdoutShouldContain(" when running on a patched runtime with --patch-module"); // Verify the error message is reasonable - analyzer.stdoutShouldNotContain("jdk.tools.jlink.internal.RunImageLinkException"); + analyzer.stdoutShouldNotContain("IOException"); analyzer.stdoutShouldNotContain("java.lang.IllegalArgumentException"); }