diff --git a/tools/sigtest/pom.xml b/tools/sigtest/pom.xml index 12e88c22a..8fe760dd5 100644 --- a/tools/sigtest/pom.xml +++ b/tools/sigtest/pom.xml @@ -27,26 +27,40 @@ UTF-8 ${java.home}/lib/ct.sym + + 11 + + 17 + ${maven.compiler.testRelease} + + org.apache.maven.plugins + maven-enforcer-plugin + 3.4.1 + + + enforce-java-version + + enforce + + + + + To build this project JDK ${jdk.min.version} (or greater) is required. + ${jdk.min.version} + + + + + + org.apache.maven.plugins maven-compiler-plugin - 3.8.1 - - - org.frgaal - compiler-maven-plugin - 21.0.0 - - + 3.12.1 - frgaal - 17 - 1.8 - 15 - 15 -Xlint:deprecation @@ -214,12 +228,6 @@ 3.9.6 jar - - org.frgaal - compiler - 21.0.0 - test - org.netbeans.tools ct-sym diff --git a/tools/sigtest/src/main/java/com/sun/tdk/signaturetest/classpath/Release.java b/tools/sigtest/src/main/java/com/sun/tdk/signaturetest/classpath/Release.java index c623e6031..e6fd39651 100644 --- a/tools/sigtest/src/main/java/com/sun/tdk/signaturetest/classpath/Release.java +++ b/tools/sigtest/src/main/java/com/sun/tdk/signaturetest/classpath/Release.java @@ -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; } /** @@ -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; } @@ -53,18 +90,67 @@ InputStream findClass(String name) { private static final Map RELEASES; static { List 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> prefixes = new HashMap<>(); @@ -86,9 +172,19 @@ InputStream findClass(String name) { for (Map.Entry> entry : prefixes.entrySet()) { Character key = entry.getKey(); List 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()); + } } diff --git a/tools/sigtest/src/test/java/com/sun/tdk/signaturetest/classpath/ReleaseTest.java b/tools/sigtest/src/test/java/com/sun/tdk/signaturetest/classpath/ReleaseTest.java index cd12a960a..ec08d501a 100644 --- a/tools/sigtest/src/test/java/com/sun/tdk/signaturetest/classpath/ReleaseTest.java +++ b/tools/sigtest/src/test/java/com/sun/tdk/signaturetest/classpath/ReleaseTest.java @@ -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);