refactor the testbench mocks so they are  more composeable (#148)

* refactor the testbench mocks so they are  more composeable. 

* Add sources and output jar normalization tests

diff --git a/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin b/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin
index 4c3dc5a..91f2964 100644
--- a/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin
+++ b/kotlin/internal/repositories/BUILD.com_github_jetbrains_kotlin
@@ -12,7 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 package(default_visibility = ["//visibility:public"])
-load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_import", "kt_js_import")
+
+load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_js_import", "kt_jvm_import")
 
 # Kotlin home filegroup containing everything that is needed.
 filegroup(
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/BUILD b/src/test/kotlin/io/bazel/kotlin/builder/BUILD
index ad1523f..0ce32ad 100644
--- a/src/test/kotlin/io/bazel/kotlin/builder/BUILD
+++ b/src/test/kotlin/io/bazel/kotlin/builder/BUILD
@@ -21,6 +21,7 @@
     "//third_party/jvm/com/google/truth",
     "//third_party/jvm/junit",
     "@io_bazel_rules_kotlin_com_google_guava_guava//jar",
+    "//third_party/jvm/com/google/code/findbugs:jsr305",
 ]
 
 java_library(
@@ -28,9 +29,10 @@
     testonly = 1,
     srcs = [
         "Deps.java",
-        "KotlinBuilderJsTestTask.java",
-        "KotlinBuilderJvmTestTask.java",
-        "KotlinBuilderResource.java",
+        "DirectoryType.java",
+        "KotlinAbstractTestBuilder.java",
+        "KotlinJsTestBuilder.java",
+        "KotlinJvmTestBuilder.java",
     ],
     data = [
         "//src/main/kotlin:compiler_lib",
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/Deps.java b/src/test/kotlin/io/bazel/kotlin/builder/Deps.java
index 8a94799..1793879 100644
--- a/src/test/kotlin/io/bazel/kotlin/builder/Deps.java
+++ b/src/test/kotlin/io/bazel/kotlin/builder/Deps.java
@@ -16,9 +16,12 @@
 package io.bazel.kotlin.builder;
 
 import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableSet;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 import io.bazel.kotlin.builder.utils.BazelRunFiles;
 
+import javax.annotation.Nullable;
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Stream;
@@ -31,22 +34,33 @@
 
     public abstract String moduleName();
 
-    public abstract Set<String> runtimeDeps();
+    public abstract List<String> runtimeDeps();
 
-    public abstract Set<String> compileJars();
+    public abstract List<String> compileJars();
+
+    @Nullable
+    public abstract String sourceJar();
+
+    @Nullable
+    public abstract String jdeps();
 
     public static Builder builder() {
-      return new AutoValue_Deps_Dep.Builder().runtimeDeps(ImmutableSet.of());
+      return new AutoValue_Deps_Dep.Builder().runtimeDeps(ImmutableList.of());
+    }
+
+    public final String singleCompileJar() {
+      Preconditions.checkState(compileJars().size() == 1);
+      return compileJars().get(0);
     }
 
     @SuppressWarnings("UnusedReturnValue")
     @AutoValue.Builder
     public abstract static class Builder {
-      public abstract Builder compileJars(Set<String> compileJars);
+      public abstract Builder compileJars(List<String> compileJars);
 
       public abstract Builder label(String label);
 
-      public abstract Builder runtimeDeps(Set<String> runtimeDeps);
+      public abstract Builder runtimeDeps(List<String> runtimeDeps);
 
       public abstract Builder moduleName(String moduleName);
 
@@ -56,6 +70,10 @@
 
       abstract Dep autoBuild();
 
+      public abstract Builder sourceJar(String sourceJar);
+
+      public abstract Builder jdeps(String jdeps);
+
       public Dep build() {
         if (!moduleName().isPresent()) {
           moduleName(label());
@@ -73,7 +91,8 @@
     public static Dep importJar(String label, String compileJar) {
       return Dep.builder()
           .label(label)
-          .compileJars(ImmutableSet.of(BazelRunFiles.resolveVerified(compileJar).getAbsolutePath()))
+          .compileJars(
+              ImmutableList.of(BazelRunFiles.resolveVerified(compileJar).getAbsolutePath()))
           .build();
     }
   }
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/DirectoryType.java b/src/test/kotlin/io/bazel/kotlin/builder/DirectoryType.java
new file mode 100644
index 0000000..10e19ce
--- /dev/null
+++ b/src/test/kotlin/io/bazel/kotlin/builder/DirectoryType.java
@@ -0,0 +1,38 @@
+package io.bazel.kotlin.builder;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.EnumSet;
+
+public enum DirectoryType {
+  SOURCES("sources", Paths.get("sources")),
+  CLASSES("compiled classes", Paths.get("classes")),
+  GENERATED_CLASSES("generated classes", Paths.get("generated_classes")),
+  TEMP("temp directory", Paths.get("temp")),
+  SOURCE_GEN("generated sources directory", Paths.get("generated_sources"));
+
+  final String name;
+  final Path relativePath;
+
+  DirectoryType(String name, Path relativePath) {
+    this.name = name;
+    this.relativePath = relativePath;
+  }
+
+  Path resolve(Path root) {
+    return root.resolve(relativePath);
+  }
+
+  static void createAll(Path root, EnumSet<DirectoryType> types) {
+    for (DirectoryType instanceType : types) {
+      try {
+        Files.createDirectory(instanceType.resolve(root));
+      } catch (IOException e) {
+        throw new UncheckedIOException(instanceType.name, e);
+      }
+    }
+  }
+}
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderResource.java b/src/test/kotlin/io/bazel/kotlin/builder/KotlinAbstractTestBuilder.java
similarity index 73%
rename from src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderResource.java
rename to src/test/kotlin/io/bazel/kotlin/builder/KotlinAbstractTestBuilder.java
index 272d377..bcf18ab 100644
--- a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderResource.java
+++ b/src/test/kotlin/io/bazel/kotlin/builder/KotlinAbstractTestBuilder.java
@@ -17,17 +17,16 @@
 
 import io.bazel.kotlin.builder.toolchain.CompilationStatusException;
 import io.bazel.kotlin.builder.utils.CompilationTaskContext;
-import io.bazel.kotlin.model.CompilationTaskInfo;
-import io.bazel.kotlin.model.KotlinToolchainInfo;
-import io.bazel.kotlin.model.Platform;
-import io.bazel.kotlin.model.RuleKind;
-import org.junit.rules.ExternalResource;
+import io.bazel.kotlin.model.*;
 
 import java.io.*;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiFunction;
 import java.util.function.Consumer;
@@ -37,42 +36,17 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 import static java.nio.charset.StandardCharsets.UTF_8;
 
-public abstract class KotlinBuilderResource<T> extends ExternalResource {
-  public enum DirectoryType {
-    INSTANCE_ROOT("test root", null),
-    EXTERNAL("bazel external directory", null),
-    /** The rest of the paths are instance relative. */
-    SOURCES("sources", Paths.get("sources")),
-    CLASSES("compiled classes", Paths.get("classes")),
-    GENERATED_CLASSES("generated classes", Paths.get("generated_classes")),
-    TEMP("temp directory", Paths.get("temp")),
-    SOURCE_GEN("generated sources directory", Paths.get("generated_sources"));
-
-    private static final EnumSet<DirectoryType> INSTANCE_TYPES =
-        EnumSet.of(SOURCES, CLASSES, SOURCE_GEN, GENERATED_CLASSES, TEMP);
-
-    final String name;
-    private final Path relativePath;
-
-    DirectoryType(String name, Path relativePath) {
-      this.name = name;
-      this.relativePath = relativePath;
-    }
-  }
-
-  private static final Path
-      BAZEL_TEST_DIR = Paths.get(Objects.requireNonNull(System.getenv("TEST_TMPDIR"))),
-      EXTERNAL_PATH = Paths.get("external");
+abstract class KotlinAbstractTestBuilder<T> {
+  private static final Path BAZEL_TEST_DIR =
+      Paths.get(Objects.requireNonNull(System.getenv("TEST_TMPDIR")));
 
   private static final AtomicInteger counter = new AtomicInteger(0);
-
+  private final CompilationTaskInfo.Builder infoBuilder = CompilationTaskInfo.newBuilder();
   private Path instanceRoot = null;
   private String label = null;
   private List<String> outLines = null;
 
-  KotlinBuilderResource() {}
-
-  abstract CompilationTaskInfo.Builder infoBuilder();
+  abstract void setupForNext(CompilationTaskInfo.Builder infoBuilder);
 
   abstract T buildTask();
 
@@ -89,11 +63,10 @@
     return outLines;
   }
 
-  @Override
-  protected void before() throws Throwable {
+  final void resetForNext() {
     outLines = null;
     label = "a_test_" + counter.incrementAndGet();
-    infoBuilder()
+    infoBuilder
         .setLabel("//some/bogus:" + label())
         .setModuleName("some_bogus_module")
         .setPlatform(Platform.JVM)
@@ -111,36 +84,16 @@
     } catch (IOException e) {
       throw new UncheckedIOException(e);
     }
-
-    for (DirectoryType instanceType : DirectoryType.INSTANCE_TYPES) {
-      try {
-        Files.createDirectory(instanceRoot.resolve(instanceType.relativePath));
-      } catch (IOException e) {
-        throw new RuntimeException("could not create instance directory: " + instanceType.name, e);
-      }
-    }
+    setupForNext(infoBuilder);
   }
 
   final Path directory(DirectoryType type) {
-    switch (type) {
-      case INSTANCE_ROOT:
-        return instanceRoot;
-      case EXTERNAL:
-        return KotlinBuilderResource.EXTERNAL_PATH;
-      case SOURCES:
-      case CLASSES:
-      case GENERATED_CLASSES:
-      case TEMP:
-      case SOURCE_GEN:
-        return instanceRoot.resolve(type.relativePath);
-      default:
-        throw new IllegalStateException(type.toString());
-    }
+    return type.resolve(instanceRoot);
   }
 
   @SuppressWarnings("unused")
   public final void setDebugTags(String... tags) {
-    infoBuilder().addAllDebug(Arrays.asList(tags));
+    infoBuilder.addAllDebug(Arrays.asList(tags));
   }
 
   final Path writeSourceFile(String filename, String[] lines) {
@@ -174,9 +127,8 @@
   }
 
   final <R> R runCompileTask(BiFunction<CompilationTaskContext, T, R> operation) {
-    CompilationTaskInfo info = infoBuilder().build();
     T task = buildTask();
-    return runCompileTask(info, task, (ctx, t) -> operation.apply(ctx, task));
+    return runCompileTask(infoBuilder.build(), task, (ctx, t) -> operation.apply(ctx, task));
   }
 
   /**
@@ -238,7 +190,7 @@
   }
 
   public final String toPlatform(String path) {
-    return KotlinBuilderResource.toPlatformPath(path).toString();
+    return KotlinAbstractTestBuilder.toPlatformPath(path).toString();
   }
 
   @SuppressWarnings("unused")
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJvmTestTask.java b/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJvmTestTask.java
deleted file mode 100644
index 824a742..0000000
--- a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJvmTestTask.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2018 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 io.bazel.kotlin.builder;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-import io.bazel.kotlin.builder.toolchain.KotlinToolchain;
-import io.bazel.kotlin.model.CompilationTaskInfo;
-import io.bazel.kotlin.model.JvmCompilationTask;
-
-import java.util.HashSet;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static io.bazel.kotlin.builder.Deps.*;
-
-public final class KotlinBuilderJvmTestTask extends KotlinBuilderResource<JvmCompilationTask> {
-  @SuppressWarnings({"unused", "WeakerAccess"})
-  public static Dep
-      KOTLIN_ANNOTATIONS =
-          Dep.importJar(
-              "kotlin-annotations",
-              "external/com_github_jetbrains_kotlin/lib/annotations-13.0.jar"),
-      KOTLIN_STDLIB =
-          Dep.importJar(
-              "kotlin-stdlib", "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib.jar"),
-      KOTLIN_STDLIB_JDK7 =
-          Dep.importJar(
-              "kotlin-stdlib-jdk7",
-              "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib-jdk7.jar"),
-      KOTLIN_STDLIB_JDK8 =
-          Dep.importJar(
-              "kotlin-stdlib-jdk8",
-              "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib-jdk8.jar");
-
-  private static final JvmCompilationTask.Builder taskBuilder = JvmCompilationTask.newBuilder();
-  private static final KotlinBuilderComponent component =
-      DaggerKotlinBuilderComponent.builder().toolchain(KotlinToolchain.createToolchain()).build();
-
-  @Override
-  CompilationTaskInfo.Builder infoBuilder() {
-    return taskBuilder.getInfoBuilder();
-  }
-
-  @Override
-  JvmCompilationTask buildTask() {
-    return taskBuilder.build();
-  }
-
-  @Override
-  protected final void before() throws Throwable {
-    taskBuilder.clear();
-    super.before();
-
-    taskBuilder
-        .getDirectoriesBuilder()
-        .setClasses(directory(DirectoryType.CLASSES).toAbsolutePath().toString())
-        .setGeneratedSources(directory(DirectoryType.SOURCE_GEN).toAbsolutePath().toString())
-        .setTemp(directory(DirectoryType.TEMP).toAbsolutePath().toString())
-        .setGeneratedClasses(
-            directory(DirectoryType.GENERATED_CLASSES).toAbsolutePath().toString());
-    taskBuilder
-        .getOutputsBuilder()
-        .setJar(instanceRoot().resolve("jar_file.jar").toAbsolutePath().toString())
-        .setJdeps(instanceRoot().resolve("jdeps_file.jdeps").toAbsolutePath().toString())
-        .setSrcjar(instanceRoot().resolve("jar_file-sources.jar").toAbsolutePath().toString());
-  }
-
-  private void resetForNext() {
-    try {
-      before();
-    } catch (Throwable throwable) {
-      throw new RuntimeException(throwable);
-    }
-  }
-
-  public void addSource(String filename, String... lines) {
-    String pathAsString = super.writeSourceFile(filename, lines).toString();
-    if (pathAsString.endsWith(".kt")) {
-      taskBuilder.getInputsBuilder().addKotlinSources(pathAsString);
-    } else if (pathAsString.endsWith(".java")) {
-      taskBuilder.getInputsBuilder().addJavaSources(pathAsString);
-    } else {
-      throw new RuntimeException("unhandled file type: " + pathAsString);
-    }
-  }
-
-  public void addAnnotationProcessors(AnnotationProcessor... annotationProcessors) {
-    Preconditions.checkState(
-        taskBuilder.getInputs().getProcessorsList().isEmpty(), "processors already set");
-    HashSet<String> processorClasses = new HashSet<>();
-    taskBuilder
-        .getInputsBuilder()
-        .addAllProcessorpaths(
-            Stream.of(annotationProcessors)
-                .peek(it -> processorClasses.add(it.processClass()))
-                .flatMap(it -> it.processorPath().stream())
-                .distinct()
-                .collect(Collectors.toList()))
-        .addAllProcessors(processorClasses);
-  }
-
-  public void addDirectDependencies(Dep... dependencies) {
-    Dep.classpathOf(dependencies)
-        .forEach((dependency) -> taskBuilder.getInputsBuilder().addClasspath(dependency));
-  }
-
-  private Dep currentDep() {
-    return Dep.builder()
-        .label(label())
-        .compileJars(ImmutableSet.of(taskBuilder.getOutputs().getJar()))
-        .runtimeDeps(ImmutableSet.copyOf(taskBuilder.getInputs().getClasspathList()))
-        .build();
-  }
-
-  @SafeVarargs
-  public final Dep runCompileTask(Consumer<KotlinBuilderJvmTestTask>... setup) {
-    Stream.of(setup).forEach(it -> it.accept(this));
-    return runCompileTask(
-        (taskContext, task) -> {
-          component.jvmTaskExecutor().execute(taskContext, task);
-          assertFilesExist(task.getOutputs().getJar(), task.getOutputs().getJdeps());
-          return currentDep();
-        });
-  }
-
-  /** Run a single compile task returning a dep and resetting the context. */
-  @SafeVarargs
-  public final Dep supplyDepTask(Consumer<KotlinBuilderJvmTestTask>... setup) {
-    Dep dep = runCompileTask(setup);
-    resetForNext();
-    return dep;
-  }
-}
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJsTestTask.java b/src/test/kotlin/io/bazel/kotlin/builder/KotlinJsTestBuilder.java
similarity index 72%
rename from src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJsTestTask.java
rename to src/test/kotlin/io/bazel/kotlin/builder/KotlinJsTestBuilder.java
index ff65016..c7a79ef 100644
--- a/src/test/kotlin/io/bazel/kotlin/builder/KotlinBuilderJsTestTask.java
+++ b/src/test/kotlin/io/bazel/kotlin/builder/KotlinJsTestBuilder.java
@@ -19,21 +19,19 @@
 import io.bazel.kotlin.model.CompilationTaskInfo;
 import io.bazel.kotlin.model.JsCompilationTask;
 
-import java.nio.file.Path;
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.List;
+import java.util.function.Consumer;
 
-public final class KotlinBuilderJsTestTask extends KotlinBuilderResource<JsCompilationTask> {
+public final class KotlinJsTestBuilder extends KotlinAbstractTestBuilder<JsCompilationTask> {
   private static final List<String> PASSTHROUGH_FLAGS =
       Arrays.asList("-source-map", "-meta-info", "-module-kind", "commonjs", "-target", "v5");
   private static final JsCompilationTask.Builder taskBuilder = JsCompilationTask.newBuilder();
   private static final KotlinBuilderComponent component =
       DaggerKotlinBuilderComponent.builder().toolchain(KotlinToolchain.createToolchain()).build();
-
-  @Override
-  CompilationTaskInfo.Builder infoBuilder() {
-    return taskBuilder.getInfoBuilder();
-  }
+  private static final EnumSet<DirectoryType> ALL_DIRECTORY_TYPES =
+      EnumSet.of(DirectoryType.SOURCES);
 
   @Override
   JsCompilationTask buildTask() {
@@ -41,10 +39,9 @@
   }
 
   @Override
-  protected final void before() throws Throwable {
-    taskBuilder.clear();
-    super.before();
-
+  void setupForNext(CompilationTaskInfo.Builder infoBuilder) {
+    taskBuilder.clear().setInfo(infoBuilder);
+    DirectoryType.createAll(instanceRoot(), ALL_DIRECTORY_TYPES);
     taskBuilder.addAllPassThroughFlags(PASSTHROUGH_FLAGS);
     taskBuilder
         .getOutputsBuilder()
@@ -53,12 +50,17 @@
         .setJs(instanceRoot().resolve(label() + ".js").toAbsolutePath().toString());
   }
 
-  public void addSource(String filename, String... lines) {
-    Path sourcePath = super.writeSourceFile(filename, lines);
-    taskBuilder.getInputsBuilder().addKotlinSources(sourcePath.toString());
+  public final class TaskBuilder {
+    public void addSource(String filename, String... lines) {
+      taskBuilder.getInputsBuilder().addKotlinSources(writeSourceFile(filename, lines).toString());
+    }
   }
 
-  public void runCompilationTask() {
+  private final TaskBuilder taskBuilderInstance = new TaskBuilder();
+
+  public void runCompilationTask(Consumer<TaskBuilder> setup) {
+    resetForNext();
+    setup.accept(taskBuilderInstance);
     runCompileTask(
         (taskContext, task) -> {
           component.jsTaskExecutor().execute(taskContext, task);
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/KotlinJvmTestBuilder.java b/src/test/kotlin/io/bazel/kotlin/builder/KotlinJvmTestBuilder.java
new file mode 100644
index 0000000..56c38a7
--- /dev/null
+++ b/src/test/kotlin/io/bazel/kotlin/builder/KotlinJvmTestBuilder.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2018 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 io.bazel.kotlin.builder;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import io.bazel.kotlin.builder.Deps.AnnotationProcessor;
+import io.bazel.kotlin.builder.Deps.Dep;
+import io.bazel.kotlin.builder.toolchain.KotlinToolchain;
+import io.bazel.kotlin.model.CompilationTaskInfo;
+import io.bazel.kotlin.model.JvmCompilationTask;
+
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public final class KotlinJvmTestBuilder extends KotlinAbstractTestBuilder<JvmCompilationTask> {
+  @SuppressWarnings({"unused", "WeakerAccess"})
+  public static Dep
+      KOTLIN_ANNOTATIONS =
+          Dep.importJar(
+              "kotlin-annotations",
+              "external/com_github_jetbrains_kotlin/lib/annotations-13.0.jar"),
+      KOTLIN_STDLIB =
+          Dep.importJar(
+              "kotlin-stdlib", "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib.jar"),
+      KOTLIN_STDLIB_JDK7 =
+          Dep.importJar(
+              "kotlin-stdlib-jdk7",
+              "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib-jdk7.jar"),
+      KOTLIN_STDLIB_JDK8 =
+          Dep.importJar(
+              "kotlin-stdlib-jdk8",
+              "external/com_github_jetbrains_kotlin/lib/kotlin-stdlib-jdk8.jar");
+
+  private static final JvmCompilationTask.Builder taskBuilder = JvmCompilationTask.newBuilder();
+  private static final KotlinBuilderComponent component =
+      DaggerKotlinBuilderComponent.builder().toolchain(KotlinToolchain.createToolchain()).build();
+
+  private static final EnumSet<DirectoryType> ALL_DIRECTORY_TYPES =
+      EnumSet.of(
+          DirectoryType.SOURCES,
+          DirectoryType.CLASSES,
+          DirectoryType.SOURCE_GEN,
+          DirectoryType.GENERATED_CLASSES,
+          DirectoryType.TEMP);
+
+  @Override
+  void setupForNext(CompilationTaskInfo.Builder taskInfo) {
+    taskBuilder.clear().setInfo(taskInfo);
+
+    DirectoryType.createAll(instanceRoot(), ALL_DIRECTORY_TYPES);
+
+    taskBuilder
+        .getDirectoriesBuilder()
+        .setClasses(directory(DirectoryType.CLASSES).toAbsolutePath().toString())
+        .setGeneratedSources(directory(DirectoryType.SOURCE_GEN).toAbsolutePath().toString())
+        .setTemp(directory(DirectoryType.TEMP).toAbsolutePath().toString())
+        .setGeneratedClasses(
+            directory(DirectoryType.GENERATED_CLASSES).toAbsolutePath().toString());
+
+    taskBuilder
+        .getOutputsBuilder()
+        .setJar(instanceRoot().resolve("jar_file.jar").toAbsolutePath().toString())
+        .setJdeps(instanceRoot().resolve("jdeps_file.jdeps").toAbsolutePath().toString())
+        .setSrcjar(instanceRoot().resolve("jar_file-sources.jar").toAbsolutePath().toString());
+  }
+
+  @Override
+  JvmCompilationTask buildTask() {
+    return taskBuilder.build();
+  }
+
+  public class TaskBuilder {
+    TaskBuilder() {}
+
+    public void setLabel(String label) {
+      taskBuilder.getInfoBuilder().setLabel(label);
+    }
+
+    public void addSource(String filename, String... lines) {
+      String pathAsString = writeSourceFile(filename, lines).toString();
+      if (pathAsString.endsWith(".kt")) {
+        taskBuilder.getInputsBuilder().addKotlinSources(pathAsString);
+      } else if (pathAsString.endsWith(".java")) {
+        taskBuilder.getInputsBuilder().addJavaSources(pathAsString);
+      } else {
+        throw new RuntimeException("unhandled file type: " + pathAsString);
+      }
+    }
+
+    public void addAnnotationProcessors(AnnotationProcessor... annotationProcessors) {
+      Preconditions.checkState(
+          taskBuilder.getInputs().getProcessorsList().isEmpty(), "processors already set");
+      HashSet<String> processorClasses = new HashSet<>();
+      taskBuilder
+          .getInputsBuilder()
+          .addAllProcessorpaths(
+              Stream.of(annotationProcessors)
+                  .peek(it -> processorClasses.add(it.processClass()))
+                  .flatMap(it -> it.processorPath().stream())
+                  .distinct()
+                  .collect(Collectors.toList()))
+          .addAllProcessors(processorClasses);
+    }
+
+    public void addDirectDependencies(Dep... dependencies) {
+      Dep.classpathOf(dependencies)
+          .forEach((dependency) -> taskBuilder.getInputsBuilder().addClasspath(dependency));
+    }
+  }
+
+  private TaskBuilder taskBuilderInstance = new TaskBuilder();
+
+  @SafeVarargs
+  public final Dep runCompileTask(Consumer<TaskBuilder>... setup) {
+    resetForNext();
+    Stream.of(setup).forEach(it -> it.accept(taskBuilderInstance));
+    return runCompileTask(
+        (taskContext, task) -> {
+          component.jvmTaskExecutor().execute(taskContext, task);
+          assertFilesExist(task.getOutputs().getJar(), task.getOutputs().getJdeps());
+          return Dep.builder()
+              .label(taskBuilder.getInfo().getLabel())
+              .compileJars(ImmutableList.of(taskBuilder.getOutputs().getJar()))
+              .runtimeDeps(ImmutableList.copyOf(taskBuilder.getInputs().getClasspathList()))
+              .sourceJar(taskBuilder.getOutputs().getSrcjar())
+              .build();
+        });
+  }
+}
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/tasks/js/KotlinBuilderJsTest.java b/src/test/kotlin/io/bazel/kotlin/builder/tasks/js/KotlinBuilderJsTest.java
index 41c2ef6..c7e1109 100644
--- a/src/test/kotlin/io/bazel/kotlin/builder/tasks/js/KotlinBuilderJsTest.java
+++ b/src/test/kotlin/io/bazel/kotlin/builder/tasks/js/KotlinBuilderJsTest.java
@@ -1,6 +1,6 @@
 package io.bazel.kotlin.builder.tasks.js;
 
-import io.bazel.kotlin.builder.KotlinBuilderJsTestTask;
+import io.bazel.kotlin.builder.KotlinJsTestBuilder;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -10,19 +10,20 @@
 
 @RunWith(JUnit4.class)
 public class KotlinBuilderJsTest {
-  @Rule public KotlinBuilderJsTestTask ctx = new KotlinBuilderJsTestTask();
+  private static final KotlinJsTestBuilder builder = new KotlinJsTestBuilder();
 
   @Test
   public void testSimpleJsCompile() {
-    ctx.addSource("AClass.kt", "package something", "class AClass{}");
-    ctx.runCompilationTask();
+    builder.runCompilationTask(
+        it -> it.addSource("AClass.kt", "package something", "class AClass{}"));
   }
 
   @Test
   public void testJsErrorRendering() {
-    ctx.addSource("AClass.kt", "package something", "class AClass{");
-    ctx.runFailingCompileTaskAndValidateOutput(
-        ctx::runCompilationTask,
-        lines -> assertThat(lines.get(0)).startsWith(ctx.toPlatform("sources/AClass.kt")));
+    builder.runFailingCompileTaskAndValidateOutput(
+        () ->
+            builder.runCompilationTask(
+                it -> it.addSource("AClass.kt", "package something", "class AClass{")),
+        lines -> assertThat(lines.get(0)).startsWith(builder.toPlatform("sources/AClass.kt")));
   }
 }
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmBasicTest.java b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmBasicTest.java
index ffe49ce..75ebc75 100644
--- a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmBasicTest.java
+++ b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmBasicTest.java
@@ -15,67 +15,81 @@
  */
 package io.bazel.kotlin.builder.tasks.jvm;
 
-import io.bazel.kotlin.builder.KotlinBuilderJvmTestTask;
-import io.bazel.kotlin.builder.KotlinBuilderResource.DirectoryType;
+import io.bazel.kotlin.builder.Deps;
+import io.bazel.kotlin.builder.DirectoryType;
+import io.bazel.kotlin.builder.KotlinJvmTestBuilder;
 import org.junit.Ignore;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.function.Consumer;
+
 import static com.google.common.truth.Truth.assertThat;
 
 @RunWith(JUnit4.class)
 public class KotlinBuilderJvmBasicTest {
-  @Rule public KotlinBuilderJvmTestTask ctx = new KotlinBuilderJvmTestTask();
+  private static final KotlinJvmTestBuilder ctx = new KotlinJvmTestBuilder();
 
   @Test
   public void testSimpleMixedModeCompile() {
-    ctx.addSource("AClass.kt", "package something;" + "class AClass{}");
-    ctx.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{}");
-    ctx.runCompileTask();
+    ctx.runCompileTask(
+        c -> {
+          c.addSource("AClass.kt", "package something;" + "class AClass{}");
+          c.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{}");
+        });
     ctx.assertFilesExist(
         DirectoryType.CLASSES, "something/AClass.class", "something/AnotherClass.class");
   }
 
   @Test
   public void testMixedBiReferences() {
-    ctx.addSource(
-        "AClass.java",
-        "package a;",
-        "",
-        "import b.BClass;",
-        "",
-        "public class AClass {",
-        "  static BClass b = new BClass();",
-        "}");
-    ctx.addSource(
-        "BClass.kt",
-        "package b",
-        "",
-        "import a.AClass",
-        "",
-        "class BClass() {",
-        "  val a = AClass()",
-        "}");
-    ctx.runCompileTask();
+    ctx.runCompileTask(
+        it -> {
+          it.addSource(
+              "AClass.java",
+              "package a;",
+              "",
+              "import b.BClass;",
+              "",
+              "public class AClass {",
+              "  static BClass b = new BClass();",
+              "}");
+          it.addSource(
+              "BClass.kt",
+              "package b",
+              "",
+              "import a.AClass",
+              "",
+              "class BClass() {",
+              "  val a = AClass()",
+              "}");
+        });
     ctx.assertFilesExist(DirectoryType.CLASSES, "a/AClass.class", "b/BClass.class");
   }
 
   @Test
   public void testKotlinErrorRendering() {
-    ctx.addSource("AClass.kt", "package something;" + "class AClass{");
     ctx.runFailingCompileTaskAndValidateOutput(
-        ctx::runCompileTask,
+        () ->
+            ctx.runCompileTask(
+                c -> c.addSource("AClass.kt", "package something;" + "class AClass{")),
         lines -> assertThat(lines.get(0)).startsWith(ctx.toPlatform("sources/AClass")));
   }
 
   @Test
   public void testJavaErrorRendering() {
-    ctx.addSource("AClass.kt", "package something;" + "class AClass{}");
-    ctx.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{");
     ctx.runFailingCompileTaskAndValidateOutput(
-        ctx::runCompileTask,
+        () ->
+            ctx.runCompileTask(
+                c -> {
+                  c.addSource("AClass.kt", "package something;" + "class AClass{}");
+                  c.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{");
+                }),
         lines -> assertThat(lines.get(0)).startsWith(ctx.toPlatform("sources/AnotherClass")));
   }
 
@@ -85,4 +99,42 @@
     ctx.runCompileTask(
         (c) -> c.addSource("AnotherClass.java", "package something;", "", "class AnotherClass{}"));
   }
+
+  private static final Consumer<KotlinJvmTestBuilder.TaskBuilder> SETUP_NORMALIZATION_TEST_SOURCES =
+      ctx -> {
+        ctx.addSource("AClass.kt", "package something;\n" + "class AClass{}");
+        ctx.addSource("BClass.kt", "package something;\n" + "class BClass{}");
+      };
+
+  @Test
+  public void testCompiledJarIsNormalized() {
+    Deps.Dep previous = ctx.runCompileTask(SETUP_NORMALIZATION_TEST_SOURCES);
+    Deps.Dep recompiled =
+        ctx.runCompileTask(ctx -> ctx.setLabel(previous.label()), SETUP_NORMALIZATION_TEST_SOURCES);
+    assertThat(previous.label()).isEqualTo(recompiled.label());
+    assertThat(hashDep(previous.singleCompileJar()))
+        .isEqualTo(hashDep(recompiled.singleCompileJar()));
+    assertThat(previous.sourceJar()).isNotEmpty();
+    assertThat(hashDep(previous.sourceJar())).isEqualTo(hashDep(recompiled.sourceJar()));
+  }
+
+  @Test
+  public void testSourceJarIsNormalized() {
+    Deps.Dep previous = ctx.runCompileTask(SETUP_NORMALIZATION_TEST_SOURCES);
+    Deps.Dep recompiled =
+        ctx.runCompileTask(ctx -> ctx.setLabel(previous.label()), SETUP_NORMALIZATION_TEST_SOURCES);
+    assertThat(previous.sourceJar()).isNotEmpty();
+    assertThat(hashDep(previous.sourceJar())).isEqualTo(hashDep(recompiled.sourceJar()));
+  }
+
+  private static String hashDep(String path) {
+    try {
+      //noinspection UnstableApiUsage
+      return com.google.common.hash.Hashing.sha256()
+          .hashBytes(Files.readAllBytes(Paths.get(path)))
+          .toString();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
 }
diff --git a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmKaptTest.java b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmKaptTest.java
index 553d560..456501f 100644
--- a/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmKaptTest.java
+++ b/src/test/kotlin/io/bazel/kotlin/builder/tasks/jvm/KotlinBuilderJvmKaptTest.java
@@ -17,9 +17,8 @@
 
 import io.bazel.kotlin.builder.Deps.AnnotationProcessor;
 import io.bazel.kotlin.builder.Deps.Dep;
-import io.bazel.kotlin.builder.KotlinBuilderJvmTestTask;
-import io.bazel.kotlin.builder.KotlinBuilderResource;
-import org.junit.Rule;
+import io.bazel.kotlin.builder.DirectoryType;
+import io.bazel.kotlin.builder.KotlinJvmTestBuilder;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -27,8 +26,8 @@
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
-import static io.bazel.kotlin.builder.KotlinBuilderJvmTestTask.KOTLIN_ANNOTATIONS;
-import static io.bazel.kotlin.builder.KotlinBuilderJvmTestTask.KOTLIN_STDLIB;
+import static io.bazel.kotlin.builder.KotlinJvmTestBuilder.KOTLIN_ANNOTATIONS;
+import static io.bazel.kotlin.builder.KotlinJvmTestBuilder.KOTLIN_STDLIB;
 
 @RunWith(JUnit4.class)
 public class KotlinBuilderJvmKaptTest {
@@ -44,9 +43,9 @@
               Dep.classpathOf(AUTO_VALUE, KOTLIN_ANNOTATIONS).collect(Collectors.toSet()))
           .build();
 
-  @Rule public KotlinBuilderJvmTestTask ctx = new KotlinBuilderJvmTestTask();
+  private static final KotlinJvmTestBuilder ctx = new KotlinJvmTestBuilder();
 
-  private static final Consumer<KotlinBuilderJvmTestTask> ADD_AUTO_VALUE_PLUGIN =
+  private static final Consumer<KotlinJvmTestBuilder.TaskBuilder> ADD_AUTO_VALUE_PLUGIN =
       (c) -> {
         c.addAnnotationProcessors(AUTO_VALUE_ANNOTATION_PROCESSOR);
         c.addDirectDependencies(AUTO_VALUE, KOTLIN_STDLIB);
@@ -76,19 +75,18 @@
                     + "}"));
 
     ctx.assertFilesExist(
-        KotlinBuilderResource.DirectoryType.CLASSES,
+        DirectoryType.CLASSES,
         "autovalue/TestKtValue.class",
         "autovalue/AutoValue_TestKtValue.class");
-    ctx.assertFilesExist(
-        KotlinBuilderResource.DirectoryType.SOURCE_GEN, "autovalue/AutoValue_TestKtValue.java");
+    ctx.assertFilesExist(DirectoryType.SOURCE_GEN, "autovalue/AutoValue_TestKtValue.java");
   }
 
   @Test
   public void testMixedKaptBiReferences() {
     ctx.runCompileTask(
         ADD_AUTO_VALUE_PLUGIN,
-        ctx -> {
-          ctx.addSource(
+        it -> {
+          it.addSource(
               "TestKtValue.kt",
               "package autovalue.a\n"
                   + "\n"
@@ -107,7 +105,7 @@
                   + "    }\n"
                   + "}");
 
-          ctx.addSource(
+          it.addSource(
               "TestAutoValue.java",
               "package autovalue.b;\n"
                   + "\n"
@@ -132,11 +130,11 @@
                   + "}");
         });
     ctx.assertFilesExist(
-        KotlinBuilderResource.DirectoryType.SOURCE_GEN,
+        DirectoryType.SOURCE_GEN,
         "autovalue/a/AutoValue_TestKtValue.java",
         "autovalue/b/AutoValue_TestAutoValue.java");
     ctx.assertFilesExist(
-        KotlinBuilderResource.DirectoryType.CLASSES,
+        DirectoryType.CLASSES,
         "autovalue/a/AutoValue_TestKtValue.class",
         "autovalue/b/AutoValue_TestAutoValue.class");
   }
diff --git a/third_party/dependencies.yaml b/third_party/dependencies.yaml
index c5bca82..9eaa370 100644
--- a/third_party/dependencies.yaml
+++ b/third_party/dependencies.yaml
@@ -11,6 +11,10 @@
   namePrefix: "io_bazel_rules_kotlin_"
 
 dependencies:
+  com.google.code.findbugs:
+    jsr305:
+      lang: "java"
+      version: "3.0.2"
   junit:
     junit:
       lang: "java"
diff --git a/third_party/jvm/com/google/code/findbugs/BUILD b/third_party/jvm/com/google/code/findbugs/BUILD
index 8cd1a41..ab817e9 100644
--- a/third_party/jvm/com/google/code/findbugs/BUILD
+++ b/third_party/jvm/com/google/code/findbugs/BUILD
@@ -5,7 +5,7 @@
         "//external:jar/io_bazel_rules_kotlin_com/google/code/findbugs/jsr305"
     ],
     visibility = [
-        "//third_party/jvm:__subpackages__"
+        "//visibility:public"
     ]
 )
 
diff --git a/third_party/jvm/workspace.bzl b/third_party/jvm/workspace.bzl
index fc0c2a1..905cbf8 100644
--- a/third_party/jvm/workspace.bzl
+++ b/third_party/jvm/workspace.bzl
@@ -69,7 +69,7 @@
     {"artifact": "com.google.auto.service:auto-service:1.0-rc4", "lang": "java", "sha1": "44954d465f3b9065388bbd2fc08a3eb8fd07917c", "sha256": "e422d49c312fd2031222e7306e8108c1b4118eb9c049f1b51eca280bed87e924", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/service/auto-service/1.0-rc4/auto-service-1.0-rc4.jar", "source": {"sha1": "4e0285a57f33a9139e203687a617d7c98104b73a", "sha256": "285a6d4bc111255b5c99f5393b833f8b9156c4acb4e6c3f7cdde8493e888dd27", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/service/auto-service/1.0-rc4/auto-service-1.0-rc4-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_auto_service_auto_service", "actual": "@io_bazel_rules_kotlin_com_google_auto_service_auto_service//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/auto/service/auto_service"},
     {"artifact": "com.google.auto.value:auto-value:1.5.3", "lang": "java", "sha1": "514df6a7c7938de35c7f68dc8b8f22df86037f38", "sha256": "238d3b7535096d782d08576d1e42f79480713ff0794f511ff2cc147363ec072d", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/value/auto-value/1.5.3/auto-value-1.5.3.jar", "source": {"sha1": "1bb4def82e18be0b6a58ab089fba288d712db6cb", "sha256": "7c9adb9f49a4f07e226778951e087da85759a9ab53ac375f9d076de6dc84ca2b", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/value/auto-value/1.5.3/auto-value-1.5.3-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_auto_value_auto_value", "actual": "@io_bazel_rules_kotlin_com_google_auto_value_auto_value//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/auto/value/auto_value"},
     {"artifact": "com.google.auto:auto-common:0.8", "lang": "java", "sha1": "c6f7af0e57b9d69d81b05434ef9f3c5610d498c4", "sha256": "97db1709f57b91b32edacb596ef4641872f227b7d99ad90e467f0d77f5ba134a", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/auto-common/0.8/auto-common-0.8.jar", "source": {"sha1": "24705cafc9997c5eb6ae3270bd6234fdf9912bad", "sha256": "1e258bc08963dc8ffdcf22efa04b9fea6886761e077fc126ebacf92d11c9abec", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/auto/auto-common/0.8/auto-common-0.8-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_auto_auto_common", "actual": "@io_bazel_rules_kotlin_com_google_auto_auto_common//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/auto/auto_common"},
-    {"artifact": "com.google.code.findbugs:jsr305:1.3.9", "lang": "java", "sha1": "40719ea6961c0cb6afaeb6a921eaa1f6afd4cfdf", "sha256": "905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar", "name": "io_bazel_rules_kotlin_com_google_code_findbugs_jsr305", "actual": "@io_bazel_rules_kotlin_com_google_code_findbugs_jsr305//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/code/findbugs/jsr305"},
+    {"artifact": "com.google.code.findbugs:jsr305:3.0.2", "lang": "java", "sha1": "25ea2e8b0c338a877313bd4672d3fe056ea78f0d", "sha256": "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar", "source": {"sha1": "b19b5927c2c25b6c70f093767041e641ae0b1b35", "sha256": "1c9e85e272d0708c6a591dc74828c71603053b48cc75ae83cce56912a2aa063b", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_code_findbugs_jsr305", "actual": "@io_bazel_rules_kotlin_com_google_code_findbugs_jsr305//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/code/findbugs/jsr305"},
     {"artifact": "com.google.code.gson:gson:2.7", "lang": "java", "sha1": "751f548c85fa49f330cecbb1875893f971b33c4e", "sha256": "2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.7/gson-2.7.jar", "source": {"sha1": "bbb63ca253b483da8ee53a50374593923e3de2e2", "sha256": "2d3220d5d936f0a26258aa3b358160741a4557e046a001251e5799c2db0f0d74", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.7/gson-2.7-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_code_gson_gson", "actual": "@io_bazel_rules_kotlin_com_google_code_gson_gson//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/code/gson/gson"},
     {"artifact": "com.google.dagger:dagger-compiler:2.16", "lang": "java", "sha1": "203235b0c6875c39a0b5053dfc2f043acab04acf", "sha256": "723dca807605ddc82cd86c4e334493789ad7fb3fe863b264a8853611c89baf3d", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/dagger/dagger-compiler/2.16/dagger-compiler-2.16.jar", "source": {"sha1": "7ceeb0333370b3f0c28f4b23b1db72d8aae5efa3", "sha256": "05dbe0867bd1efce9a446359d30a0ad2bfe0407b1afd2b31a3058944d2bf3a7d", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/dagger/dagger-compiler/2.16/dagger-compiler-2.16-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_dagger_dagger_compiler", "actual": "@io_bazel_rules_kotlin_com_google_dagger_dagger_compiler//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/dagger/dagger_compiler"},
     {"artifact": "com.google.dagger:dagger-producers:2.16", "lang": "java", "sha1": "4e084a99b71a31e7079603c9675cb4994aff1344", "sha256": "97737907bde6e94cfa90883fa2a8ff4765400b9561bdcb4d83fe475ddbaf22af", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/dagger/dagger-producers/2.16/dagger-producers-2.16.jar", "source": {"sha1": "b477b4eebb171e718c7c9c4e4968913e50cf8e52", "sha256": "93838ce482666e54ed7a10d97558db99fce7c761392db44c259805e66664f384", "repository": "https://repo.maven.apache.org/maven2/", "url": "https://repo.maven.apache.org/maven2/com/google/dagger/dagger-producers/2.16/dagger-producers-2.16-sources.jar"} , "name": "io_bazel_rules_kotlin_com_google_dagger_dagger_producers", "actual": "@io_bazel_rules_kotlin_com_google_dagger_dagger_producers//jar", "bind": "jar/io_bazel_rules_kotlin_com/google/dagger/dagger_producers"},