aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2017-03-09 09:47:17 +0000
committerGravatar Vladimir Moskva <vladmos@google.com>2017-03-09 10:30:56 +0000
commit4369f79c0e1667ab517f7570aaa448184daf4e66 (patch)
treeaeebc8445841b665656ae7e1b0dd1dc0d311407e /src/tools/android/java/com/google
parent52ab7d960dab8d5e1003490d4230b9b23c57a492 (diff)
Add an --copy_bridges_from_classpath argument
This argument allows to copy bridges from interfaces that are on the classpath to the desugared classes. RELNOTES: Add an --copy_bridges_from_classpath argument to android desugaring tool -- PiperOrigin-RevId: 149631699 MOS_MIGRATED_REVID=149631699
Diffstat (limited to 'src/tools/android/java/com/google')
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/ClassReaderFactory.java22
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java36
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/HeaderClassLoader.java40
-rw-r--r--src/tools/android/java/com/google/devtools/build/android/desugar/IndexedJars.java84
4 files changed, 128 insertions, 54 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/ClassReaderFactory.java b/src/tools/android/java/com/google/devtools/build/android/desugar/ClassReaderFactory.java
index 6ec4e0d4c9..56f99a3d67 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/ClassReaderFactory.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/ClassReaderFactory.java
@@ -15,31 +15,39 @@ package com.google.devtools.build.android.desugar;
import java.io.IOException;
import java.io.InputStream;
+import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.annotation.Nullable;
import org.objectweb.asm.ClassReader;
class ClassReaderFactory {
- private final ZipFile jar;
+ private final IndexedJars indexedJars;
private final CoreLibraryRewriter rewriter;
- public ClassReaderFactory(ZipFile jar, CoreLibraryRewriter rewriter) {
- this.jar = jar;
+ public ClassReaderFactory(IndexedJars indexedJars, CoreLibraryRewriter rewriter) {
this.rewriter = rewriter;
+ this.indexedJars = indexedJars;
}
/**
* Returns a reader for the given/internal/Class$Name if the class is defined in the wrapped Jar
- * and {@code null} otherwise. For simplicity this method turns checked into runtime excpetions
+ * and {@code null} otherwise. For simplicity this method turns checked into runtime exceptions
* under the assumption that all classes have already been read once when this method is called.
*/
@Nullable
public ClassReader readIfKnown(String internalClassName) {
- ZipEntry entry = jar.getEntry(rewriter.unprefix(internalClassName) + ".class");
- if (entry == null) {
- return null;
+ String filename = rewriter.unprefix(internalClassName) + ".class";
+ JarFile jarFile = indexedJars.getJarFile(filename);
+
+ if (jarFile != null) {
+ return getClassReader(internalClassName, jarFile, jarFile.getEntry(filename));
}
+
+ return null;
+ }
+
+ private ClassReader getClassReader(String internalClassName, ZipFile jar, ZipEntry entry) {
try (InputStream bytecode = jar.getInputStream(entry)) {
// ClassReader doesn't take ownership and instead eagerly reads the stream's contents
return rewriter.reader(bytecode);
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java b/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
index 36d9f5587d..116b2b5769 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar.java
@@ -121,6 +121,14 @@ class Desugar {
public int minSdkVersion;
@Option(
+ name = "copy_bridges_from_classpath",
+ defaultValue = "false",
+ category = "misc",
+ help = "Copy bridges from classpath to desugared classes."
+ )
+ public boolean copyBridgesFromClasspath;
+
+ @Option(
name = "core_library",
defaultValue = "false",
category = "undocumented",
@@ -168,16 +176,22 @@ class Desugar {
CoreLibraryRewriter rewriter =
new CoreLibraryRewriter(options.coreLibrary ? "__desugar__/" : "");
+ IndexedJars appIndexedJar = new IndexedJars(ImmutableList.of(options.inputJar));
+ IndexedJars appAndClasspathIndexedJars = new IndexedJars(options.classpath, appIndexedJar);
ClassLoader loader =
- createClassLoader(
- rewriter, options.bootclasspath, options.inputJar, options.classpath, parent);
+ createClassLoader(rewriter, options.bootclasspath, appAndClasspathIndexedJars, parent);
boolean allowCallsToObjectsNonNull = options.minSdkVersion >= 19;
try (ZipFile in = new ZipFile(options.inputJar.toFile());
ZipOutputStream out =
new ZipOutputStream(
new BufferedOutputStream(Files.newOutputStream(options.outputJar)))) {
LambdaClassMaker lambdas = new LambdaClassMaker(dumpDirectory);
- ClassReaderFactory readerFactory = new ClassReaderFactory(in, rewriter);
+ ClassReaderFactory readerFactory =
+ new ClassReaderFactory(
+ (options.copyBridgesFromClasspath && !allowDefaultMethods)
+ ? appAndClasspathIndexedJars
+ : appIndexedJar,
+ rewriter);
ImmutableSet.Builder<String> interfaceLambdaMethodCollector = ImmutableSet.builder();
@@ -288,21 +302,19 @@ class Desugar {
private static ClassLoader createClassLoader(
CoreLibraryRewriter rewriter,
List<Path> bootclasspath,
- Path inputJar,
- List<Path> classpath,
+ IndexedJars appAndClasspathIndexedJars,
ClassLoader parent)
throws IOException {
- // Prepend classpath with input jar itself so LambdaDesugaring can load classes with lambdas.
- // Note that inputJar and classpath need to be in the same classloader because we typically get
- // the header Jar for inputJar on the classpath and having the header Jar in a parent loader
- // means the header version is preferred over the real thing.
- classpath = ImmutableList.<Path>builder().add(inputJar).addAll(classpath).build();
// Use a classloader that as much as possible uses the provided bootclasspath instead of
// the tool's system classloader. Unfortunately we can't do that for java. classes.
if (!bootclasspath.isEmpty()) {
- parent = HeaderClassLoader.fromClassPath(bootclasspath, rewriter, parent);
+ parent = new HeaderClassLoader(new IndexedJars(bootclasspath), rewriter, parent);
}
- return HeaderClassLoader.fromClassPath(classpath, rewriter, parent);
+ // Prepend classpath with input jar itself so LambdaDesugaring can load classes with lambdas.
+ // Note that inputJar and classpath need to be in the same classloader because we typically get
+ // the header Jar for inputJar on the classpath and having the header Jar in a parent loader
+ // means the header version is preferred over the real thing.
+ return new HeaderClassLoader(appAndClasspathIndexedJars, rewriter, parent);
}
private static class ThrowingClassLoader extends ClassLoader {
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/HeaderClassLoader.java b/src/tools/android/java/com/google/devtools/build/android/desugar/HeaderClassLoader.java
index 053d52d4b2..44c39325c1 100644
--- a/src/tools/android/java/com/google/devtools/build/android/desugar/HeaderClassLoader.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/HeaderClassLoader.java
@@ -16,12 +16,6 @@ package com.google.devtools.build.android.desugar;
import java.io.IOError;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.file.Path;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import org.objectweb.asm.ClassReader;
@@ -41,44 +35,20 @@ import org.objectweb.asm.Opcodes;
*/
class HeaderClassLoader extends ClassLoader {
- private final Map<String, JarFile> jarfiles;
+ private final IndexedJars indexedJars;
private final CoreLibraryRewriter rewriter;
- /** Creates a classloader from the given classpath with the given parent. */
- public static HeaderClassLoader fromClassPath(
- List<Path> classpath, CoreLibraryRewriter rewriter, ClassLoader parent) throws IOException {
- return new HeaderClassLoader(indexJars(classpath), rewriter, parent);
- }
-
- /**
- * Opens the given list of Jar files and returns an index of all classes in them, to avoid
- * scanning all Jars over and over for each class in {@link #findClass}.
- */
- private static Map<String, JarFile> indexJars(List<Path> classpath) throws IOException {
- HashMap<String, JarFile> result = new HashMap<>();
- for (Path jarfile : classpath) {
- JarFile jar = new JarFile(jarfile.toFile());
- for (Enumeration<JarEntry> cur = jar.entries(); cur.hasMoreElements(); ) {
- JarEntry entry = cur.nextElement();
- if (entry.getName().endsWith(".class") && !result.containsKey(entry.getName())) {
- result.put(entry.getName(), jar);
- }
- }
- }
- return result;
- }
-
- private HeaderClassLoader(
- Map<String, JarFile> jarfiles, CoreLibraryRewriter rewriter, ClassLoader parent) {
+ public HeaderClassLoader(
+ IndexedJars indexedJars, CoreLibraryRewriter rewriter, ClassLoader parent) {
super(parent);
this.rewriter = rewriter;
- this.jarfiles = jarfiles;
+ this.indexedJars = indexedJars;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String filename = rewriter.unprefix(name.replace('.', '/') + ".class");
- JarFile jarfile = jarfiles.get(filename);
+ JarFile jarfile = indexedJars.getJarFile(filename);
if (jarfile == null) {
throw new ClassNotFoundException();
}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/IndexedJars.java b/src/tools/android/java/com/google/devtools/build/android/desugar/IndexedJars.java
new file mode 100644
index 0000000000..bdb5b47844
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/IndexedJars.java
@@ -0,0 +1,84 @@
+// 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.
+package com.google.devtools.build.android.desugar;
+
+import com.google.common.base.Preconditions;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import javax.annotation.Nullable;
+
+/**
+ * Opens the given list of Jar files and compute an index of all classes in them, to avoid
+ * scanning all Jars over and over for each class to load. An indexed jars can have a parent
+ * that is firstly used when a file name is searched.
+ */
+class IndexedJars {
+
+ private final Map<String, JarFile> jarfiles = new HashMap<>();
+
+ /**
+ * Parent indexed jars to use before to search a file name into this indexed jars.
+ */
+ @Nullable
+ private final IndexedJars parentIndexedJar;
+
+ /**
+ * Index a list of Jar files without a parent indexed jars.
+ */
+ public IndexedJars(List<Path> jarFiles) throws IOException {
+ this(jarFiles, null);
+ }
+
+ /**
+ * Index a list of Jar files and set a parent indexed jars that is firstly used during the search
+ * of a file name.
+ */
+ public IndexedJars(List<Path> jarFiles, @Nullable IndexedJars parentIndexedJar)
+ throws IOException {
+ this.parentIndexedJar = parentIndexedJar;
+ for (Path jarfile : jarFiles) {
+ indexJar(jarfile);
+ }
+ }
+
+ @Nullable
+ public JarFile getJarFile(String filename) {
+ Preconditions.checkArgument(filename.endsWith(".class"));
+
+ if (parentIndexedJar != null) {
+ JarFile jarFile = parentIndexedJar.getJarFile(filename);
+ if (jarFile != null) {
+ return jarFile;
+ }
+ }
+
+ return jarfiles.get(filename);
+ }
+
+ private void indexJar(Path jarfile) throws IOException {
+ JarFile jar = new JarFile(jarfile.toFile());
+ for (Enumeration<JarEntry> cur = jar.entries(); cur.hasMoreElements(); ) {
+ JarEntry entry = cur.nextElement();
+ if (entry.getName().endsWith(".class") && !jarfiles.containsKey(entry.getName())) {
+ jarfiles.put(entry.getName(), jar);
+ }
+ }
+ }
+}