Skip to content

Commit

Permalink
Enable support for running against the current JVM's ct.sym file. Req…
Browse files Browse the repository at this point in the history
…uire a minimum of Java SE 17 for testing and add Java 17 tests.

Signed-off-by: James R. Perkins <[email protected]>
  • Loading branch information
jamezp committed Feb 14, 2024
1 parent e2b9be0 commit b28ae26
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 34 deletions.
46 changes: 27 additions & 19 deletions tools/sigtest/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit b28ae26

Please sign in to comment.