Auto integrate unknown commit for java.desugar_jdk_libs

TOOL=annealing
PiperOrigin-RevId: 285879012
diff --git a/src/test/java/com/google/devtools/build/android/desugar/nest/functional/ComplexCasesTest.java b/src/test/java/com/google/devtools/build/android/desugar/nest/functional/ComplexCasesTest.java
index a2ed553..133eb59 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/nest/functional/ComplexCasesTest.java
+++ b/src/test/java/com/google/devtools/build/android/desugar/nest/functional/ComplexCasesTest.java
@@ -19,8 +19,8 @@
 import com.google.common.flags.Flag;
 import com.google.common.flags.FlagSpec;
 import com.google.common.flags.Flags;
-import com.google.devtools.build.android.desugar.DesugarRule;
-import com.google.devtools.build.android.desugar.DesugarRule.LoadClass;
+import com.google.devtools.build.android.desugar.testing.junit.DesugarRule;
+import com.google.devtools.build.android.desugar.testing.junit.LoadClass;
 import com.google.testing.junit.junit4.api.TestArgs;
 import com.google.testing.testsize.MediumTest;
 import com.google.testing.testsize.MediumTestAttribute;
diff --git a/src/test/java/com/google/devtools/build/android/desugar/nest/functional/ConstructorInNestTest.java b/src/test/java/com/google/devtools/build/android/desugar/nest/functional/ConstructorInNestTest.java
index 687634b..826abca 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/nest/functional/ConstructorInNestTest.java
+++ b/src/test/java/com/google/devtools/build/android/desugar/nest/functional/ConstructorInNestTest.java
@@ -19,8 +19,8 @@
 import com.google.common.flags.Flag;
 import com.google.common.flags.FlagSpec;
 import com.google.common.flags.Flags;
-import com.google.devtools.build.android.desugar.DesugarRule;
-import com.google.devtools.build.android.desugar.DesugarRule.LoadClass;
+import com.google.devtools.build.android.desugar.testing.junit.DesugarRule;
+import com.google.devtools.build.android.desugar.testing.junit.LoadClass;
 import com.google.testing.junit.junit4.api.TestArgs;
 import com.google.testing.testsize.MediumTest;
 import com.google.testing.testsize.MediumTestAttribute;
diff --git a/src/test/java/com/google/devtools/build/android/desugar/nest/functional/FieldBridgeTest.java b/src/test/java/com/google/devtools/build/android/desugar/nest/functional/FieldBridgeTest.java
index 931132a..7fdda97 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/nest/functional/FieldBridgeTest.java
+++ b/src/test/java/com/google/devtools/build/android/desugar/nest/functional/FieldBridgeTest.java
@@ -18,8 +18,8 @@
 import com.google.common.flags.Flag;
 import com.google.common.flags.FlagSpec;
 import com.google.common.flags.Flags;
-import com.google.devtools.build.android.desugar.DesugarRule;
-import com.google.devtools.build.android.desugar.DesugarRule.LoadClass;
+import com.google.devtools.build.android.desugar.testing.junit.DesugarRule;
+import com.google.devtools.build.android.desugar.testing.junit.LoadClass;
 import com.google.testing.junit.junit4.api.TestArgs;
 import com.google.testing.testsize.MediumTest;
 import com.google.testing.testsize.MediumTestAttribute;
diff --git a/src/test/java/com/google/devtools/build/android/desugar/nest/functional/InterfaceBridgeTest.java b/src/test/java/com/google/devtools/build/android/desugar/nest/functional/InterfaceBridgeTest.java
index c5dee3d..77567ec 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/nest/functional/InterfaceBridgeTest.java
+++ b/src/test/java/com/google/devtools/build/android/desugar/nest/functional/InterfaceBridgeTest.java
@@ -20,8 +20,8 @@
 import com.google.common.flags.Flag;
 import com.google.common.flags.FlagSpec;
 import com.google.common.flags.Flags;
