From b35be1bd9474b55866d602433c6a2f2d228ba8c6 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Thu, 14 May 2026 20:02:08 -0700 Subject: [PATCH] 8384608: [lworld] Sync preview jimage overlay implementation with mainline 8377070 --- .../jdk/internal/jimage/ImageLocation.java | 19 +- .../jdk/internal/jimage/ImageReader.java | 6 +- .../{ModuleReference.java => ModuleLink.java} | 128 +++++++----- .../jlink/internal/ImageFileCreator.java | 2 +- .../jlink/internal/ImageResourcesTree.java | 62 +++--- .../internal/jimage/ImageLocationTest.java | 52 ++--- ...ReferenceTest.java => ModuleLinkTest.java} | 98 ++++----- test/jdk/tools/jlink/JLinkPreviewTest.java | 193 ++++++++++++++++++ .../internal/ImageResourcesTreeTest.java | 74 +++---- 9 files changed, 430 insertions(+), 204 deletions(-) rename src/java.base/share/classes/jdk/internal/jimage/{ModuleReference.java => ModuleLink.java} (61%) rename test/jdk/jdk/internal/jimage/{ModuleReferenceTest.java => ModuleLinkTest.java} (69%) create mode 100644 test/jdk/tools/jlink/JLinkPreviewTest.java diff --git a/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java b/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java index 26167241835..349ec6db244 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java +++ b/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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 @@ -118,7 +118,8 @@ public class ImageLocation { *
  • {@code "[/modules]//META-INF/preview/"} preview * resource or directory:
    * {@code FLAGS_IS_PREVIEW_VERSION}, and additionally {@code - * FLAGS_IS_PREVIEW_ONLY} if no normal version of the resource exists. + * FLAGS_IS_PREVIEW_ONLY} if no normal version of the resource or + * directory exists. *
  • In all other cases, returned flags are zero (note that {@code * "/packages/xxx"} entries may have flags, but these are calculated * elsewhere). @@ -129,7 +130,7 @@ public class ImageLocation { * is present. * @return flags for the ATTRIBUTE_PREVIEW_FLAGS attribute. */ - public static int getFlags(String name, Predicate hasEntry) { + public static int getPreviewFlags(String name, Predicate hasEntry) { if (name.startsWith(PACKAGES_PREFIX + "/")) { throw new IllegalArgumentException( "Package sub-directory flags handled separately: " + name); @@ -164,21 +165,21 @@ public static int getFlags(String name, Predicate hasEntry) { * Helper function to calculate package flags for {@code "/packages/xxx"} * directory entries. * - *

    Based on the module references, the flags are: + *

    Based on the module links, the flags are: *

      - *
    • {@code FLAGS_HAS_PREVIEW_VERSION} if any referenced + *
    • {@code FLAGS_HAS_PREVIEW_VERSION} if any linked * package has a preview version. - *
    • {@code FLAGS_IS_PREVIEW_ONLY} if all referenced packages + *
    • {@code FLAGS_IS_PREVIEW_ONLY} if all linked packages * are preview only. *
    * * @return package flags for {@code "/packages/xxx"} directory entries. */ - public static int getPackageFlags(List moduleReferences) { + public static int getPackageFlags(List moduleLinks) { boolean hasPreviewVersion = - moduleReferences.stream().anyMatch(ModuleReference::hasPreviewVersion); + moduleLinks.stream().anyMatch(ModuleLink::hasPreviewVersion); boolean isPreviewOnly = - moduleReferences.stream().allMatch(ModuleReference::isPreviewOnly); + moduleLinks.stream().allMatch(ModuleLink::isPreviewOnly); return (hasPreviewVersion ? ImageLocation.FLAGS_HAS_PREVIEW_VERSION : 0) | (isPreviewOnly ? ImageLocation.FLAGS_IS_PREVIEW_ONLY : 0); } diff --git a/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java b/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java index b7fd80a6639..761b4282ca1 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java +++ b/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java @@ -323,7 +323,7 @@ private ArrayList processPackagesDirectory(boolean previewMode) { ImageLocation pkgDir = getLocation(offsets.get(i)); int flags = pkgDir.getFlags(); // A package subdirectory is "preview only" if all the modules - // it references have that package marked as preview only. + // it links have that package marked as preview only. // Skipping these entries avoids empty package subdirectories. if (previewMode || !ImageLocation.isPreviewOnly(flags)) { pkgDirs.add(ensureCached(newDirectory(pkgDir.getFullName()))); @@ -332,7 +332,7 @@ private ArrayList processPackagesDirectory(boolean previewMode) { // Only do this in preview mode for the small set of packages with // preview versions (the number of preview entries should be small). List moduleNames = new ArrayList<>(); - ModuleReference.readNameOffsets(getOffsetBuffer(pkgDir), /*normal*/ false, /*preview*/ true) + ModuleLink.readNameOffsets(getOffsetBuffer(pkgDir), /*normal*/ false, /*preview*/ true) .forEachRemaining(n -> moduleNames.add(getString(n))); previewPackagesToModules.put(pkgDir.getBase().replace('.', '/'), moduleNames); } @@ -680,7 +680,7 @@ private void completePackageSubdirectory(Directory dir, ImageLocation loc) { // entries, but it's not worth "right-sizing" the array for that. IntBuffer offsets = getOffsetBuffer(loc); List children = new ArrayList<>(offsets.capacity() / 2); - ModuleReference.readNameOffsets(offsets, /*normal*/ true, previewMode) + ModuleLink.readNameOffsets(offsets, /*normal*/ true, previewMode) .forEachRemaining(n -> { String modName = getString(n); Node link = newLinkNode(dir.getName() + "/" + modName, MODULES_PREFIX + "/" + modName); diff --git a/src/java.base/share/classes/jdk/internal/jimage/ModuleReference.java b/src/java.base/share/classes/jdk/internal/jimage/ModuleLink.java similarity index 61% rename from src/java.base/share/classes/jdk/internal/jimage/ModuleReference.java rename to src/java.base/share/classes/jdk/internal/jimage/ModuleLink.java index da97170d2d5..2af6167192d 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/ModuleReference.java +++ b/src/java.base/share/classes/jdk/internal/jimage/ModuleLink.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -34,10 +34,16 @@ import java.util.function.Function; /** - * Represents the module entries stored in the buffer of {@code "/packages/xxx"} - * image locations (package subdirectories). These entries use flags which are - * similar to, but distinct from, the {@link ImageLocation} flags, so - * encapsulating them here helps avoid confusion. + * Represents links to modules stored in the buffer of {@code "/packages/xxx"} + * image locations (package subdirectories). + * + *

    Package subdirectories store their data differently to all other jimage + * entries. Instead of storing a sequence of offsets to their child entries, + * they store a flattened representation of the child's data in an interleaved + * buffer. These entries also use flags which are similar to, but distinct from, + * the {@link ImageLocation} flags. + * + *

    This class encapsulates that complexity to help avoid confusion. * * @implNote This class needs to maintain JDK 8 source compatibility. * @@ -45,7 +51,7 @@ * but also compiled and delivered as part of the jrtfs.jar to support access * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ -public final class ModuleReference implements Comparable { +public final class ModuleLink implements Comparable { // These flags are additive (hence "has-content" rather than "is-empty"). /** If set, this package exists in preview mode. */ @@ -56,62 +62,74 @@ public final class ModuleReference implements Comparable { private static final int FLAGS_PKG_HAS_RESOURCES = 0x4; /** - * References are ordered with preview versions first which permits early + * Links are ordered with preview versions first which permits early * exit when processing preview entries (it's reversed because the default * order for a boolean is {@code false < true}). */ - private static final Comparator PREVIEW_FIRST = - Comparator.comparing(ModuleReference::hasPreviewVersion).reversed() - .thenComparing(ModuleReference::name); + private static final Comparator PREVIEW_FIRST = + Comparator.comparing(ModuleLink::hasPreviewVersion).reversed() + .thenComparing(ModuleLink::name); /** - * Returns a reference for non-empty packages (those with resources) in a + * Returns a link for non-empty packages (those with resources) in a * given module. * - *

    The same reference can be used for multiple packages in the same module. + *

    The same link can be used for multiple packages in the same module. + * + * @param moduleName the name of the module in which this package exits. + * @param isPreview whether the associated package is defined for preview mode. */ - public static ModuleReference forPackage(String moduleName, boolean isPreview) { - return new ModuleReference(moduleName, FLAGS_PKG_HAS_RESOURCES | previewFlag(isPreview)); + public static ModuleLink forPackage(String moduleName, boolean isPreview) { + return new ModuleLink(moduleName, FLAGS_PKG_HAS_RESOURCES | previewFlag(isPreview)); } /** - * Returns a reference for empty packages in a given module. + * Returns a link for empty packages in a given module. * - *

    The same reference can be used for multiple packages in the same module. + *

    The same link can be used for multiple packages in the same module. + * + * @param moduleName the name of the module in which this package exits. + * @param isPreview whether the associated package is defined for preview mode. */ - public static ModuleReference forEmptyPackage(String moduleName, boolean isPreview) { - return new ModuleReference(moduleName, previewFlag(isPreview)); + public static ModuleLink forEmptyPackage(String moduleName, boolean isPreview) { + return new ModuleLink(moduleName, previewFlag(isPreview)); } + /** + * Returns the appropriate FLAGS_PKG_HAS_XXX_VERSION constant according to + * whether the associated package is defined for preview mode. + * + * @param isPreview whether the associated package is defined for preview mode. + */ private static int previewFlag(boolean isPreview) { return isPreview ? FLAGS_PKG_HAS_PREVIEW_VERSION : FLAGS_PKG_HAS_NORMAL_VERSION; } - /** Merges two references for the same module (combining their flags). */ - public ModuleReference merge(ModuleReference other) { + /** Merges two links for the same module (combining their flags). */ + public ModuleLink merge(ModuleLink other) { if (!name.equals(other.name)) { throw new IllegalArgumentException("Cannot merge " + other + " with " + this); } // Because flags are additive, we can just OR them here. - return new ModuleReference(name, flags | other.flags); + return new ModuleLink(name, flags | other.flags); } private final String name; private final int flags; - private ModuleReference(String moduleName, int flags) { + private ModuleLink(String moduleName, int flags) { this.name = Objects.requireNonNull(moduleName); this.flags = flags; } - /** Returns the module name of this reference. */ + /** Returns the module name of this link. */ public String name() { return name; } /** - * Returns whether the package associated with this reference contains - * resources in this reference's module. + * Returns whether the package associated with this link contains resources + * in its module. * *

    An invariant of the module system is that while a package may exist * under many modules, it only has resources in one. @@ -121,34 +139,34 @@ public boolean hasResources() { } /** - * Returns whether the package associated with this reference has a preview - * version (empty or otherwise) in this reference's module. + * Returns whether the package associated with this module link has a + * preview version (empty or otherwise) in this link's module. */ public boolean hasPreviewVersion() { return (flags & FLAGS_PKG_HAS_PREVIEW_VERSION) != 0; } - /** Returns whether this reference exists only in preview mode. */ + /** Returns whether this module link exists only in preview mode. */ public boolean isPreviewOnly() { return (flags & FLAGS_PKG_HAS_NORMAL_VERSION) == 0; } @Override - public int compareTo(ModuleReference rhs) { + public int compareTo(ModuleLink rhs) { return PREVIEW_FIRST.compare(this, rhs); } @Override public String toString() { - return "ModuleReference{ module=" + name + ", flags=" + flags + " }"; + return "ModuleLink{ module=" + name + ", flags=" + flags + " }"; } @Override public boolean equals(Object obj) { - if (!(obj instanceof ModuleReference)) { + if (!(obj instanceof ModuleLink)) { return false; } - ModuleReference other = (ModuleReference) obj; + ModuleLink other = (ModuleLink) obj; return name.equals(other.name) && flags == other.flags; } @@ -161,6 +179,20 @@ public int hashCode() { * Reads the content buffer of a package subdirectory to return a sequence * of module name offsets in the jimage. * + *

    Package subdirectories store their entries using pairs of integers in + * an interleaved buffer: + *

    +     *     ...
    +     *     [ entry-N flags ]
    +     *     [ entry-N name offset ]
    +     *     [ entry-(N+1) flags ]
    +     *     [ entry-(N+1) name offset ]
    +     *     ...
    +     * 
    + * + *

    Entry flags control whether an entry name should be included by the + * returned iterator, depending on the given include-flags. + * * @param buffer the content buffer of an {@link ImageLocation} with type * {@link ImageLocation.LocationType#PACKAGES_DIR PACKAGES_DIR}. * @param includeNormal whether to include name offsets for modules present @@ -217,42 +249,42 @@ public Integer next() { } /** - * Writes a list of module references to a given buffer. The given references - * list is checked carefully to ensure the written buffer will be valid. + * Writes a list of module links to a given buffer. The given entry list is + * checked carefully to ensure the written buffer will be valid. * *

    Entries are written in order, taking two integer slots per entry as * {@code [, ]}. * - * @param refs the references to write, correctly ordered. + * @param links the module links to write, correctly ordered. * @param buffer destination buffer. * @param nameEncoder encoder for module names. - * @throws IllegalArgumentException in the references are invalid in any way. + * @throws IllegalArgumentException in the link entries are invalid in any way. */ public static void write( - List refs, IntBuffer buffer, Function nameEncoder) { - if (refs.isEmpty()) { - throw new IllegalArgumentException("References list must be non-empty"); + List links, IntBuffer buffer, Function nameEncoder) { + if (links.isEmpty()) { + throw new IllegalArgumentException("Links list must be non-empty"); } - int expectedCapacity = 2 * refs.size(); + int expectedCapacity = 2 * links.size(); if (buffer.capacity() != expectedCapacity) { throw new IllegalArgumentException( "Invalid buffer capacity: expected " + expectedCapacity + ", got " + buffer.capacity()); } // This catches exact duplicates in the list. - refs.stream().reduce((lhs, rhs) -> { + links.stream().reduce((lhs, rhs) -> { if (lhs.compareTo(rhs) >= 0) { - throw new IllegalArgumentException("References must be strictly ordered: " + refs); + throw new IllegalArgumentException("Links must be strictly ordered: " + links); } return rhs; }); - // Distinct references can have the same name (but we don't allow this). - if (refs.stream().map(ModuleReference::name).distinct().count() != refs.size()) { - throw new IllegalArgumentException("Reference names must be unique: " + refs); + // Distinct links can have the same name (but we don't allow this). + if (links.stream().map(ModuleLink::name).distinct().count() != links.size()) { + throw new IllegalArgumentException("Module link names must be unique: " + links); } - if (refs.stream().filter(ModuleReference::hasResources).count() > 1) { - throw new IllegalArgumentException("At most one reference can have resources: " + refs); + if (links.stream().filter(ModuleLink::hasResources).count() > 1) { + throw new IllegalArgumentException("At most one module link can have resources: " + links); } - for (ModuleReference modRef : refs) { + for (ModuleLink modRef : links) { buffer.put(modRef.flags); buffer.put(nameEncoder.apply(modRef.name)); } 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 51bd19347be..98dacb7e184 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 @@ -260,7 +260,7 @@ private static ResourcePool generateJImage(ResourcePoolManager allContent, offset[0] += onFileSize; return; } - int locFlags = ImageLocation.getFlags( + int locFlags = ImageLocation.getPreviewFlags( res.path(), p -> resultResources.findEntry(p).isPresent()); duplicates.add(path); writer.addLocation(path, offset[0], compressedSize, uncompressedSize, locFlags); diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java index 5f10950fc41..044c344c7ae 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageResourcesTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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 @@ -25,7 +25,7 @@ package jdk.tools.jlink.internal; import jdk.internal.jimage.ImageLocation; -import jdk.internal.jimage.ModuleReference; +import jdk.internal.jimage.ModuleLink; import java.io.DataOutputStream; import java.io.IOException; @@ -124,29 +124,29 @@ public ResourceNode(String name, Node parent) { * {@code "/packages/java.util/java.logging"} will exist, but only * {@code "java.base"} entry will be marked as having content. * - *

    When processing module references in non-preview mode, entries marked - * as {@link ModuleReference#isPreviewOnly() preview-only} must be ignored. + *

    When processing module links in non-preview mode, entries marked + * as {@link ModuleLink#isPreviewOnly() preview-only} must be ignored. * - *

    If all references in a package are preview-only, then the entire - * package is marked as preview-only, and must be ignored. + *

    If all links in a package are preview-only, then the entire package is + * marked as preview-only, and must be ignored. */ // Visible for testing only. static final class PackageNode extends Node { - private final List moduleReferences; + private final List moduleLinks; - PackageNode(String name, List moduleReferences, Node parent) { + PackageNode(String name, List moduleLinks, Node parent) { super(name, parent); - if (moduleReferences.isEmpty()) { + if (moduleLinks.isEmpty()) { throw new IllegalStateException("Package must be associated with modules: " + name); } - if (moduleReferences.stream().filter(ModuleReference::hasResources).count() > 1) { + if (moduleLinks.stream().filter(ModuleLink::hasResources).count() > 1) { throw new IllegalStateException("Multiple modules contain non-empty package: " + name); } - this.moduleReferences = Collections.unmodifiableList(moduleReferences); + this.moduleLinks = Collections.unmodifiableList(moduleLinks); } - List getModuleReferences() { - return moduleReferences; + List getModuleLinks() { + return moduleLinks; } } @@ -187,12 +187,12 @@ private void buildTree() { packagesRoot = new Node("packages", root); directAccess.put(packagesRoot.getPath(), packagesRoot); - // Map of dot-separated package names to module references (those - // in which the package appear). References are merged after to - // ensure each module name appears only once, but temporarily a - // module may have several entries per package (e.g. with-content, + // Map of dot-separated package names to module links (those in + // which the package appear). Links are merged after to ensure each + // module name appears only once, but temporarily a module may have + // several link entries per package (e.g. with-content, // without-content, normal, preview-only etc..). - Map> packageToModules = new TreeMap<>(); + Map> packageToModules = new TreeMap<>(); for (String fullPath : paths) { try { processPath(fullPath, modulesRoot, packageToModules); @@ -207,12 +207,12 @@ private void buildTree() { // (empty) package and anything under "META-INF". However, these should // not have entries in the "/packages" directory. packageToModules.keySet().removeIf(p -> p.isEmpty() || p.equals("META-INF") || p.startsWith("META-INF.")); - packageToModules.forEach((pkgName, modRefs) -> { - // Merge multiple refs for the same module. - List pkgModules = modRefs.stream() - .collect(Collectors.groupingBy(ModuleReference::name)) + packageToModules.forEach((pkgName, modLinks) -> { + // Merge multiple links for the same module. + List pkgModules = modLinks.stream() + .collect(Collectors.groupingBy(ModuleLink::name)) .values().stream() - .map(refs -> refs.stream().reduce(ModuleReference::merge).orElseThrow()) + .map(refs -> refs.stream().reduce(ModuleLink::merge).orElseThrow()) .sorted() .toList(); PackageNode pkgNode = new PackageNode(pkgName, pkgModules, packagesRoot); @@ -223,7 +223,7 @@ private void buildTree() { private void processPath( String fullPath, Node modulesRoot, - Map> packageToModules) + Map> packageToModules) throws InvalidTreeException { // Paths are untrusted, so be careful about checking expected format. if (!fullPath.startsWith("/") || fullPath.endsWith("/") || fullPath.contains("//")) { @@ -252,8 +252,8 @@ private void processPath( String fullPkgName = (pathEnd == -1) ? "" : pkgPath.substring(0, pathEnd).replace('/', '.'); String resourceName = pkgPath.substring(pathEnd + 1); // Intermediate packages are marked "empty" (no resources). This might - // later be merged with a non-empty reference for the same package. - ModuleReference emptyRef = ModuleReference.forEmptyPackage(modName, isPreviewPath); + // later be merged with a non-empty link for the same package. + ModuleLink emptyRef = ModuleLink.forEmptyPackage(modName, isPreviewPath); // Work down through empty packages to final resource. for (int i = pkgEndIndex(fullPkgName, 0); i != -1; i = pkgEndIndex(fullPkgName, i)) { @@ -266,7 +266,7 @@ private void processPath( // Reached non-empty (leaf) package (could still be a duplicate). Node resourceNode = parentNode.getChildren(resourceName); if (resourceNode == null) { - ModuleReference resourceRef = ModuleReference.forPackage(modName, isPreviewPath); + ModuleLink resourceRef = ModuleLink.forPackage(modName, isPreviewPath); packageToModules.computeIfAbsent(fullPkgName, p -> new HashSet<>()).add(resourceRef); // Init adds new node to parent (don't add resources to directAccess). new ResourceNode(resourceName, parentNode); @@ -339,7 +339,7 @@ private static final class LocationsAdder { private int addLocations(Node current) { if (current instanceof PackageNode) { - List refs = ((PackageNode) current).getModuleReferences(); + List refs = ((PackageNode) current).getModuleLinks(); // "/packages/" entries have 8-byte entries (flags+offset). int size = refs.size() * 8; writer.addLocation(current.getPath(), offset, 0, size, ImageLocation.getPackageFlags(refs)); @@ -352,7 +352,7 @@ private int addLocations(Node current) { i += 1; } if (current != tree.getRoot() && !(current instanceof ResourceNode)) { - int locFlags = ImageLocation.getFlags(current.getPath(), tree.directAccess::containsKey); + int locFlags = ImageLocation.getPreviewFlags(current.getPath(), tree.directAccess::containsKey); // Normal directory entries have 4-byte entries (offset only). int size = ret.length * 4; writer.addLocation(current.getPath(), offset, 0, size, locFlags); @@ -382,10 +382,10 @@ private List computeContent() { private int computeContent(Node current, Map outLocations) { if (current instanceof PackageNode) { // "/packages/" entries have 8-byte entries (flags+offset). - List refs = ((PackageNode) current).getModuleReferences(); + List refs = ((PackageNode) current).getModuleLinks(); ByteBuffer byteBuffer = ByteBuffer.allocate(8 * refs.size()); byteBuffer.order(writer.getByteOrder()); - ModuleReference.write(refs, byteBuffer.asIntBuffer(), writer::addString); + ModuleLink.write(refs, byteBuffer.asIntBuffer(), writer::addString); content.add(byteBuffer.array()); current.setLocation(outLocations.get(current.getPath())); } else { diff --git a/test/jdk/jdk/internal/jimage/ImageLocationTest.java b/test/jdk/jdk/internal/jimage/ImageLocationTest.java index 46baa348a58..b6a6bfdb4d3 100644 --- a/test/jdk/jdk/internal/jimage/ImageLocationTest.java +++ b/test/jdk/jdk/internal/jimage/ImageLocationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -22,7 +22,7 @@ */ import jdk.internal.jimage.ImageLocation; -import jdk.internal.jimage.ModuleReference; +import jdk.internal.jimage.ModuleLink; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -48,21 +48,21 @@ public class ImageLocationTest { @ValueSource(strings = { "/modules/modfoo/com", "/modules/modfoo/com/foo/Foo.class"}) - public void getFlags_resourceNames(String name) { + public void getPreviewFlags_resourceNames(String name) { String previewName = previewName(name); int noPreviewFlags = - ImageLocation.getFlags(name, Set.of(name)::contains); + ImageLocation.getPreviewFlags(name, Set.of(name)::contains); assertEquals(0, noPreviewFlags); assertFalse(ImageLocation.hasPreviewVersion(noPreviewFlags)); assertFalse(ImageLocation.isPreviewOnly(noPreviewFlags)); int withPreviewFlags = - ImageLocation.getFlags(name, Set.of(name, previewName)::contains); + ImageLocation.getPreviewFlags(name, Set.of(name, previewName)::contains); assertTrue(ImageLocation.hasPreviewVersion(withPreviewFlags)); assertFalse(ImageLocation.isPreviewOnly(withPreviewFlags)); - int previewOnlyFlags = ImageLocation.getFlags(previewName, Set.of(previewName)::contains); + int previewOnlyFlags = ImageLocation.getPreviewFlags(previewName, Set.of(previewName)::contains); assertFalse(ImageLocation.hasPreviewVersion(previewOnlyFlags)); assertTrue(ImageLocation.isPreviewOnly(previewOnlyFlags)); } @@ -74,24 +74,24 @@ public void getFlags_resourceNames(String name) { "/modules/modfoo", "/modules/modfoo/META-INF", "/modules/modfoo/META-INF/module-info.class"}) - public void getFlags_zero(String name) { - assertEquals(0, ImageLocation.getFlags(name, Set.of(name)::contains)); + public void getPreviewFlags_zero(String name) { + assertEquals(0, ImageLocation.getPreviewFlags(name, Set.of(name)::contains)); } @Test - public void getFlags_packageFlags() { + public void getPreviewFlags_packageFlags() { assertThrows( IllegalArgumentException.class, - () -> ImageLocation.getFlags("/packages/pkgname", p -> true)); + () -> ImageLocation.getPreviewFlags("/packages/pkgname", p -> true)); } @Test public void getPackageFlags_noPreview() { - List refs = List.of( - ModuleReference.forPackage("modfoo", false), - ModuleReference.forEmptyPackage("modbar", false), - ModuleReference.forEmptyPackage("modbaz", false)); - int noPreviewFlags = ImageLocation.getPackageFlags(refs); + List links = List.of( + ModuleLink.forPackage("modfoo", false), + ModuleLink.forEmptyPackage("modbar", false), + ModuleLink.forEmptyPackage("modbaz", false)); + int noPreviewFlags = ImageLocation.getPackageFlags(links); assertEquals(0, noPreviewFlags); assertFalse(ImageLocation.hasPreviewVersion(noPreviewFlags)); assertFalse(ImageLocation.isPreviewOnly(noPreviewFlags)); @@ -99,23 +99,23 @@ public void getPackageFlags_noPreview() { @Test public void getPackageFlags_withPreview() { - List refs = List.of( - ModuleReference.forPackage("modfoo", true), - ModuleReference.forEmptyPackage("modbar", false), - ModuleReference.forEmptyPackage("modbaz", true)); - int withPreviewFlags = ImageLocation.getPackageFlags(refs); + List links = List.of( + ModuleLink.forPackage("modfoo", true), + ModuleLink.forEmptyPackage("modbar", false), + ModuleLink.forEmptyPackage("modbaz", true)); + int withPreviewFlags = ImageLocation.getPackageFlags(links); assertTrue(ImageLocation.hasPreviewVersion(withPreviewFlags)); assertFalse(ImageLocation.isPreviewOnly(withPreviewFlags)); } @Test public void getPackageFlags_previewOnly() { - List refs = List.of( - ModuleReference.forPackage("modfoo", true), - ModuleReference.forEmptyPackage("modbar", true), - ModuleReference.forEmptyPackage("modbaz", true)); - int previewOnlyFlags = ImageLocation.getPackageFlags(refs); - // Note the asymmetry between this and the getFlags() case. Unlike + List links = List.of( + ModuleLink.forPackage("modfoo", true), + ModuleLink.forEmptyPackage("modbar", true), + ModuleLink.forEmptyPackage("modbaz", true)); + int previewOnlyFlags = ImageLocation.getPackageFlags(links); + // Note the asymmetry between this and the getPreviewFlags() case. Unlike // module resources, there is no concept of a separate package directory // existing in the preview namespace, so a single entry serves both // purposes, and hasPreviewVersion() and isPreviewOnly() can both be set. diff --git a/test/jdk/jdk/internal/jimage/ModuleReferenceTest.java b/test/jdk/jdk/internal/jimage/ModuleLinkTest.java similarity index 69% rename from test/jdk/jdk/internal/jimage/ModuleReferenceTest.java rename to test/jdk/jdk/internal/jimage/ModuleLinkTest.java index 7a36b0d04e1..d8b561e778c 100644 --- a/test/jdk/jdk/internal/jimage/ModuleReferenceTest.java +++ b/test/jdk/jdk/internal/jimage/ModuleLinkTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -21,7 +21,7 @@ * questions. */ -import jdk.internal.jimage.ModuleReference; +import jdk.internal.jimage.ModuleLink; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -34,8 +34,8 @@ import java.util.List; import java.util.function.Function; -import static jdk.internal.jimage.ModuleReference.forEmptyPackage; -import static jdk.internal.jimage.ModuleReference.forPackage; +import static jdk.internal.jimage.ModuleLink.forEmptyPackage; +import static jdk.internal.jimage.ModuleLink.forPackage; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -44,11 +44,11 @@ /* * @test - * @summary Tests for ModuleReference. + * @summary Tests for ModuleLink. * @modules java.base/jdk.internal.jimage - * @run junit/othervm -esa ModuleReferenceTest + * @run junit/othervm -esa ModuleLinkTest */ -public final class ModuleReferenceTest { +public final class ModuleLinkTest { // Copied (not referenced) for testing. private static final int FLAGS_HAS_PREVIEW_VERSION = 0x1; private static final int FLAGS_HAS_NORMAL_VERSION = 0x2; @@ -56,32 +56,32 @@ public final class ModuleReferenceTest { @ParameterizedTest @ValueSource(booleans = {false, true}) - public void emptyRefs(boolean isPreview) { - ModuleReference ref = forEmptyPackage("module", isPreview); + public void emptyLinks(boolean isPreview) { + ModuleLink link = forEmptyPackage("module", isPreview); - assertEquals("module", ref.name()); - assertFalse(ref.hasResources()); - assertEquals(isPreview, ref.hasPreviewVersion()); - assertEquals(isPreview, ref.isPreviewOnly()); + assertEquals("module", link.name()); + assertFalse(link.hasResources()); + assertEquals(isPreview, link.hasPreviewVersion()); + assertEquals(isPreview, link.isPreviewOnly()); } @ParameterizedTest @ValueSource(booleans = {false, true}) - public void resourceRefs(boolean isPreview) { - ModuleReference ref = forPackage("module", isPreview); + public void resourceLinks(boolean isPreview) { + ModuleLink link = forPackage("module", isPreview); - assertEquals("module", ref.name()); - assertTrue(ref.hasResources()); - assertEquals(isPreview, ref.hasPreviewVersion()); - assertEquals(isPreview, ref.isPreviewOnly()); + assertEquals("module", link.name()); + assertTrue(link.hasResources()); + assertEquals(isPreview, link.hasPreviewVersion()); + assertEquals(isPreview, link.isPreviewOnly()); } @ParameterizedTest @ValueSource(booleans = {false, true}) - public void mergedRefs(boolean isPreview) { - ModuleReference emptyRef = forEmptyPackage("module", true); - ModuleReference resourceRef = forPackage("module", isPreview); - ModuleReference merged = emptyRef.merge(resourceRef); + public void mergedLinks(boolean isPreview) { + ModuleLink emptyLink = forEmptyPackage("module", true); + ModuleLink resourceLink = forPackage("module", isPreview); + ModuleLink merged = emptyLink.merge(resourceLink); // Merging preserves whether there's content. assertTrue(merged.hasResources()); @@ -91,13 +91,13 @@ public void mergedRefs(boolean isPreview) { @Test public void writeBuffer() { - List refs = Arrays.asList( + List links = Arrays.asList( forEmptyPackage("alpha", true), forEmptyPackage("beta", false).merge(forEmptyPackage("beta", true)), forPackage("gamma", false), forEmptyPackage("zeta", false)); - IntBuffer buffer = IntBuffer.allocate(2 * refs.size()); - ModuleReference.write(refs, buffer, fakeEncoder()); + IntBuffer buffer = IntBuffer.allocate(2 * links.size()); + ModuleLink.write(links, buffer, fakeEncoder()); assertArrayEquals( new int[]{ FLAGS_HAS_PREVIEW_VERSION, 100, @@ -112,58 +112,58 @@ public void writeBuffer_emptyList() { IntBuffer buffer = IntBuffer.allocate(0); var err = assertThrows( IllegalArgumentException.class, - () -> ModuleReference.write(List.of(), buffer, null)); + () -> ModuleLink.write(List.of(), buffer, null)); assertTrue(err.getMessage().contains("non-empty")); } @Test public void writeBuffer_badCapacity() { - List refs = Arrays.asList( + List links = Arrays.asList( forPackage("first", false), forEmptyPackage("alpha", false)); IntBuffer buffer = IntBuffer.allocate(10); var err = assertThrows( IllegalArgumentException.class, - () -> ModuleReference.write(refs, buffer, null)); + () -> ModuleLink.write(links, buffer, null)); assertTrue(err.getMessage().contains("buffer capacity")); } @Test public void writeBuffer_multiplePackagesWithResources() { - // Only one module reference (at most) can have resources. - List refs = Arrays.asList( + // Only one module link (at most) can have resources. + List links = Arrays.asList( forPackage("alpha", false), forPackage("beta", false)); - IntBuffer buffer = IntBuffer.allocate(2 * refs.size()); + IntBuffer buffer = IntBuffer.allocate(2 * links.size()); var err = assertThrows( IllegalArgumentException.class, - () -> ModuleReference.write(refs, buffer, null)); + () -> ModuleLink.write(links, buffer, null)); assertTrue(err.getMessage().contains("resources")); } @Test public void writeBuffer_badOrdering() { - // Badly ordered because preview references should come first. - List refs = Arrays.asList( + // Badly ordered because preview links should come first. + List links = Arrays.asList( forEmptyPackage("alpha", false), forEmptyPackage("beta", true)); - IntBuffer buffer = IntBuffer.allocate(2 * refs.size()); + IntBuffer buffer = IntBuffer.allocate(2 * links.size()); var err = assertThrows( IllegalArgumentException.class, - () -> ModuleReference.write(refs, buffer, null)); + () -> ModuleLink.write(links, buffer, null)); assertTrue(err.getMessage().contains("strictly ordered")); } @Test - public void writeBuffer_duplicateRef() { + public void writeBuffer_duplicateLink() { // Technically distinct, and correctly sorted, but with duplicate names. - List refs = Arrays.asList( + List links = Arrays.asList( forEmptyPackage("duplicate", true), forEmptyPackage("duplicate", false)); - IntBuffer buffer = IntBuffer.allocate(2 * refs.size()); + IntBuffer buffer = IntBuffer.allocate(2 * links.size()); var err = assertThrows( IllegalArgumentException.class, - () -> ModuleReference.write(refs, buffer, null)); + () -> ModuleLink.write(links, buffer, null)); assertTrue(err.getMessage().contains("unique")); } @@ -176,9 +176,9 @@ public void readNameOffsets() { FLAGS_HAS_NORMAL_VERSION | FLAGS_HAS_CONTENT, 102, FLAGS_HAS_NORMAL_VERSION, 103}); - List normalOffsets = asList(ModuleReference.readNameOffsets(buffer, true, false)); - List previewOffsets = asList(ModuleReference.readNameOffsets(buffer, false, true)); - List allOffsets = asList(ModuleReference.readNameOffsets(buffer, true, true)); + List normalOffsets = asList(ModuleLink.readNameOffsets(buffer, true, false)); + List previewOffsets = asList(ModuleLink.readNameOffsets(buffer, false, true)); + List allOffsets = asList(ModuleLink.readNameOffsets(buffer, true, true)); assertEquals(List.of(100, 102, 103), normalOffsets); assertEquals(List.of(100, 101), previewOffsets); @@ -189,7 +189,7 @@ public void readNameOffsets() { public void readNameOffsets_badBufferSize() { var err = assertThrows( IllegalArgumentException.class, - () -> ModuleReference.readNameOffsets(IntBuffer.allocate(3), true, false)); + () -> ModuleLink.readNameOffsets(IntBuffer.allocate(3), true, false)); assertTrue(err.getMessage().contains("buffer size")); } @@ -198,22 +198,22 @@ public void readNameOffsets_badFlags() { IntBuffer buffer = IntBuffer.wrap(new int[]{FLAGS_HAS_CONTENT, 100}); var err = assertThrows( IllegalArgumentException.class, - () -> ModuleReference.readNameOffsets(buffer, false, false)); + () -> ModuleLink.readNameOffsets(buffer, false, false)); assertTrue(err.getMessage().contains("flags")); } @Test public void sortOrder_previewFirst() { - List refs = Arrays.asList( + List links = Arrays.asList( forEmptyPackage("normal.beta", false), forPackage("preview.beta", true), forEmptyPackage("preview.alpha", true), forEmptyPackage("normal.alpha", false)); - refs.sort(Comparator.naturalOrder()); + links.sort(Comparator.naturalOrder()); // Non-empty first with remaining sorted by name. assertEquals( List.of("preview.alpha", "preview.beta", "normal.alpha", "normal.beta"), - refs.stream().map(ModuleReference::name).toList()); + links.stream().map(ModuleLink::name).toList()); } private static List asList(Iterator src) { diff --git a/test/jdk/tools/jlink/JLinkPreviewTest.java b/test/jdk/tools/jlink/JLinkPreviewTest.java new file mode 100644 index 00000000000..d263c1ad972 --- /dev/null +++ b/test/jdk/tools/jlink/JLinkPreviewTest.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2026, 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 jdk.test.lib.compiler.InMemoryJavaCompiler; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.JarBuilder; +import jdk.tools.jlink.internal.LinkableRuntimeImage; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import tests.Helper; +import tests.JImageGenerator; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.spi.ToolProvider; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* + * @test + * @summary Tests preview mode support in JLink. + * @library /test/jdk/tools/lib + * /test/lib + * @build jdk.test.lib.process.ProcessTools + * tests.* + * @modules jdk.jlink/jdk.tools.jimage + * jdk.jlink/jdk.tools.jlink.internal + * java.base/jdk.internal.jimage + * @run junit/othervm JLinkPreviewTest + */ +public class JLinkPreviewTest { + private static final String TEST_MODULE = "java.test"; + private static final String TEST_PACKAGE = "test"; + private static final String TEST_CLASS = "InjectedTestClass"; + private static final int NORMAL_EXIT_VALUE = 23; + private static final int PREVIEW_EXIT_VALUE = 42; + + private static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") + .orElseThrow(() -> new RuntimeException("jlink tool not found")); + + private static Path customJreRoot; + + @BeforeAll + static void buildCustomBootImage(@TempDir Path tmp) throws Exception { + Path jreRoot = tmp.resolve("testjdk"); + if (JLINK_TOOL.run(System.out, System.err, + "--add-modules", "java.base", + "--add-modules", "jdk.zipfs", + "--output", jreRoot.toString()) != 0) { + throw new RuntimeException("failed to create small boot image"); + } + Path jimage = jreRoot.resolve("lib", "modules"); + + Helper helper = getHelper(); + // Compile into the helper's jar directory so jlink will include it. + compileTestModule(helper.getJarDir()); + Path customJimage = buildJimage(helper); + Files.copy(customJimage, jimage, REPLACE_EXISTING); + customJreRoot = jreRoot; + } + + @Test + public void nonPreviewMode() throws Exception { + runTestClass(false, NORMAL_EXIT_VALUE, TEST_CLASS + ": NORMAL"); + } + + @Test + public void previewMode() throws Exception { + runTestClass(true, PREVIEW_EXIT_VALUE, TEST_CLASS + ": PREVIEW"); + } + + @Test + public void ensureJimageContent() { + Path jimage = customJreRoot.resolve("lib", "modules"); + // The jimage tool isn't present in the custom JRE, but should + // have the same version by virtue of coming from the test JVM. + StringWriter buffer = new StringWriter(); + assertEquals(0, jdk.tools.jimage.Main.run(new String[] { "list", jimage.toString() }, new PrintWriter(buffer))); + List outLines = buffer.toString().lines().map(String::strip).toList(); + + String pkgPath = getPackagePath(TEST_PACKAGE + "." + TEST_CLASS); + assertTrue(outLines.contains("Module: " + TEST_MODULE)); + assertTrue(outLines.contains(pkgPath)); + assertTrue(outLines.contains("META-INF/preview/" + pkgPath)); + } + + /// Returns the helper for building JAR and jimage files. + private static Helper getHelper() { + Helper helper; + try { + boolean isLinkableRuntime = LinkableRuntimeImage.isLinkableRuntime(); + helper = Helper.newHelper(isLinkableRuntime); + } catch (IOException e) { + throw new RuntimeException(e); + } + Assumptions.assumeTrue(helper != null, "Cannot create test helper, skipping test!"); + return helper; + } + + /// Builds a jimage file with the specified class entries. The classes in + /// the built image can be loaded and executed to return their names via + /// `toString()` to confirm the correct bytes were returned. + private static Path buildJimage(Helper helper) { + Path outDir = helper.createNewImageDir("test"); + // The default module path contains the directory we compiled the jars into. + JImageGenerator.JLinkTask jlink = JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .output(outDir); + jlink.addMods(TEST_MODULE); + return jlink.call().assertSuccess().resolve("lib", "modules"); + } + + /// Compiles a test module containing test classes into a single Jar. + /// The test class can be instantiated and have their {@code toString()} + /// method called to return a status string for testing. + private static void compileTestModule(Path jarDir) throws IOException { + JarBuilder jar = new JarBuilder(jarDir.resolve(TEST_MODULE + ".jar").toString()); + String moduleInfo = "open module " + TEST_MODULE + " {}"; + jar.addEntry("module-info.class", InMemoryJavaCompiler.compile("module-info", moduleInfo)); + compileTestClass(jar, false); + compileTestClass(jar, true); + jar.build(); + } + + /// Compiles a test class into a given single Jar. + private static void compileTestClass(JarBuilder jar, boolean isPreview) { + String fqn = TEST_PACKAGE + "." + TEST_CLASS; + String msg = isPreview ? "PREVIEW" : "NORMAL"; + int exit = isPreview ? PREVIEW_EXIT_VALUE : NORMAL_EXIT_VALUE; + String testSrc = String.format( + """ + package %1$s; + public class %2$s { + public static void main(String[] args) { + System.out.println("%2$s: %3$s"); + System.out.flush(); + System.exit(%4$d); + } + } + """, TEST_PACKAGE, TEST_CLASS, msg, exit); + String pkgPath = getPackagePath(fqn); + String path = (isPreview ? "META-INF/preview/" : "") + pkgPath; + jar.addEntry(path, InMemoryJavaCompiler.compile(fqn, testSrc)); + } + + private static void runTestClass(boolean isPreviewMode, int expectedExitValue, String expectedMessage) throws Exception { + List args = new ArrayList<>(); + args.add(customJreRoot.resolve("bin", "java").toString()); + if (isPreviewMode) { + args.add("--enable-preview"); + } + args.add("-m"); + args.add(TEST_MODULE + "/" + TEST_PACKAGE + "." + TEST_CLASS); + ProcessBuilder cmd = new ProcessBuilder(args); + OutputAnalyzer result = ProcessTools.executeCommand(cmd); + assertEquals(expectedExitValue, result.getExitValue()); + assertEquals(expectedMessage + System.lineSeparator(), result.getStdout()); + } + + private static String getPackagePath(String fqn) { + return fqn.replace('.', '/') + ".class"; + } +} diff --git a/test/jdk/tools/jlink/whitebox/jdk.jlink/jdk/tools/jlink/internal/ImageResourcesTreeTest.java b/test/jdk/tools/jlink/whitebox/jdk.jlink/jdk/tools/jlink/internal/ImageResourcesTreeTest.java index b61759b04e5..180cf6480cb 100644 --- a/test/jdk/tools/jlink/whitebox/jdk.jlink/jdk/tools/jlink/internal/ImageResourcesTreeTest.java +++ b/test/jdk/tools/jlink/whitebox/jdk.jlink/jdk/tools/jlink/internal/ImageResourcesTreeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -23,7 +23,7 @@ package jdk.tools.jlink.internal; -import jdk.internal.jimage.ModuleReference; +import jdk.internal.jimage.ModuleLink; import jdk.tools.jlink.internal.ImageResourcesTree.Node; import jdk.tools.jlink.internal.ImageResourcesTree.PackageNode; import jdk.tools.jlink.internal.ImageResourcesTree.ResourceNode; @@ -138,15 +138,15 @@ public void expectedPackageEntries() { Tree tree = new Tree(paths); Map nodes = tree.getMap(); PackageNode pkgUtil = getPackageNode(nodes, "java.util"); - List modRefs = pkgUtil.getModuleReferences(); - assertEquals(2, modRefs.size()); + List modLinks = pkgUtil.getModuleLinks(); + assertEquals(2, modLinks.size()); - List modNames = modRefs.stream().map(ModuleReference::name).toList(); + List modNames = modLinks.stream().map(ModuleLink::name).toList(); assertEquals(List.of("java.base", "java.logging"), modNames); // Ordered by name. - assertNonEmptyRef(modRefs.get(0), "java.base"); - assertEmptyRef(modRefs.get(1), "java.logging"); + assertNonEmptyLink(modLinks.get(0), "java.base"); + assertEmptyLink(modLinks.get(1), "java.logging"); } @Test @@ -160,11 +160,11 @@ public void expectedPackageEntries_withPreviewResources() { Tree tree = new Tree(paths); Map nodes = tree.getMap(); PackageNode pkgUtil = getPackageNode(nodes, "java.util"); - List modRefs = pkgUtil.getModuleReferences(); + List modLinks = pkgUtil.getModuleLinks(); - ModuleReference baseRef = modRefs.get(0); - assertNonEmptyRef(baseRef, "java.base"); - assertTrue(baseRef.hasPreviewVersion()); + ModuleLink baseLink = modLinks.get(0); + assertNonEmptyLink(baseLink, "java.base"); + assertTrue(baseLink.hasPreviewVersion()); } @Test @@ -178,13 +178,13 @@ public void expectedPackageEntries_withPreviewOnlyPackages() { // Preview only package (with content). PackageNode nonEmptyPkg = getPackageNode(nodes, "java.util.preview.only"); - ModuleReference nonEmptyRef = nonEmptyPkg.getModuleReferences().getFirst(); - assertNonEmptyPreviewOnlyRef(nonEmptyRef, "java.base"); + ModuleLink nonEmptyLink = nonEmptyPkg.getModuleLinks().getFirst(); + assertNonEmptyPreviewOnlyLink(nonEmptyLink, "java.base"); // Preview only packages can be empty. PackageNode emptyPkg = getPackageNode(nodes, "java.util.preview"); - ModuleReference emptyRef = emptyPkg.getModuleReferences().getFirst(); - assertEmptyPreviewOnlyRef(emptyRef, "java.base"); + ModuleLink emptyLink = emptyPkg.getModuleLinks().getFirst(); + assertEmptyPreviewOnlyLink(emptyLink, "java.base"); } @Test @@ -211,19 +211,19 @@ public void expectedPackageOrder_sharedPackage() { Map nodes = tree.getMap(); PackageNode sharedPkg = getPackageNode(nodes, "java.shared"); - List refs = sharedPkg.getModuleReferences(); + List links = sharedPkg.getModuleLinks(); // Preview packages first, by name. int n = 1; - for (ModuleReference ref : refs.subList(0, 3)) { - assertEmptyPreviewOnlyRef(ref, "java.preview" + (n++)); + for (ModuleLink link : links.subList(0, 3)) { + assertEmptyPreviewOnlyLink(link, "java.preview" + (n++)); } // The content package (simply due to its name). - assertNonEmptyRef(refs.get(3), "java.content"); + assertNonEmptyLink(links.get(3), "java.content"); // And the non-preview empty packages after. n = 1; - for (ModuleReference ref : refs.subList(4, 7)) { - assertEmptyRef(ref, "java.module" + (n++)); + for (ModuleLink link : links.subList(4, 7)) { + assertEmptyLink(link, "java.module" + (n++)); } } @@ -239,27 +239,27 @@ static void assertContainsResources(Node dirNode, String... resourceNames) { } } - static void assertNonEmptyRef(ModuleReference ref, String modName) { - assertEquals(modName, ref.name(), "Unexpected module name: " + ref); - assertTrue(ref.hasResources(), "Expected non-empty reference: " + ref); - assertFalse(ref.isPreviewOnly(), "Expected not preview-only: " + ref); + static void assertNonEmptyLink(ModuleLink link, String modName) { + assertEquals(modName, link.name(), "Unexpected module name: " + link); + assertTrue(link.hasResources(), "Expected non-empty link: " + link); + assertFalse(link.isPreviewOnly(), "Expected not preview-only: " + link); } - static void assertEmptyRef(ModuleReference ref, String modName) { - assertEquals(modName, ref.name(), "Unexpected module name: " + ref); - assertFalse(ref.hasResources(), "Expected empty reference: " + ref); - assertFalse(ref.isPreviewOnly(), "Expected not preview-only: " + ref); + static void assertEmptyLink(ModuleLink link, String modName) { + assertEquals(modName, link.name(), "Unexpected module name: " + link); + assertFalse(link.hasResources(), "Expected empty link: " + link); + assertFalse(link.isPreviewOnly(), "Expected not preview-only: " + link); } - static void assertNonEmptyPreviewOnlyRef(ModuleReference ref, String modName) { - assertEquals(modName, ref.name(), "Unexpected module name: " + ref); - assertTrue(ref.hasResources(), "Expected empty reference: " + ref); - assertTrue(ref.isPreviewOnly(), "Expected preview-only: " + ref); + static void assertNonEmptyPreviewOnlyLink(ModuleLink link, String modName) { + assertEquals(modName, link.name(), "Unexpected module name: " + link); + assertTrue(link.hasResources(), "Expected non-empty link: " + link); + assertTrue(link.isPreviewOnly(), "Expected preview-only: " + link); } - static void assertEmptyPreviewOnlyRef(ModuleReference ref, String modName) { - assertEquals(modName, ref.name(), "Unexpected module name: " + ref); - assertFalse(ref.hasResources(), "Expected empty reference: " + ref); - assertTrue(ref.isPreviewOnly(), "Expected preview-only: " + ref); + static void assertEmptyPreviewOnlyLink(ModuleLink link, String modName) { + assertEquals(modName, link.name(), "Unexpected module name: " + link); + assertFalse(link.hasResources(), "Expected empty link: " + link); + assertTrue(link.isPreviewOnly(), "Expected preview-only: " + link); } }