Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix the sigtest Release to allow for new JVM's #24

Merged
merged 2 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 28 additions & 20 deletions tools/sigtest/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<groupId>jakarta.tck</groupId>
<artifactId>sigtest-maven-plugin</artifactId>
<version>2.0</version>
<version>2.1-SNAPSHOT</version>
<packaging>maven-plugin</packaging>
<name>API Signature Test Plugin</name>
<url>https://github.com/eclipse-ee4j/jakartaee-tck-tools/wiki</url>
Expand All @@ -27,26 +27,40 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<ct.sym>${java.home}/lib/ct.sym</ct.sym>

<maven.compiler.release>11</maven.compiler.release>
<!-- Require a Java 17 for testing and compiling -->
<maven.compiler.testRelease>17</maven.compiler.testRelease>
<jdk.min.version>${maven.compiler.testRelease}</jdk.min.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<id>enforce-java-version</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireJavaVersion>
<message>To build this project JDK ${jdk.min.version} (or greater) is required.</message>
<version>${jdk.min.version}</version>
</requireJavaVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<dependencies>
<dependency>
<groupId>org.frgaal</groupId>
<artifactId>compiler-maven-plugin</artifactId>
<version>21.0.0</version>
</dependency>
</dependencies>
<version>3.12.1</version>
<configuration>
<compilerId>frgaal</compilerId>
<source>17</source>
<target>1.8</target>
<testSource>15</testSource>
<testTarget>15</testTarget>
<compilerArgs>
<arg>-Xlint:deprecation</arg>
</compilerArgs>
Expand Down Expand Up @@ -214,12 +228,6 @@
<version>3.9.6</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.frgaal</groupId>
<artifactId>compiler</artifactId>
<version>21.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.netbeans.tools</groupId>
<artifactId>ct-sym</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,34 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public final class Release {
public static final Release BOOT_CLASS_PATH = new Release('0', null);
public static final Release BOOT_CLASS_PATH = new Release('0', null, null);

private final char version;
private final FileSystem zipFs;
private final String[] prefixes;

private Release(char version, String... prefixes) {
private Release(char version, FileSystem zipFs, String... prefixes) {
this.version = version;
this.prefixes = prefixes;
this.zipFs = zipFs;
this.prefixes =prefixes;
}

/**
Expand All @@ -39,8 +53,31 @@ InputStream findClass(String name) {
return ClassLoader.getSystemClassLoader().getResourceAsStream(resourceName);
} else {
for (String p : prefixes) {
final String resourceName = "/META-INF/sigtest/" + p + "/" + name.replace('.', '/') + ".sig";
InputStream is = Release.class.getResourceAsStream(resourceName);
InputStream is = null;
// We're using the local ct.sym file
if (zipFs != null) {
if (p.endsWith("system-modules")) {
// The current release does not container sig files we need to just return the class resource
// from our current class path.
final String resourceName = name.replace('.', '/') + ".class";
return ClassLoader.getSystemClassLoader().getResourceAsStream(resourceName);
}
try {
// Look for the signature file in the ct.sym archive.
final Path sigFile = zipFs.getPath(p + "/" + name.replace('.', '/') + ".sig");
if (Files.exists(sigFile)) {
is = Files.newInputStream(sigFile);
}
} catch (IOException e) {
// This is unlikely, but it seems we should fail early on this as an indicator to what might
// be wrong.
throw new UncheckedIOException(e);
}
} else {
// Attempt to use signature files that may be on the class path
final String resourceName = "/META-INF/sigtest/" + p + "/" + name.replace('.', '/') + ".sig";
is = Release.class.getResourceAsStream(resourceName);
}
if (is != null) {
return is;
}
Expand All @@ -53,18 +90,67 @@ InputStream findClass(String name) {
private static final Map<Character, Release> RELEASES;
static {
List<String> lines = new ArrayList<>();
try {
try (BufferedReader r = new BufferedReader(new InputStreamReader(Release.class.getResourceAsStream("/META-INF/sigtest.ls")))) {
for (;;) {
String l = r.readLine();
if (l == null) {
break;
final FileSystem zipFs;
final Path ctSym = Paths.get(System.getProperty("java.home"), "lib", "ct.sym");
// If the ct.sym file exists, use it. This is useful when testing with a JVM which is newer than the used to
// create the library that embeds the signature files.
if (Files.exists(ctSym)) {
try {
zipFs = zipFs(ctSym);
// We need to shut down the FileSystem. This is not ideal in some environments, but it's better than
// leaving resources open.
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
zipFs.close();
} catch (IOException ignore) {
}
}));
// Walk the root of the ZIP file to build the prefixes. This is akin to what
// org.netbeans.apitest.ListCtSym does.
Files.walkFileTree(zipFs.getPath("/"), Set.of(), 2, new SimpleFileVisitor<>() {
private String prefix;

@Override
public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) {
prefix = dir.getFileName() == null ? null : dir.getFileName().toString();
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) {
final String fileName = file.getFileName().toString();
String newPrefix = prefix == null ? fileName : prefix + "/" + fileName;
if (prefix != null) {
lines.add(newPrefix);
}
return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult postVisitDirectory(final Path dir, final IOException exc) {
prefix = null;
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
throw new InternalError(e);
}
} else {
// The ct.sym file does not exist. Use the sigtest.ls file which should be on the class path
zipFs = null;
try {
try (BufferedReader r = new BufferedReader(new InputStreamReader(Release.class.getResourceAsStream("/META-INF/sigtest.ls")))) {
for (; ; ) {
String l = r.readLine();
if (l == null) {
break;
}
lines.add(l);
}
lines.add(l);
}
} catch (IOException ex) {
throw new InternalError(ex);
}
} catch (IOException ex) {
throw new InternalError(ex);
}

Map<Character,List<String>> prefixes = new HashMap<>();
Expand All @@ -86,9 +172,19 @@ InputStream findClass(String name) {
for (Map.Entry<Character, List<String>> entry : prefixes.entrySet()) {
Character key = entry.getKey();
List<String> value = entry.getValue();
releases.put(key, new Release(key, value.toArray(new String[0])));
releases.put(key, new Release(key, zipFs, value.toArray(new String[0])));
}

RELEASES = releases;
}

private static FileSystem zipFs(final Path path) throws IOException {
// locate file system by using the syntax defined in java.net.JarURLConnection
URI uri = URI.create("jar:" + path.toUri());
try {
return FileSystems.getFileSystem(uri);
} catch (FileSystemNotFoundException ignore) {
}
return FileSystems.newFileSystem(uri, Map.of());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ public void testFindJDK15() throws ClassNotFoundException {
assertMethods(deprecatedClass, "forRemoval", "since");
}

@Test
public void testFindJDK17() throws ClassNotFoundException {
Release jdk17 = Release.find(17);
assertNotNull(jdk17.findClass("java.lang.Object"));
assertNotNull(jdk17.findClass("java.lang.Module"));
assertNotNull(jdk17.findClass("java.lang.Record"));
assertNotNull(jdk17.findClass("java.util.random.RandomGeneratorFactory"));
BinaryClassDescrLoader loader = new BinaryClassDescrLoader(new ClasspathImpl(jdk17, null), 4096);
ClassDescription deprecatedClass = loader.load("java.lang.Deprecated");
assertMethods(deprecatedClass, "forRemoval", "since");
}

private void assertMethods(ClassDescription deprecatedClass, String... names) {
MethodDescr[] arr = deprecatedClass.getDeclaredMethods();
assertEquals("Same number of methods: " + Arrays.toString(arr), names.length, arr.length);
Expand Down