-import com.google.devtools.build.android.desugar.DesugarRule;
-import com.google.devtools.build.android.desugar.DesugarRule.LoadClass;
+import com.google.devtools.build.android.desugar.testing.junit.DesugarRule;
+import com.google.devtools.build.android.desugar.testing.junit.LoadClass;
 import com.google.testing.junit.junit4.api.TestArgs;
 import com.google.testing.testsize.MediumTest;
 import com.google.testing.testsize.MediumTestAttribute;
diff --git a/src/test/java/com/google/devtools/build/android/desugar/nest/functional/MethodInNestTest.java b/src/test/java/com/google/devtools/build/android/desugar/nest/functional/MethodInNestTest.java
index 1b0f5242..6452e7d 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/nest/functional/MethodInNestTest.java
+++ b/src/test/java/com/google/devtools/build/android/desugar/nest/functional/MethodInNestTest.java
@@ -19,8 +19,8 @@
 import com.google.common.flags.Flag;
 import com.google.common.flags.FlagSpec;
 import com.google.common.flags.Flags;
-import com.google.devtools.build.android.desugar.DesugarRule;
-import com.google.devtools.build.android.desugar.DesugarRule.LoadClass;
+import com.google.devtools.build.android.desugar.testing.junit.DesugarRule;
+import com.google.devtools.build.android.desugar.testing.junit.LoadClass;
 import com.google.testing.junit.junit4.api.TestArgs;
 import com.google.testing.testsize.MediumTest;
 import com.google.testing.testsize.MediumTestAttribute;
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarRuleTest.java b/src/test/java/com/google/devtools/build/android/desugar/testing/junit/DesugarRuleTest.java
similarity index 77%
rename from src/test/java/com/google/devtools/build/android/desugar/DesugarRuleTest.java
rename to src/test/java/com/google/devtools/build/android/desugar/testing/junit/DesugarRuleTest.java
index 974315d..4e9ba09 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/DesugarRuleTest.java
+++ b/src/test/java/com/google/devtools/build/android/desugar/testing/junit/DesugarRuleTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.devtools.build.android.desugar;
+package com.google.devtools.build.android.desugar.testing.junit;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth8.assertThat;
@@ -23,9 +23,6 @@
 import com.google.common.flags.Flag;
 import com.google.common.flags.FlagSpec;
 import com.google.common.flags.Flags;
-import com.google.devtools.build.android.desugar.DesugarRule.LoadAsmNode;
-import com.google.devtools.build.android.desugar.DesugarRule.LoadClass;
-import com.google.devtools.build.android.desugar.DesugarRule.LoadZipEntry;
 import com.google.testing.junit.junit4.api.TestArgs;
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Method;
@@ -56,47 +53,50 @@
           .build();
 
   @LoadClass(
-      "com.google.devtools.build.android.desugar.DesugarRuleTestTarget$InterfaceSubjectToDesugar")
+      "com.google.devtools.build.android.desugar.testing.junit.DesugarRuleTestTarget$InterfaceSubjectToDesugar")
   private Class<?> interfaceSubjectToDesugarClassRound1;
 
   @LoadClass(
       value =
-          "com.google.devtools.build.android.desugar.DesugarRuleTestTarget$InterfaceSubjectToDesugar",
+          "com.google.devtools.build.android.desugar.testing.junit.DesugarRuleTestTarget$InterfaceSubjectToDesugar",
       round = 2)
   private Class<?> interfaceSubjectToDesugarClassRound2;
 
   @LoadClass(
-      "com.google.devtools.build.android.desugar.DesugarRuleTestTarget$InterfaceSubjectToDesugar$$CC")
+      "com.google.devtools.build.android.desugar.testing.junit.DesugarRuleTestTarget$InterfaceSubjectToDesugar$$CC")
   private Class<?> interfaceSubjectToDesugarCompanionClassRound1;
 
   @LoadClass(
       value =
-          "com.google.devtools.build.android.desugar.DesugarRuleTestTarget$InterfaceSubjectToDesugar$$CC",
+          "com.google.devtools.build.android.desugar.testing.junit.DesugarRuleTestTarget$InterfaceSubjectToDesugar$$CC",
       round = 2)
   private Class<?> interfaceSubjectToDesugarCompanionClassRound2;
 
   @LoadZipEntry(
       value =
-          "com/google/devtools/build/android/desugar/DesugarRuleTestTarget$InterfaceSubjectToDesugar$$CC.class",
+          "com/google/devtools/build/android/desugar/testing/junit/DesugarRuleTestTarget$InterfaceSubjectToDesugar$$CC.class",
       round = 1)
   private ZipEntry interfaceSubjectToDesugarZipEntryRound1;
 
   @LoadZipEntry(
       value =
-          "com/google/devtools/build/android/desugar/DesugarRuleTestTarget$InterfaceSubjectToDesugar$$CC.class",
+          "com/google/devtools/build/android/desugar/testing/junit/DesugarRuleTestTarget$InterfaceSubjectToDesugar$$CC.class",
       round = 2)
   private ZipEntry interfaceSubjectToDesugarZipEntryRound2;
 
