8268611: jar --validate should check targeted classes in MR-JAR files

Reviewed-by: jvernee
This commit is contained in:
Christian Stein 2024-12-17 07:16:12 +00:00
parent 87804f24b2
commit bd3c0be36d
14 changed files with 124 additions and 108 deletions

View File

@ -131,6 +131,14 @@ final class FingerPrint {
return attrs.name;
}
public int classMajorVersion() {
return attrs.majorVersion; // ..., 53, 54, ...
}
public int classReleaseVersion() {
return attrs.majorVersion - 44; // ..., 53 -> 9, 54 -> 10, ...
}
public int mrversion() {
return mrversion;
}

View File

@ -209,18 +209,8 @@ public class Main {
}
}
static String formatMsg(String key, String arg) {
static String formatMsg(String key, String... args) {
String msg = getMsg(key);
String[] args = new String[1];
args[0] = arg;
return MessageFormat.format(msg, (Object[]) args);
}
static String formatMsg2(String key, String arg, String arg1) {
String msg = getMsg(key);
String[] args = new String[2];
args[0] = arg;
args[1] = arg1;
return MessageFormat.format(msg, (Object[]) args);
}
@ -458,7 +448,7 @@ public class Main {
try (ZipFile zf = new ZipFile(file)) {
return Validator.validate(this, zf);
} catch (IOException e) {
error(formatMsg2("error.validator.jarfile.exception", fname, e.getMessage()));
error(formatMsg("error.validator.jarfile.exception", fname, e.getMessage()));
return true;
}
}
@ -839,7 +829,7 @@ public class Main {
// the entry starts with VERSIONS_DIR and version != BASE_VERSION,
// which means the "[dirs|files]" in --release v [dirs|files]
// includes VERSIONS_DIR-ed entries --> warning and skip (?)
error(formatMsg2("error.release.unexpected.versioned.entry",
error(formatMsg("error.release.unexpected.versioned.entry",
name, String.valueOf(version)));
ok = false;
return;
@ -1263,8 +1253,7 @@ public class Main {
if (vflag) {
size = e.getSize();
long csize = e.getCompressedSize();
out.print(formatMsg2("out.size", String.valueOf(size),
String.valueOf(csize)));
out.print(formatMsg("out.size", String.valueOf(size), String.valueOf(csize)));
if (e.getMethod() == ZipEntry.DEFLATED) {
long ratio = 0;
if (size != 0) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2024, 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
@ -51,7 +51,6 @@ import static sun.tools.jar.Main.VERSIONS_DIR_LENGTH;
import static sun.tools.jar.Main.MODULE_INFO;
import static sun.tools.jar.Main.getMsg;
import static sun.tools.jar.Main.formatMsg;
import static sun.tools.jar.Main.formatMsg2;
import static sun.tools.jar.Main.toBinaryName;
final class Validator {
@ -164,7 +163,15 @@ final class Validator {
public void validateVersioned(Map<String, FingerPrint> fps) {
fps.values().forEach( fp -> {
// all versioned entries must be compatible with their release target number
if (fp.mrversion() < fp.classReleaseVersion()) {
errorAndInvalid(formatMsg("error.release.value.toohigh.versioned.entry",
fp.entryName(), // META-INF/versions/9/com/foo/Bar.class has class file version
String.valueOf(fp.classMajorVersion()), // 69, but class file version
String.valueOf(fp.mrversion() + 44), // 53 or less is required to target release
String.valueOf(fp.mrversion()))); // 9 of the Java Platform
return;
}
// validate the versioned module-info
if (MODULE_INFO.equals(fp.basename())) {
checkModuleDescriptor(fp.entryName());
@ -310,7 +317,7 @@ final class Validator {
if (fp.className().equals(className(fp.basename()))) {
return true;
}
error(formatMsg2("error.validator.names.mismatch",
error(formatMsg("error.validator.names.mismatch",
fp.entryName(), fp.className().replace("/", ".")));
return isValid = false;
}

View File

@ -90,6 +90,8 @@ error.release.value.toosmall=\
release {0} not valid, must be >= 9
error.release.unexpected.versioned.entry=\
unexpected versioned entry {0} for release {1}
error.release.value.toohigh.versioned.entry=\
{0} has class file version {1}, but class file version {2} or less is required to target release {3} of the Java Platform
error.date.notvalid=\
date {0} is not a valid ISO-8601 extended offset date-time with optional time-zone
error.date.out.of.range=\

View File

@ -125,15 +125,15 @@ public class MVJarSigningTest {
private static void compile (String jarContent_path) throws Throwable {
Path classes = Paths.get(USR_DIR, "classes", "base");
Path source = Paths.get(TEST_SRC, jarContent_path, "base", "version");
CompilerUtils.compile(source, classes);
CompilerUtils.compile(source, classes, "--release", "8");
classes = Paths.get(USR_DIR, "classes", "v9");
source = Paths.get(TEST_SRC, jarContent_path , "v9", "version");
CompilerUtils.compile(source, classes);
CompilerUtils.compile(source, classes, "--release", "9");
classes = Paths.get(USR_DIR, "classes", "v10");
source = Paths.get(TEST_SRC, jarContent_path, "v10", "version");
CompilerUtils.compile(source, classes);
CompilerUtils.compile(source, classes, "--release", "10");
}
private static OutputAnalyzer jar(String...args) throws Throwable {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2024, 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
@ -49,6 +49,7 @@ import java.lang.module.ModuleDescriptor.Version;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
@ -80,25 +81,28 @@ public class Basic {
// compile the classes directory
Path source = testsrc.resolve("src").resolve("classes");
Path destination = Paths.get("classes");
javac(source, destination);
javac(source, destination, 8);
// compile the mr9 directory including module-info.java
source = testsrc.resolve("src").resolve("mr9");
destination = Paths.get("mr9");
javac(source, destination);
javac(source, destination, 9);
// move module-info.class for later use
Files.move(destination.resolve("module-info.class"),
Paths.get("module-info.class"));
}
private void javac(Path source, Path destination) throws IOException {
String[] args = Stream.concat(
Stream.of("-d", destination.toString()),
Files.walk(source)
.map(Path::toString)
.filter(s -> s.endsWith(".java"))
).toArray(String[]::new);
private void javac(Path source, Path destination, int release) throws IOException {
ArrayList<Object> arguments = new ArrayList();
arguments.add("-d");
arguments.add(destination);
arguments.add("--release");
arguments.add(release);
try (var stream = Files.walk(source)) {
stream.map(Path::toString).filter(s -> s.endsWith(".java")).forEach(arguments::add);
}
String[] args = arguments.stream().map(Object::toString).toArray(String[]::new);
JAVAC_TOOL.run(System.out, System.err, args);
}
@ -110,8 +114,8 @@ public class Basic {
@AfterClass
public void cleanup() throws IOException {
Files.walk(userdir, 1)
.filter(p -> !p.equals(userdir))
try (var stream = Files.walk(userdir, 1)) {
stream.filter(p -> !p.equals(userdir))
.forEach(p -> {
try {
if (Files.isDirectory(p)) {
@ -123,6 +127,7 @@ public class Basic {
throw new UncheckedIOException(x);
}
});
}
}
// updates a valid multi-release jar with a new public class in
@ -229,7 +234,7 @@ public class Basic {
// compile the mr10 directory
Path source = testsrc.resolve("src").resolve("mr10");
Path destination = Paths.get("mr10");
javac(source, destination);
javac(source, destination, 10);
// create a directory for this tests special files
Files.createDirectory(Paths.get("test5"));
@ -240,7 +245,7 @@ public class Basic {
Files.write(modinfo, hi.getBytes());
// and compile it
javac(modinfo, Paths.get("test5"));
javac(modinfo, Paths.get("test5"), 9);
int rc = jar("--create --file mr.jar -C classes .");
Assert.assertEquals(rc, 0);
@ -335,7 +340,7 @@ public class Basic {
// compile the classes directory
Path src = testsrc.resolve("src").resolve("classes");
Path dst = Paths.get("test6");
javac(src, dst);
javac(src, dst, 8);
byte[] mdBytes = Files.readAllBytes(Paths.get("module-info.class"));
@ -397,7 +402,7 @@ public class Basic {
// compile the classes directory
Path src = testsrc.resolve("src").resolve("classes");
Path dst = Paths.get("test7");
javac(src, dst);
javac(src, dst, 8);
// move module-info.class to v9 later use
Files.copy(Paths.get("module-info.class"),

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2024, 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
@ -82,8 +82,8 @@ public class ApiValidatorTest extends MRTestBase {
String base = classTemplate.replace(METHOD_SIG, sigBase);
String v10 = classTemplate.replace(METHOD_SIG, sigV10);
compileTemplate(classes.resolve("base"), base);
compileTemplate(classes.resolve("v10"), v10);
compileTemplate(8, classes.resolve("base"), base);
compileTemplate(10, classes.resolve("v10"), v10);
String jarfile = root.resolve("test.jar").toString();
OutputAnalyzer result = jar("cf", jarfile,
@ -135,8 +135,8 @@ public class ApiValidatorTest extends MRTestBase {
String base = classTemplate.replace(API, "");
String v10 = classTemplate.replace(API, publicAPI);
compileTemplate(classes.resolve("base"), base);
compileTemplate(classes.resolve("v10"), v10);
compileTemplate(8, classes.resolve("base"), base);
compileTemplate(10, classes.resolve("v10"), v10);
String failureMessage = "contains a class with different api from earlier version";
@ -176,8 +176,8 @@ public class ApiValidatorTest extends MRTestBase {
String base = classTemplate.replace(API, "");
String v10 = classTemplate.replace(API, privateAPI);
compileTemplate(classes.resolve("base"), base);
compileTemplate(classes.resolve("v10"), v10);
compileTemplate(8, classes.resolve("base"), base);
compileTemplate(10, classes.resolve("v10"), v10);
String jarfile = root.resolve("test.jar").toString();
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
@ -208,12 +208,12 @@ public class ApiValidatorTest extends MRTestBase {
};
}
private void compileTemplate(Path classes, String template) throws Throwable {
private void compileTemplate(int release, Path classes, String template) throws Throwable {
Path classSourceFile = Files.createDirectories(
classes.getParent().resolve("src").resolve(classes.getFileName()))
.resolve("C.java");
Files.write(classSourceFile, template.getBytes());
javac(classes, classSourceFile);
javac(release, classes, classSourceFile);
}
/* Modular multi-release checks */
@ -452,7 +452,7 @@ public class ApiValidatorTest extends MRTestBase {
sourceFiles[i + 1] = sourceFile;
}
javac(classes, sourceFiles);
javac(9, classes, sourceFiles);
}
@SafeVarargs

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2024, 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 @@
/*
* @test
# @bug 8186087 8196748 8212807
# @bug 8186087 8196748 8212807 8268611
* @library /test/lib
* @modules java.base/jdk.internal.misc
* jdk.compiler
@ -126,9 +126,9 @@ public class Basic extends MRTestBase {
Path classes = Paths.get("classes");
// valid
for (String release : List.of("10000", "09", "00010", "10")) {
for (String release : List.of("09", "00010", "10")) {
jarTool("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
"--release", release, "-C", classes.resolve("v10").toString(), ".")
"--release", release, "-C", classes.resolve("v9").toString(), ".")
.shouldHaveExitValue(SUCCESS)
.shouldBeEmptyIgnoreVMWarnings();
}
@ -207,26 +207,16 @@ public class Basic extends MRTestBase {
compare(jarfile, names);
// 8268611: The following creates an invalid JAR, which gets deleted.
// write the v9 version/Version.class entry in base and the v10
// version/Version.class entry in versions/9 section
jarTool("uf", jarfile, "-C", classes.resolve("v9").toString(), "version",
"--release", "9", "-C", classes.resolve("v10").toString(), ".")
.shouldHaveExitValue(SUCCESS);
checkMultiRelease(jarfile, true);
names = Map.of(
"version/Main.class",
new String[]{"base", "version", "Main.class"},
"version/Version.class",
new String[]{"v9", "version", "Version.class"},
"META-INF/versions/9/version/Version.class",
new String[]{"v10", "version", "Version.class"}
);
compare(jarfile, names);
.shouldNotHaveExitValue(SUCCESS)
.shouldContain("META-INF/versions/9/version/Version.class")
.shouldContain(" has class file version 54,")
.shouldContain(" but class file version 53 or less is required")
.shouldContain(" to target release 9 of the Java Platform");
FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
@ -247,7 +237,7 @@ public class Basic extends MRTestBase {
// replace the v9 class
Path source = Paths.get(src, "data", "test04", "v9", "version");
javac(classes.resolve("v9"), source.resolve("Version.java"));
javac(9, classes.resolve("v9"), source.resolve("Version.java"));
jarTool("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
@ -269,7 +259,7 @@ public class Basic extends MRTestBase {
// add the new v9 class
Path source = Paths.get(src, "data", "test05", "v9", "version");
javac(classes.resolve("v9"), source.resolve("Extra.java"));
javac(9, classes.resolve("v9"), source.resolve("Extra.java"));
jarTool("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
@ -291,7 +281,7 @@ public class Basic extends MRTestBase {
// add the new v9 class
Path source = Paths.get(src, "data", "test06", "v9", "version");
javac(classes.resolve("v9"), source.resolve("Extra.java"));
javac(9, classes.resolve("v9"), source.resolve("Extra.java"));
jarTool("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
@ -313,7 +303,7 @@ public class Basic extends MRTestBase {
// add the new v9 class
Path source = Paths.get(src, "data", "test01", "base", "version");
javac(classes.resolve("v9"), source.resolve("Version.java"));
javac(9, classes.resolve("v9"), source.resolve("Version.java"));
jarTool("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
@ -382,11 +372,11 @@ public class Basic extends MRTestBase {
// add a base class with a nested class
Path source = Paths.get(src, "data", "test10", "base", "version");
javac(classes.resolve("base"), source.resolve("Nested.java"));
javac(8, classes.resolve("base"), source.resolve("Nested.java"));
// add a versioned class with a nested class
source = Paths.get(src, "data", "test10", "v9", "version");
javac(classes.resolve("v9"), source.resolve("Nested.java"));
javac(9, classes.resolve("v9"), source.resolve("Nested.java"));
jarTool("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
@ -407,14 +397,14 @@ public class Basic extends MRTestBase {
// add a base class with a nested class
Path source = Paths.get(src, "data", "test10", "base", "version");
javac(classes.resolve("base"), source.resolve("Nested.java"));
javac(8, classes.resolve("base"), source.resolve("Nested.java"));
// remove the top level class, thus isolating the nested class
Files.delete(classes.resolve("base").resolve("version").resolve("Nested.class"));
// add a versioned class with a nested class
source = Paths.get(src, "data", "test10", "v9", "version");
javac(classes.resolve("v9"), source.resolve("Nested.java"));
javac(9, classes.resolve("v9"), source.resolve("Nested.java"));
List<String> output = jarTool("cf", jarfile,
"-C", classes.resolve("base").toString(), ".",
@ -460,11 +450,11 @@ public class Basic extends MRTestBase {
// add a base class with a nested class
Path source = Paths.get(src, "data", "test10", "base", "version");
javac(classes.resolve("base"), source.resolve("Nested.java"));
javac(8, classes.resolve("base"), source.resolve("Nested.java"));
// add a versioned class with a nested class
source = Paths.get(src, "data", "test10", "v9", "version");
javac(classes.resolve("v9"), source.resolve("Nested.java"));
javac(9, classes.resolve("v9"), source.resolve("Nested.java"));
// remove the top level class, thus isolating the nested class
Files.delete(classes.resolve("v9").resolve("version").resolve("Nested.class"));
@ -489,11 +479,11 @@ public class Basic extends MRTestBase {
// add a base class with a nested and nested-nested class
Path source = Paths.get(src, "data", "test13", "base", "version");
javac(classes.resolve("base"), source.resolve("Nested.java"));
javac(8, classes.resolve("base"), source.resolve("Nested.java"));
// add a versioned class with a nested and nested-nested class
source = Paths.get(src, "data", "test13", "v10", "version");
javac(classes.resolve("v10"), source.resolve("Nested.java"));
javac(10, classes.resolve("v10"), source.resolve("Nested.java"));
jarTool("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
@ -535,7 +525,7 @@ public class Basic extends MRTestBase {
jar("ufm", jarfile, manifest.toString(),
"-C", classes.resolve("base").toString(), ".",
"--release", "9", "-C", classes.resolve("v10").toString(), ".")
"--release", "9", "-C", classes.resolve("v9").toString(), ".")
.shouldHaveExitValue(SUCCESS)
.shouldContain("WARNING: Duplicate name in Manifest: Multi-release.");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2024, 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
@ -52,22 +52,22 @@ public class Basic1 extends MRTestBase {
Path base = classes.resolve("base");
Files.createDirectories(base);
Path source = Paths.get(src, "data", test, "base", "version");
javac(base, source.resolve("Main.java"), source.resolve("Version.java"));
javac(8, base, source.resolve("Main.java"), source.resolve("Version.java"));
Path v9 = classes.resolve("v9");
Files.createDirectories(v9);
source = Paths.get(src, "data", test, "v9", "version");
javac(v9, source.resolve("Version.java"));
javac(9, v9, source.resolve("Version.java"));
Path v10 = classes.resolve("v10");
Files.createDirectories(v10);
source = Paths.get(src, "data", test, "v10", "version");
javac(v10, source.resolve("Version.java"));
javac(10, v10, source.resolve("Version.java"));
Path v10_1 = classes.resolve("v10_1").resolve("META-INF").resolve("versions").resolve("v10");
Files.createDirectories(v10_1);
source = Paths.get(src, "data", test, "v10", "version");
javac(v10_1, source.resolve("Version.java"));
javac(10, v10_1, source.resolve("Version.java"));
}
@Test

View File

@ -62,17 +62,17 @@ public class MRTestBase {
Path classes = Paths.get(usr, "classes", "base");
Files.createDirectories(classes);
Path source = Paths.get(src, "data", test, "base", "version");
javac(classes, source.resolve("Main.java"), source.resolve("Version.java"));
javac(8, classes, source.resolve("Main.java"), source.resolve("Version.java"));
classes = Paths.get(usr, "classes", "v9");
Files.createDirectories(classes);
source = Paths.get(src, "data", test, "v9", "version");
javac(classes, source.resolve("Version.java"));
javac(9, classes, source.resolve("Version.java"));
classes = Paths.get(usr, "classes", "v10");
Files.createDirectories(classes);
source = Paths.get(src, "data", test, "v10", "version");
javac(classes, source.resolve("Version.java"));
javac(10, classes, source.resolve("Version.java"));
}
protected void checkMultiRelease(String jarFile,
@ -101,23 +101,17 @@ public class MRTestBase {
}
}
void javac(Path dest, Path... sourceFiles) throws Throwable {
javac(dest, List.of(), sourceFiles);
}
void javac(Path dest, List<String> extraParameters, Path... sourceFiles) throws Throwable {
void javac(int release, Path dest, Path... sourceFiles) throws Throwable {
List<String> commands = new ArrayList<>();
String opts = System.getProperty("test.compiler.opts");
if (!opts.isEmpty()) {
commands.addAll(Arrays.asList(opts.split(" +")));
}
commands.add("--release");
commands.add(String.valueOf(release));
commands.add("-d");
commands.add(dest.toString());
Stream.of(sourceFiles)
.map(Object::toString)
.forEach(x -> commands.add(x));
commands.addAll(extraParameters);
Stream.of(sourceFiles).map(Object::toString).forEach(commands::add);
StringWriter sw = new StringWriter();
try (PrintWriter pw = new PrintWriter(sw)) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2024, 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
@ -88,7 +88,7 @@ public class VersionValidatorTest extends MRTestBase {
Path classesDir = root.resolve("classes").resolve(majorVersion);
javac(classesDir, List.of("--release", majorVersion), sourceFile);
javac(Integer.parseInt(majorVersion), classesDir, sourceFile);
if (enablePreview) {
rewriteMinorVersionForEnablePreviewClass(classesDir.resolve("Lib.class"));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2024, 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,6 @@
* @test
* @bug 8153654 8176333
* @summary Tests for jdeps tool with multi-release jar files
* @modules jdk.jdeps/com.sun.tools.jdeps
* @library mrjar mrjar/base mrjar/9 mrjar/10 mrjar/v9 mrjar/v10
* @build test.* p.* q.* foo/* Main
* @run testng MultiReleaseJar
@ -38,6 +37,7 @@ import org.testng.annotations.Test;
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Stream;
@ -60,6 +60,15 @@ public class MultiReleaseJar {
fileSep = System.getProperty("file.separator");
cmdPath = Paths.get(testJdk, "bin");
// fixup classfile versions
forceReleaseInClassFile(9, "Main.class");
forceReleaseInClassFile(9, "base/test/Version.class", "base/p/Foo.class");
forceReleaseInClassFile(9, "9/test/NonPublic.class", "9/test/Version.class");
forceReleaseInClassFile(9, "v9/p/Foo.class", "v9/q/Bar.class");
forceReleaseInClassFile(9, "v9/p/Foo.class", "v9/q/Bar.class");
forceReleaseInClassFile(10, "10/test/Version.class");
forceReleaseInClassFile(10, "v10/q/Bar.class", "v10/q/Gee.class");
// build Version.jar, Version_9.jar and main.jar
Result r = run("jar -cf Version.jar -C base test --release 9 -C 9 test --release 10 -C 10 test");
checkResult(r);
@ -74,10 +83,22 @@ public class MultiReleaseJar {
checkResult(r);
Path foo = Paths.get(System.getProperty("test.classes")).resolve("modules").resolve("foo");
forceReleaseInClassFile(9, foo.resolve("module-info.class"));
r = run("jar -uf Foo.jar --release 9 -C " + foo.toString() + " module-info.class --release 10 -C v10 q");
checkResult(r);
}
private void forceReleaseInClassFile(int release, Object... paths) {
for (var path : paths) {
try (var file = new RandomAccessFile(mrjar.resolve(path.toString()).toFile(), "rw")) {
file.seek(4 + 2); // skip magic and minor
file.writeShort(release + 44); // overwrite major
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
}
@Test
public void basic() throws Exception {
Result r = run("jdeps -J-Duser.language=en -J-Duser.country=US --multi-release 9 -v missing.jar");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2024, 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
@ -55,7 +55,7 @@ public class MissingDepsTest {
private static final Path CLASSES_DIR = Paths.get("classes");
private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar").orElseThrow();
private static final String VERSION = "13";
private static final String VERSION = String.valueOf(Runtime.version().feature());
private static final Set<String> modules = Set.of("m1", "m2");
@ -122,7 +122,7 @@ public class MissingDepsTest {
JdepsRunner jdepsRunner = new JdepsRunner(options.toArray(new String[0]));
int rc = jdepsRunner.run(DEBUG);
assertTrue(rc != 0);
String regex = "\\s+13/p.internal.X\\s+->\\s+q.T\\s+not found";
String regex = "\\s+" + VERSION + "/p.internal.X\\s+->\\s+q.T\\s+not found";
assertTrue(Arrays.stream(jdepsRunner.output()).anyMatch(l -> l.matches(regex)));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2024, 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
@ -56,7 +56,7 @@ public class MultiVersionError {
public void compileAll() throws Exception {
CompilerUtils.cleanDir(MODS_DIR);
modules.forEach(mn ->
assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn)));
assertTrue(CompilerUtils.compileModule(SRC_DIR, MODS_DIR, mn, "--release", "9")));
// create a modular multi-release m1.jar
Path m1 = MODS_DIR.resolve("m1");