Skip to content

Commit

Permalink
[6.4.0] Fix Java compilation for jdk21 (bazelbuild#19735)
Browse files Browse the repository at this point in the history
Fixes bazelbuild#19680

Backported from
bazelbuild/rules_java@325a9e1:
```
Use JRTFS instead of initializing a FileManager to process --system


PiperOrigin-RevId: 565773578
Change-Id: I1c8a803d1650d8c0beb9a6bf074b53369144e1df
```
  • Loading branch information
hvadehra authored Oct 5, 2023
1 parent ef72058 commit b598797
Showing 1 changed file with 36 additions and 54 deletions.
90 changes: 36 additions & 54 deletions tools/jdk/DumpPlatformClassPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,26 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javac.util.Context;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
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.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
Expand All @@ -38,16 +42,11 @@
import java.util.jar.JarOutputStream;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;

/**
* Output a jar file containing all classes on the platform classpath of the given JDK release.
*
* <p>usage: DumpPlatformClassPath <release version> <output jar> <path to target JDK>?
* <p>usage: {@code DumpPlatformClassPath <output jar> <path to target JDK>}
*/
public class DumpPlatformClassPath {

Expand Down Expand Up @@ -90,58 +89,43 @@ static boolean dumpJDK9AndNewerBootClassPath(
// * --release takes a language level (e.g. '9') and uses the API information baked in to
// the host JDK (in lib/ct.sym).

// Since --system only supports JDK >= 9, first check of the target JDK defines a JDK 8
// Since --system only supports JDK >= 9, first check if the target JDK defines a JDK 8
// bootclasspath.
List<Path> bootClassPathJars = getBootClassPathJars(targetJavabase);
if (!bootClassPathJars.isEmpty()) {
writeClassPathJars(output, bootClassPathJars);
return true;
}

// Initialize a FileManager to process the --system argument, and then read the
// initialized bootclasspath data back out.

Context context = new Context();
try {
JavacTool.create()
.getTask(
/* out = */ null,
/* fileManager = */ null,
/* diagnosticListener = */ null,
/* options = */ Arrays.asList("--system", String.valueOf(targetJavabase)),
/* classes = */ null,
/* compilationUnits = */ null,
context);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
String.format(
"Failed to collect system class path. Please ensure that the configured Java runtime"
+ " ('%s') is a complete JDK. There are known issues with Homebrew versions of"
+ " the Java runtime.",
targetJavabase.toRealPath()),
e);
}
StandardJavaFileManager fileManager =
(StandardJavaFileManager) context.get(JavaFileManager.class);

SortedMap<String, InputStream> entries = new TreeMap<>();
for (JavaFileObject fileObject :
fileManager.list(
StandardLocation.PLATFORM_CLASS_PATH,
"",
EnumSet.of(Kind.CLASS),
/* recurse= */ true)) {
String binaryName =
fileManager.inferBinaryName(StandardLocation.PLATFORM_CLASS_PATH, fileObject);
entries.put(binaryName.replace('.', '/') + ".class", fileObject.openInputStream());
// Read the bootclasspath data using the JRT filesystem
Map<String, byte[]> entries = new TreeMap<>();
Map<String, String> env = new TreeMap<>();
env.put("java.home", String.valueOf(targetJavabase));
try (FileSystem fileSystem = FileSystems.newFileSystem(URI.create("jrt:/"), env)) {
Path modules = fileSystem.getPath("/modules");
try (DirectoryStream<Path> ms = Files.newDirectoryStream(modules)) {
for (Path m : ms) {
Files.walkFileTree(
m,
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
if (file.getFileName().toString().endsWith(".class")) {
entries.put(m.relativize(file).toString(), Files.readAllBytes(file));
}
return super.visitFile(file, attrs);
}
});
}
}
writeEntries(output, entries);
}
writeEntries(output, entries);
return true;
}

/** Writes the given entry names and data to a jar archive at the given path. */
private static void writeEntries(Path output, Map<String, InputStream> entries)
throws IOException {
private static void writeEntries(Path output, Map<String, byte[]> entries) throws IOException {
if (!entries.containsKey("java/lang/Object.class")) {
throw new AssertionError(
"\nCould not find java.lang.Object on bootclasspath; something has gone terribly wrong.\n"
Expand All @@ -168,14 +152,14 @@ private static void writeClassPathJars(Path output, Collection<Path> paths) thro
for (Path path : paths) {
jars.add(new JarFile(path.toFile()));
}
SortedMap<String, InputStream> entries = new TreeMap<>();
SortedMap<String, byte[]> entries = new TreeMap<>();
for (JarFile jar : jars) {
jar.stream()
.filter(p -> p.getName().endsWith(".class"))
.forEachOrdered(
entry -> {
try {
entries.put(entry.getName(), jar.getInputStream(entry));
entries.put(entry.getName(), toByteArray(jar.getInputStream(entry)));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Expand Down Expand Up @@ -214,12 +198,10 @@ private static List<Path> getBootClassPathJars(Path javaHome) throws IOException
* Add a jar entry to the given {@link JarOutputStream}, normalizing the entry timestamps to
* ensure deterministic build output.
*/
private static void addEntry(JarOutputStream jos, String name, InputStream input)
throws IOException {
private static void addEntry(JarOutputStream jos, String name, byte[] bytes) throws IOException {
JarEntry je = new JarEntry(name);
je.setTime(FIXED_TIMESTAMP);
je.setMethod(ZipEntry.STORED);
byte[] bytes = toByteArray(input);
// When targeting JDK >= 10, patch the major version so it will be accepted by javac 9
// TODO(cushon): remove this after updating javac
if (bytes[7] > 53) {
Expand Down

0 comments on commit b598797

Please sign in to comment.