// Copyright 2017 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Comparator.comparing; 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.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.Arrays; import java.util.EnumSet; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import java.util.zip.CRC32; import java.util.zip.ZipEntry; import javax.tools.JavaCompiler; import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; import javax.tools.StandardJavaFileManager; import javax.tools.StandardLocation; import javax.tools.ToolProvider; /** * Output a jar file containing all classes on the JDK 8 platform classpath of the default java * compiler of the current JDK. * *

usage: DumpPlatformClassPath output.jar */ public class DumpPlatformClassPath { public static void main(String[] args) throws IOException { if (args.length != 2) { System.err.println("usage: DumpPlatformClassPath "); System.exit(1); } String targetRelease = args[0]; Map entries = new HashMap<>(); JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, UTF_8); if (isJdk9OrLater()) { // this configures the filemanager to use a JDK 8 bootclasspath compiler.getTask( null, fileManager, null, Arrays.asList("--release", targetRelease), null, null); for (Path path : getLocationAsPaths(fileManager)) { Files.walkFileTree( path, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (file.getFileName().toString().endsWith(".sig")) { String outputPath = path.relativize(file).toString(); outputPath = outputPath.substring(0, outputPath.length() - ".sig".length()) + ".class"; entries.put(outputPath, Files.readAllBytes(file)); } return FileVisitResult.CONTINUE; } }); } } else { 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", toByteArray(fileObject.openInputStream())); } } try (OutputStream os = Files.newOutputStream(Paths.get(args[1])); BufferedOutputStream bos = new BufferedOutputStream(os, 65536); JarOutputStream jos = new JarOutputStream(bos)) { entries .entrySet() .stream() .sorted(comparing(Map.Entry::getKey)) .forEachOrdered(e -> addEntry(jos, e.getKey(), e.getValue())); } } @SuppressWarnings("unchecked") private static Iterable getLocationAsPaths(StandardJavaFileManager fileManager) { try { return (Iterable) StandardJavaFileManager.class .getMethod("getLocationAsPaths", Location.class) .invoke(fileManager, StandardLocation.PLATFORM_CLASS_PATH); } catch (ReflectiveOperationException e) { throw new LinkageError(e.getMessage(), e); } } // Use a fixed timestamp for deterministic jar output. private static final long FIXED_TIMESTAMP = new GregorianCalendar(2010, 0, 1, 0, 0, 0).getTimeInMillis(); private static void addEntry(JarOutputStream jos, String name, byte[] bytes) { try { JarEntry je = new JarEntry(name); je.setTime(FIXED_TIMESTAMP); je.setMethod(ZipEntry.STORED); je.setSize(bytes.length); CRC32 crc = new CRC32(); crc.update(bytes); je.setCrc(crc.getValue()); jos.putNextEntry(je); jos.write(bytes); } catch (IOException e) { throw new UncheckedIOException(e); } } private static byte[] toByteArray(InputStream is) throws IOException { byte[] buffer = new byte[8192]; ByteArrayOutputStream boas = new ByteArrayOutputStream(); while (true) { int r = is.read(buffer); if (r == -1) { break; } boas.write(buffer, 0, r); } return boas.toByteArray(); } private static boolean isJdk9OrLater() { return Double.parseDouble(System.getProperty("java.class.version")) >= 53.0; } }