-  @LoadAsmNode(className = "com.google.devtools.build.android.desugar.DesugarRuleTestTarget")
+  @LoadAsmNode(
+      className = "com.google.devtools.build.android.desugar.testing.junit.DesugarRuleTestTarget")
   private ClassNode desugarRuleTestTargetClassNode;
 
   @LoadAsmNode(
-      className = "com.google.devtools.build.android.desugar.DesugarRuleTestTarget$Alpha",
+      className =
+          "com.google.devtools.build.android.desugar.testing.junit.DesugarRuleTestTarget$Alpha",
       memberName = "twoIntSum")
   private MethodNode twoIntSum;
 
   @LoadAsmNode(
-      className = "com.google.devtools.build.android.desugar.DesugarRuleTestTarget$Alpha",
+      className =
+          "com.google.devtools.build.android.desugar.testing.junit.DesugarRuleTestTarget$Alpha",
       memberName = "multiplier",
       memberDescriptor = "J")
   private FieldNode multiplier;
@@ -132,7 +132,7 @@
   public void nestMembers() {
     assertThat(desugarRuleTestTargetClassNode.nestMembers)
         .contains(
-            "com/google/devtools/build/android/desugar/DesugarRuleTestTarget$InterfaceSubjectToDesugar");
+            "com/google/devtools/build/android/desugar/testing/junit/DesugarRuleTestTarget$InterfaceSubjectToDesugar");
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarRuleTestTarget.java b/src/test/java/com/google/devtools/build/android/desugar/testing/junit/DesugarRuleTestTarget.java
similarity index 95%
rename from src/test/java/com/google/devtools/build/android/desugar/DesugarRuleTestTarget.java
rename to src/test/java/com/google/devtools/build/android/desugar/testing/junit/DesugarRuleTestTarget.java
index b46c786..d6f8adf 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/DesugarRuleTestTarget.java
+++ b/src/test/java/com/google/devtools/build/android/desugar/testing/junit/DesugarRuleTestTarget.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.google.devtools.build.android.desugar;
+package com.google.devtools.build.android.desugar.testing.junit;
 
 /**
  * The source class used as data in {@link DesugarRuleTest}.
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 5fd4c9d..4da98a8 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
@@ -77,7 +77,7 @@
  * Command-line tool to desugar Java 8 constructs that dx doesn't know what to do with, in
  * particular lambdas and method references.
  */
-class Desugar {
+public class Desugar {
 
   /** Commandline options for {@link Desugar}. */
   public static class DesugarOptions extends OptionsBase {
diff --git a/src/test/java/com/google/devtools/build/android/desugar/DesugarRule.java b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/DesugarRule.java
similarity index 77%
rename from src/test/java/com/google/devtools/build/android/desugar/DesugarRule.java
rename to src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/DesugarRule.java
index b74963d9..069cee3 100644
--- a/src/test/java/com/google/devtools/build/android/desugar/DesugarRule.java
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/DesugarRule.java
@@ -14,29 +14,22 @@
  * limitations under the License.
  */
 
-package com.google.devtools.build.android.desugar;
+package com.google.devtools.build.android.desugar.testing.junit;
 
 import static com.google.common.base.Preconditions.checkState;
 
-import com.google.auto.value.AutoValue;
-import com.google.auto.value.extension.memoized.Memoized;
-import com.google.common.annotations.UsedReflectively;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableListMultimap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.LinkedHashMultimap;
 import com.google.common.collect.Multimap;
+import com.google.devtools.build.android.desugar.Desugar;
 import com.google.devtools.build.runtime.RunfilesPaths;
 import com.google.errorprone.annotations.FormatMethod;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.annotation.Annotation;
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodHandles.Lookup;
@@ -73,125 +66,7 @@
 /** A JUnit4 Rule that desugars an input jar file and load the transformed jar to JVM. */
 public class DesugarRule implements TestRule {
 
-  /**
-   * Identifies injectable class-literal fields with the specified class to load at runtime and
-   * assign to the field. An injectable class-literal field may have any access modifier (private,
-   * package-private, protected, public). Sample usage:
-   *
-   * <pre><code>
-   * &#064;RunWith(JUnit4.class)
-   * public class DesugarRuleTest {
-   *
-   *   &#064;Rule
-   *   public final DesugarRule desugarRule =
-   *       DesugarRule.builder(this, MethodHandles.lookup())
-   *           .addRuntimeInputs("path/to/my_jar.jar")
-   *           .build();
-   *
-   *   &#064;LoadClass("my.package.ClassToDesugar")
-   *   private Class<?> classToDesugarClass;
-   *
-   *   // ... Test methods ...
-   * }
-   * </code></pre>
-   */
-  @UsedReflectively
-  @Documented
-  @Target(ElementType.FIELD)
-  @Retention(RetentionPolicy.RUNTIME)
-  public @interface LoadClass {
-
-    /**
-     * The fully-qualified class name of the class to load. The format agrees with {@link
-     * Class#getName}.
-     */
-    String value();
-
-    /** The round during which its associated jar is being used. */
-    int round() default 1;
-  }
-
-  /**
-   * Identifies injectable {@link ZipEntry} fields with a zip entry path. The desugar rule resolves
-   * the requested zip entry at runtime and assign it to the annotated field. An injectable {@link
-   * ZipEntry} field may have any access modifier (private, package-private, protected, public).
-   * Sample usage:
-   *
-   * <pre><code>
-   * &#064;RunWith(JUnit4.class)
-   * public class DesugarRuleTest {
-   *
-   *   &#064;Rule
-   *   public final DesugarRule desugarRule =
-   *       DesugarRule.builder(this, MethodHandles.lookup())
-   *           .addRuntimeInputs("path/to/my_jar.jar")
-   *           .build();
-   *
-   *   &#064;LoadZipEntry("my/package/ClassToDesugar.class")
-   *   private ZipEntry classToDesugarClassFile;
-   *
-   *   // ... Test methods ...
-   * }
-   * </code></pre>
-   */
-  @UsedReflectively
-  @Documented
-  @Target(ElementType.FIELD)
-  @Retention(RetentionPolicy.RUNTIME)
-  public @interface LoadZipEntry {
-
-    /** The requested zip entry path name within a zip file. */
-    String value();
-
-    /** The round during which its associated jar is being used. */
-    int round() default 1;
-  }
-
-  /**
-   * Identifies injectable ASM node fields (e.g. {@link org.objectweb.asm.tree.ClassNode}, {@link
-   * org.objectweb.asm.tree.MethodNode}, {@link org.objectweb.asm.tree.FieldNode}) with a qualified
-   * class name. The desugar rule resolves the requested class at runtime, parse it into a {@link
-   * ClassNode} and assign parsed class node to the annotated field. An injectable ASM node field
-   * may have any access modifier (private, package-private, protected, public). Sample usage:
-   *
-   * <pre><code>
-   * &#064;RunWith(JUnit4.class)
-   * public class DesugarRuleTest {
-   *
-   *   &#064;Rule
-   *   public final DesugarRule desugarRule =
-   *       DesugarRule.builder(this, MethodHandles.lookup())
-   *           .addRuntimeInputs("path/to/my_jar.jar")
-   *           .build();
-   *
-   *   &#064;LoadAsmNode("my.package.ClassToDesugar")
-   *   private ClassNode classToDesugarClassFile;
-   *
-   *   // ... Test methods ...
-   * }
-   * </code></pre>
-   */
-  @UsedReflectively
-  @Documented
-  @Target(ElementType.FIELD)
-  @Retention(RetentionPolicy.RUNTIME)
-  public @interface LoadAsmNode {
-
-    /**
-     * The fully-qualified class name of the class to load. The format agrees with {@link
-     * Class#getName}.
-     */
-    String className();
-
-    /** If non-empty, load the specified class member (field or method) from the enclosing class. */
-    String memberName() default "";
-
-    /** If non-empty, use the specified member descriptor to disambiguate overloaded methods. */
-    String memberDescriptor() default "";
-
-    /** The round during which its associated jar is being used. */
-    int round() default 1;
-  }
+  static final ClassLoader BASE_CLASS_LOADER = ClassLoader.getSystemClassLoader().getParent();
 
   private static final Path ANDROID_RUNTIME_JAR_PATH =
       RunfilesPaths.resolve(
@@ -202,67 +77,6 @@
 
   private static final String DEFAULT_OUTPUT_ROOT_PREFIX = "desugared_dump";
 
-  private static final ClassLoader BASE_CLASS_LOADER =
-      ClassLoader.getSystemClassLoader().getParent();
-
-  /** The transformation record that describes the desugaring of a jar. */
-  @AutoValue
-  abstract static class JarTransformationRecord {
-
-    /**
-     * The full runtime path of a pre-transformationRecord jar.
-     *
-     * @see Desugar.DesugarOptions#inputJars for details.
-     */
-    abstract ImmutableList<Path> inputJars();
-
-    /**
-     * The full runtime path of a post-transformationRecord jar (deguared jar).
-     *
-     * @see Desugar.DesugarOptions#inputJars for details.
-     */
-    abstract ImmutableList<Path> outputJars();
-
-    /** @see Desugar.DesugarOptions#classpath for details. */
-    abstract ImmutableList<Path> classPathEntries();
-
-    /** @see Desugar.DesugarOptions#bootclasspath for details. */
-    abstract ImmutableList<Path> bootClassPathEntries();
-
-    /** The remaining command options used for desugaring. */
-    abstract ImmutableListMultimap<String, String> extraCustomCommandOptions();
-
-    /** The factory method of this jar transformation record. */
-    static JarTransformationRecord create(
-        ImmutableList<Path> inputJars,
-        ImmutableList<Path> outputJars,
-        ImmutableList<Path> classPathEntries,
-        ImmutableList<Path> bootClassPathEntries,
-        ImmutableListMultimap<String, String> extraCustomCommandOptions) {
-      return new AutoValue_DesugarRule_JarTransformationRecord(
-          inputJars, outputJars, classPathEntries, bootClassPathEntries, extraCustomCommandOptions);
-    }
-
-    final ImmutableList<String> getDesugarFlags() {
-      ImmutableList.Builder<String> args = ImmutableList.builder();
-      inputJars().forEach(path -> args.add("--input=" + path));
-      outputJars().forEach(path -> args.add("--output=" + path));
-      classPathEntries().forEach(path -> args.add("--classpath_entry=" + path));
-      bootClassPathEntries().forEach(path -> args.add("--bootclasspath_entry=" + path));
-      extraCustomCommandOptions().forEach((k, v) -> args.add("--" + k + "=" + v));
-      return args.build();
-    }
-
-    @Memoized
-    ClassLoader getOutputClassLoader() throws MalformedURLException {
-      List<URL> urls = new ArrayList<>();
-      for (Path path : Iterables.concat(outputJars(), classPathEntries(), bootClassPathEntries())) {
-        urls.add(path.toUri().toURL());
-      }
-      return URLClassLoader.newInstance(urls.toArray(new URL[0]), BASE_CLASS_LOADER);
-    }
-  }
-
   /** For hosting desugared jar temporarily. */
   private final TemporaryFolder temporaryFolder = new TemporaryFolder();
 
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/JarTransformationRecord.java b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/JarTransformationRecord.java
new file mode 100644
index 0000000..bdb0c72
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/JarTransformationRecord.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2019 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.testing.junit;
+
+import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.android.desugar.Desugar.DesugarOptions;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+/** The transformation record that describes the desugaring of a jar. */
+@AutoValue
+abstract class JarTransformationRecord {
+
+  /**
+   * The full runtime path of a pre-transformationRecord jar.
+   *
+   * @see DesugarOptions#inputJars for details.
+   */
+  abstract ImmutableList<Path> inputJars();
+
+  /**
+   * The full runtime path of a post-transformationRecord jar (deguared jar).
+   *
+   * @see DesugarOptions#inputJars for details.
+   */
+  abstract ImmutableList<Path> outputJars();
+
+  /** @see DesugarOptions#classpath for details. */
+  abstract ImmutableList<Path> classPathEntries();
+
+  /** @see DesugarOptions#bootclasspath for details. */
+  abstract ImmutableList<Path> bootClassPathEntries();
+
+  /** The remaining command options used for desugaring. */
+  abstract ImmutableListMultimap<String, String> extraCustomCommandOptions();
+
+  /** The factory method of this jar transformation record. */
+  static JarTransformationRecord create(
+      ImmutableList<Path> inputJars,
+      ImmutableList<Path> outputJars,
+      ImmutableList<Path> classPathEntries,
+      ImmutableList<Path> bootClassPathEntries,
+      ImmutableListMultimap<String, String> extraCustomCommandOptions) {
+    return new AutoValue_JarTransformationRecord(
+        inputJars, outputJars, classPathEntries, bootClassPathEntries, extraCustomCommandOptions);
+  }
+
+  final ImmutableList<String> getDesugarFlags() {
+    ImmutableList.Builder<String> args = ImmutableList.builder();
+    inputJars().forEach(path -> args.add("--input=" + path));
+    outputJars().forEach(path -> args.add("--output=" + path));
+    classPathEntries().forEach(path -> args.add("--classpath_entry=" + path));
+    bootClassPathEntries().forEach(path -> args.add("--bootclasspath_entry=" + path));
+    extraCustomCommandOptions().forEach((k, v) -> args.add("--" + k + "=" + v));
+    return args.build();
+  }
+
+  @Memoized
+  ClassLoader getOutputClassLoader() throws MalformedURLException {
+    List<URL> urls = new ArrayList<>();
+    for (Path path : Iterables.concat(outputJars(), classPathEntries(), bootClassPathEntries())) {
+      urls.add(path.toUri().toURL());
+    }
+    return URLClassLoader.newInstance(urls.toArray(new URL[0]), DesugarRule.BASE_CLASS_LOADER);
+  }
+}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/LoadAsmNode.java b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/LoadAsmNode.java
new file mode 100644
index 0000000..7fc4bba
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/LoadAsmNode.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2019 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.testing.junit;
+
+import com.google.common.annotations.UsedReflectively;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.objectweb.asm.tree.ClassNode;
+
+/**
+ * Identifies injectable ASM node fields (e.g. {@link org.objectweb.asm.tree.ClassNode}, {@link
+ * org.objectweb.asm.tree.MethodNode}, {@link org.objectweb.asm.tree.FieldNode}) with a qualified
+ * class name. The desugar rule resolves the requested class at runtime, parse it into a {@link
+ * ClassNode} and assign parsed class node to the annotated field. An injectable ASM node field may
+ * have any access modifier (private, package-private, protected, public). Sample usage:
+ *
+ * <pre><code>
+ * &#064;RunWith(JUnit4.class)
+ * public class DesugarRuleTest {
+ *
+ *   &#064;Rule
+ *   public final DesugarRule desugarRule =
+ *       DesugarRule.builder(this, MethodHandles.lookup())
+ *           .addRuntimeInputs("path/to/my_jar.jar")
+ *           .build();
+ *
+ *   &#064;LoadAsmNode("my.package.ClassToDesugar")
+ *   private ClassNode classToDesugarClassFile;
+ *
+ *   // ... Test methods ...
+ * }
+ * </code></pre>
+ */
+@UsedReflectively
+@Documented
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface LoadAsmNode {
+
+  /**
+   * The fully-qualified class name of the class to load. The format agrees with {@link
+   * Class#getName}.
+   */
+  String className();
+
+  /** If non-empty, load the specified class member (field or method) from the enclosing class. */
+  String memberName() default "";
+
+  /** If non-empty, use the specified member descriptor to disambiguate overloaded methods. */
+  String memberDescriptor() default "";
+
+  /** The round during which its associated jar is being used. */
+  int round() default 1;
+}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/LoadClass.java b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/LoadClass.java
new file mode 100644
index 0000000..975761d
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/LoadClass.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 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.testing.junit;
+
+import com.google.common.annotations.UsedReflectively;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Identifies injectable class-literal fields with the specified class to load at runtime and assign
+ * to the field. An injectable class-literal field may have any access modifier (private,
+ * package-private, protected, public). Sample usage:
+ *
+ * <pre><code>
+ * &#064;RunWith(JUnit4.class)
+ * public class DesugarRuleTest {
+ *
+ *   &#064;Rule
+ *   public final DesugarRule desugarRule =
+ *       DesugarRule.builder(this, MethodHandles.lookup())
+ *           .addRuntimeInputs("path/to/my_jar.jar")
+ *           .build();
+ *
+ *   &#064;LoadClass("my.package.ClassToDesugar")
+ *   private Class<?> classToDesugarClass;
+ *
+ *   // ... Test methods ...
+ * }
+ * </code></pre>
+ */
+@UsedReflectively
+@Documented
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface LoadClass {
+
+  /**
+   * The fully-qualified class name of the class to load. The format agrees with {@link
+   * Class#getName}.
+   */
+  String value();
+
+  /** The round during which its associated jar is being used. */
+  int round() default 1;
+}
diff --git a/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/LoadZipEntry.java b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/LoadZipEntry.java
new file mode 100644
index 0000000..265c337
--- /dev/null
+++ b/src/tools/android/java/com/google/devtools/build/android/desugar/testing/junit/LoadZipEntry.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 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.testing.junit;
+
+import com.google.common.annotations.UsedReflectively;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.zip.ZipEntry;
+
+/**
+ * Identifies injectable {@link ZipEntry} fields with a zip entry path. The desugar rule resolves
+ * the requested zip entry at runtime and assign it to the annotated field. An injectable {@link
+ * ZipEntry} field may have any access modifier (private, package-private, protected, public).
+ * Sample usage:
+ *
+ * <pre><code>
+ * &#064;RunWith(JUnit4.class)
+ * public class DesugarRuleTest {
+ *
+ *   &#064;Rule
+ *   public final DesugarRule desugarRule =
+ *       DesugarRule.builder(this, MethodHandles.lookup())
+ *           .addRuntimeInputs("path/to/my_jar.jar")
+ *           .build();
+ *
+ *   &#064;LoadZipEntry("my/package/ClassToDesugar.class")
+ *   private ZipEntry classToDesugarClassFile;
+ *
+ *   // ... Test methods ...
+ * }
+ * </code></pre>
+ */
+@UsedReflectively
+@Documented
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface LoadZipEntry {
+
+  /** The requested zip entry path name within a zip file. */
+  String value();
+
+  /** The round during which its associated jar is being used. */
+  int round() default 1;
+}