Deprecate --experimental_java_header_compilation_disable_javac_fallback

unconditionally disable javac fallback for non-API-generating annotation
processors, and remove support for two-tiered spawns from header
compilation actions.

PiperOrigin-RevId: 210728118
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 07d8281..52a2d8f 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -1044,7 +1044,7 @@
         "rules/java/JavaConfiguration.java",
         "rules/java/JavaExportsProvider.java",
         "rules/java/JavaGenJarsProvider.java",
-        "rules/java/JavaHeaderCompileAction.java",
+        "rules/java/JavaHeaderCompileActionBuilder.java",
         "rules/java/JavaHelper.java",
         "rules/java/JavaInfo.java",
         "rules/java/JavaInfoBuildHelper.java",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
index e934049..11ba92c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
@@ -396,8 +396,7 @@
                 runtimeJar.getRoot());
 
     JavaTargetAttributes attributes = getAttributes();
-    JavaHeaderCompileAction.Builder builder =
-        new JavaHeaderCompileAction.Builder(getRuleContext());
+    JavaHeaderCompileActionBuilder builder = new JavaHeaderCompileActionBuilder(getRuleContext());
     builder.setSourceFiles(attributes.getSourceFiles());
     builder.addSourceJars(attributes.getSourceJars());
     builder.setClasspathEntries(attributes.getCompileTimeClassPath());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
index 97cb739..b774719 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
@@ -150,7 +150,6 @@
   private final Label javaLauncherLabel;
   private final boolean useIjars;
   private final boolean useHeaderCompilation;
-  private final boolean headerCompilationDisableJavacFallback;
   private final boolean generateJavaDeps;
   private final boolean strictDepsJavaProtos;
   private final boolean protoGeneratedStrictDeps;
@@ -188,7 +187,6 @@
     this.javaLauncherLabel = javaOptions.javaLauncher;
     this.useIjars = javaOptions.useIjars;
     this.useHeaderCompilation = javaOptions.headerCompilation;
-    this.headerCompilationDisableJavacFallback = javaOptions.headerCompilationDisableJavacFallback;
     this.generateJavaDeps =
         javaOptions.javaDeps || javaOptions.javaClasspath != JavaClasspathMode.OFF;
     this.javaClasspath = javaOptions.javaClasspath;
@@ -244,7 +242,6 @@
       Label javaLauncherLabel,
       boolean useIjars,
       boolean useHeaderCompilation,
-      boolean headerCompilationDisableJavacFallback,
       boolean generateJavaDeps,
       boolean strictDepsJavaProtos,
       boolean protoGeneratedStrictDeps,
@@ -275,7 +272,6 @@
     this.javaLauncherLabel = javaLauncherLabel;
     this.useIjars = useIjars;
     this.useHeaderCompilation = useHeaderCompilation;
-    this.headerCompilationDisableJavacFallback = headerCompilationDisableJavacFallback;
     this.generateJavaDeps = generateJavaDeps;
     this.strictDepsJavaProtos = strictDepsJavaProtos;
     this.protoGeneratedStrictDeps = protoGeneratedStrictDeps;
@@ -337,14 +333,6 @@
   }
 
   /**
-   * If --java_header_compilation is set, report diagnostics from turbine instead of falling back to
-   * javac. Diagnostics will be produced more quickly, but may be less helpful.
-   */
-  public boolean headerCompilationDisableJavacFallback() {
-    return headerCompilationDisableJavacFallback;
-  }
-
-  /**
    * Returns true iff dependency information is generated after compilation.
    */
   public boolean getGenerateJavaDeps() {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileAction.java
deleted file mode 100644
index 6198048..0000000
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileAction.java
+++ /dev/null
@@ -1,626 +0,0 @@
-// Copyright 2016 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.lib.rules.java;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static com.google.common.base.Preconditions.checkState;
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Joiner;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.devtools.build.lib.actions.ActionExecutionContext;
-import com.google.devtools.build.lib.actions.ActionInput;
-import com.google.devtools.build.lib.actions.ActionKeyContext;
-import com.google.devtools.build.lib.actions.ActionOwner;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.BaseSpawn;
-import com.google.devtools.build.lib.actions.CommandLine;
-import com.google.devtools.build.lib.actions.CommandLineExpansionException;
-import com.google.devtools.build.lib.actions.CommandLines;
-import com.google.devtools.build.lib.actions.CommandLines.CommandLineLimits;
-import com.google.devtools.build.lib.actions.ExecException;
-import com.google.devtools.build.lib.actions.ParamFileInfo;
-import com.google.devtools.build.lib.actions.ParameterFile;
-import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
-import com.google.devtools.build.lib.actions.ResourceSet;
-import com.google.devtools.build.lib.actions.RunfilesSupplier;
-import com.google.devtools.build.lib.actions.Spawn;
-import com.google.devtools.build.lib.actions.SpawnActionContext;
-import com.google.devtools.build.lib.actions.SpawnResult;
-import com.google.devtools.build.lib.actions.UserExecException;
-import com.google.devtools.build.lib.analysis.RuleContext;
-import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
-import com.google.devtools.build.lib.analysis.actions.ParameterFileWriteAction;
-import com.google.devtools.build.lib.analysis.actions.SpawnAction;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
-import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.collect.nestedset.NestedSet;
-import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
-import com.google.devtools.build.lib.collect.nestedset.Order;
-import com.google.devtools.build.lib.rules.java.JavaPluginInfoProvider.JavaPluginInfo;
-import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
-import com.google.devtools.build.lib.util.Fingerprint;
-import com.google.devtools.build.lib.util.LazyString;
-import com.google.devtools.build.lib.vfs.PathFragment;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import javax.annotation.Nullable;
-
-/**
- * Action for Java header compilation, to be used if --java_header_compilation is enabled.
- *
- * <p>The header compiler consumes the inputs of a java compilation, and produces an interface jar
- * that can be used as a compile-time jar by upstream targets. The header interface jar is
- * equivalent to the output of ijar, but unlike ijar the header compiler operates directly on Java
- * source files instead post-processing the class outputs of the compilation. Compiling the
- * interface jar from source moves javac off the build's critical path.
- *
- * <p>The implementation of the header compiler tool can be found under {@code
- * //src/java_tools/buildjar/java/com/google/devtools/build/java/turbine}.
- */
-@AutoCodec
-public class JavaHeaderCompileAction extends SpawnAction {
-
-  private static final String GUID = "952db158-2654-4ced-87e5-4646d50523cf";
-
-  private static final ResourceSet LOCAL_RESOURCES =
-      ResourceSet.createWithRamCpuIo(/*memoryMb=*/ 750.0, /*cpuUsage=*/ 0.5, /*ioUsage=*/ 0.0);
-
-  private final Iterable<Artifact> directInputs;
-  @Nullable private final CommandLine directCommandLine;
-
-  /** The command line for a direct classpath compilation, or {@code null} if disabled. */
-  @VisibleForTesting
-  @Nullable
-  public CommandLine directCommandLine() {
-    return directCommandLine;
-  }
-
-  /**
-   * Constructs an action to compile a set of Java source files to a header interface jar.
-   *
-   * @param owner the action owner, typically a java_* RuleConfiguredTarget
-   * @param tools the set of files comprising the tool that creates the header interface jar
-   * @param directInputs the set of direct input artifacts of the compile action
-   * @param inputs the set of transitive input artifacts of the compile action
-   * @param outputs the outputs of the action
-   * @param primaryOutput the output jar
-   * @param commandLines the transitive command line arguments for the java header compiler
-   * @param directCommandLine the direct command line arguments for the java header compiler
-   * @param commandLineLimits the command line limits
-   * @param progressMessage the message printed during the progression of the build
-   */
-  protected JavaHeaderCompileAction(
-      ActionOwner owner,
-      Iterable<Artifact> tools,
-      Iterable<Artifact> directInputs,
-      Iterable<Artifact> inputs,
-      Iterable<Artifact> outputs,
-      Artifact primaryOutput,
-      CommandLines commandLines,
-      CommandLine directCommandLine,
-      CommandLineLimits commandLineLimits,
-      CharSequence progressMessage,
-      RunfilesSupplier runfilesSupplier) {
-    super(
-        owner,
-        tools,
-        inputs,
-        outputs,
-        primaryOutput,
-        LOCAL_RESOURCES,
-        commandLines,
-        commandLineLimits,
-        false,
-        // TODO(#3320): This is missing the config's action environment.
-        JavaCompileAction.UTF8_ACTION_ENVIRONMENT,
-        /* executionInfo= */ ImmutableMap.of(),
-        progressMessage,
-        runfilesSupplier,
-        "Turbine",
-        /* executeUnconditionally= */ false,
-        /* extraActionInfoSupplier= */ null);
-    this.directInputs = checkNotNull(directInputs);
-    this.directCommandLine = checkNotNull(directCommandLine);
-  }
-
-  @Override
-  protected void computeKey(ActionKeyContext actionKeyContext, Fingerprint fp) {
-    fp.addString(GUID);
-    try {
-      super.computeKey(actionKeyContext, fp);
-      fp.addStrings(directCommandLine.arguments());
-    } catch (CommandLineExpansionException e) {
-      throw new AssertionError("JavaHeaderCompileAction command line expansion cannot fail");
-    }
-  }
-
-  @Override
-  protected List<SpawnResult> internalExecute(ActionExecutionContext actionExecutionContext)
-      throws ExecException, InterruptedException {
-    Spawn spawn = getDirectSpawn();
-    SpawnActionContext context = actionExecutionContext.getContext(SpawnActionContext.class);
-    try {
-      return context.exec(spawn, actionExecutionContext);
-    } catch (ExecException e) {
-      // if the direct input spawn failed, try again with transitive inputs to produce better
-      // better messages
-      try {
-        return context.exec(getSpawn(actionExecutionContext), actionExecutionContext);
-      } catch (CommandLineExpansionException commandLineExpansionException) {
-        throw new UserExecException(commandLineExpansionException);
-      }
-      // The compilation should never fail with direct deps but succeed with transitive inputs
-      // unless it failed due to a strict deps error, in which case fall back to the transitive
-      // classpath may allow it to succeed (Strict Java Deps errors are reported by javac,
-      // not turbine).
-    }
-  }
-
-  private final Spawn getDirectSpawn() {
-    try {
-      return new BaseSpawn(
-          ImmutableList.copyOf(directCommandLine.arguments()),
-          ImmutableMap.<String, String>of() /*environment*/,
-          ImmutableMap.<String, String>of() /*executionInfo*/,
-          this,
-          LOCAL_RESOURCES) {
-        @Override
-        public Iterable<? extends ActionInput> getInputFiles() {
-          return directInputs;
-        }
-      };
-    } catch (CommandLineExpansionException e) {
-      throw new AssertionError("JavaHeaderCompileAction command line expansion cannot fail");
-    }
-  }
-
-  /** Builder class to construct Java header compilation actions. */
-  public static class Builder {
-
-    private final RuleContext ruleContext;
-
-    private Artifact outputJar;
-    @Nullable private Artifact outputDepsProto;
-    private ImmutableSet<Artifact> sourceFiles = ImmutableSet.of();
-    private final Collection<Artifact> sourceJars = new ArrayList<>();
-    private NestedSet<Artifact> classpathEntries =
-        NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER);
-    private ImmutableList<Artifact> bootclasspathEntries = ImmutableList.<Artifact>of();
-    @Nullable private Label targetLabel;
-    @Nullable private String injectingRuleKind;
-    private PathFragment tempDirectory;
-    private BuildConfiguration.StrictDepsMode strictJavaDeps
-        = BuildConfiguration.StrictDepsMode.OFF;
-    private NestedSet<Artifact> directJars = NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER);
-    private NestedSet<Artifact> compileTimeDependencyArtifacts =
-        NestedSetBuilder.emptySet(Order.STABLE_ORDER);
-    private ImmutableList<String> javacOpts;
-    private JavaPluginInfo plugins = JavaPluginInfo.empty();
-
-    private NestedSet<Artifact> additionalInputs = NestedSetBuilder.emptySet(Order.STABLE_ORDER);
-    private Artifact javacJar;
-    private NestedSet<Artifact> toolsJars = NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER);
-
-    public Builder(RuleContext ruleContext) {
-      this.ruleContext = ruleContext;
-    }
-
-    /** Sets the output jdeps file. */
-    public Builder setOutputDepsProto(@Nullable Artifact outputDepsProto) {
-      this.outputDepsProto = outputDepsProto;
-      return this;
-    }
-
-    /** Sets the direct dependency artifacts. */
-    public Builder setDirectJars(NestedSet<Artifact> directJars) {
-      checkNotNull(directJars, "directJars must not be null");
-      this.directJars = directJars;
-      return this;
-    }
-
-    /** Sets the .jdeps artifacts for direct dependencies. */
-    public Builder setCompileTimeDependencyArtifacts(NestedSet<Artifact> dependencyArtifacts) {
-      checkNotNull(dependencyArtifacts, "dependencyArtifacts must not be null");
-      this.compileTimeDependencyArtifacts = dependencyArtifacts;
-      return this;
-    }
-
-    /** Sets Java compiler flags. */
-    public Builder setJavacOpts(ImmutableList<String> javacOpts) {
-      checkNotNull(javacOpts, "javacOpts must not be null");
-      this.javacOpts = javacOpts;
-      return this;
-    }
-
-    /** Sets the output jar. */
-    public Builder setOutputJar(Artifact outputJar) {
-      checkNotNull(outputJar, "outputJar must not be null");
-      this.outputJar = outputJar;
-      return this;
-    }
-
-    /** Adds Java source files to compile. */
-    public Builder setSourceFiles(ImmutableSet<Artifact> sourceFiles) {
-      checkNotNull(sourceFiles, "sourceFiles must not be null");
-      this.sourceFiles = sourceFiles;
-      return this;
-    }
-
-    /** Adds a jar archive of Java sources to compile. */
-    public Builder addSourceJars(Collection<Artifact> sourceJars) {
-      checkNotNull(sourceJars, "sourceJars must not be null");
-      this.sourceJars.addAll(sourceJars);
-      return this;
-    }
-
-    /** Sets the compilation classpath entries. */
-    public Builder setClasspathEntries(NestedSet<Artifact> classpathEntries) {
-      checkNotNull(classpathEntries, "classpathEntries must not be null");
-      this.classpathEntries = classpathEntries;
-      return this;
-    }
-
-    /** Sets the compilation bootclasspath entries. */
-    public Builder setBootclasspathEntries(ImmutableList<Artifact> bootclasspathEntries) {
-      checkNotNull(bootclasspathEntries, "bootclasspathEntries must not be null");
-      this.bootclasspathEntries = bootclasspathEntries;
-      return this;
-    }
-
-    /** Sets the annotation processors classpath entries. */
-    public Builder setPlugins(JavaPluginInfo plugins) {
-      checkNotNull(plugins, "plugins must not be null");
-      checkState(this.plugins.isEmpty());
-      this.plugins = plugins;
-      return this;
-    }
-
-    /** Sets the label of the target being compiled. */
-    public Builder setTargetLabel(@Nullable Label targetLabel) {
-      this.targetLabel = targetLabel;
-      return this;
-    }
-
-    /** Sets the injecting rule kind of the target being compiled. */
-    public Builder setInjectingRuleKind(@Nullable String injectingRuleKind) {
-      this.injectingRuleKind = injectingRuleKind;
-      return this;
-    }
-
-    /**
-     * Sets the path to a temporary directory, e.g. for extracting sourcejar entries to before
-     * compilation.
-     */
-    public Builder setTempDirectory(PathFragment tempDirectory) {
-      checkNotNull(tempDirectory, "tempDirectory must not be null");
-      this.tempDirectory = tempDirectory;
-      return this;
-    }
-
-    /** Sets the Strict Java Deps mode. */
-    public Builder setStrictJavaDeps(BuildConfiguration.StrictDepsMode strictJavaDeps) {
-      checkNotNull(strictJavaDeps, "strictJavaDeps must not be null");
-      this.strictJavaDeps = strictJavaDeps;
-      return this;
-    }
-
-    /** Sets the javabase inputs. */
-    public Builder setAdditionalInputs(NestedSet<Artifact> additionalInputs) {
-      checkNotNull(additionalInputs, "additionalInputs must not be null");
-      this.additionalInputs = additionalInputs;
-      return this;
-    }
-
-    /** Sets the javac jar. */
-    public Builder setJavacJar(Artifact javacJar) {
-      checkNotNull(javacJar, "javacJar must not be null");
-      this.javacJar = javacJar;
-      return this;
-    }
-
-    /** Sets the tools jars. */
-    public Builder setToolsJars(NestedSet<Artifact> toolsJars) {
-      checkNotNull(toolsJars, "toolsJars must not be null");
-      this.toolsJars = toolsJars;
-      return this;
-    }
-
-    /** Builds and registers the {@link JavaHeaderCompileAction} for a header compilation. */
-    public void build(JavaToolchainProvider javaToolchain, JavaRuntimeInfo hostJavabase) {
-      checkNotNull(outputDepsProto, "outputDepsProto must not be null");
-      checkNotNull(sourceFiles, "sourceFiles must not be null");
-      checkNotNull(sourceJars, "sourceJars must not be null");
-      checkNotNull(classpathEntries, "classpathEntries must not be null");
-      checkNotNull(bootclasspathEntries, "bootclasspathEntries must not be null");
-      checkNotNull(tempDirectory, "tempDirectory must not be null");
-      checkNotNull(strictJavaDeps, "strictJavaDeps must not be null");
-      checkNotNull(directJars, "directJars must not be null");
-      checkNotNull(
-          compileTimeDependencyArtifacts, "compileTimeDependencyArtifacts must not be null");
-      checkNotNull(javacOpts, "javacOpts must not be null");
-
-      // Invariant: if strictJavaDeps is OFF, then directJars and
-      // dependencyArtifacts are ignored
-      if (strictJavaDeps == BuildConfiguration.StrictDepsMode.OFF) {
-        directJars = NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER);
-        compileTimeDependencyArtifacts = NestedSetBuilder.emptySet(Order.STABLE_ORDER);
-      }
-
-      // The compilation uses API-generating annotation processors and has to fall back to
-      // javac-turbine.
-      boolean requiresAnnotationProcessing = !plugins.isEmpty();
-
-      NestedSet<Artifact> tools =
-          NestedSetBuilder.<Artifact>stableOrder()
-              .add(javacJar)
-              .addTransitive(javaToolchain.getHeaderCompiler().getFilesToRun())
-              .addTransitive(toolsJars)
-              .build();
-      ImmutableList<Artifact> outputs = ImmutableList.of(outputJar, outputDepsProto);
-      NestedSet<Artifact> baseInputs =
-          NestedSetBuilder.<Artifact>stableOrder()
-              .addTransitive(hostJavabase.javaBaseInputsMiddleman())
-              .addTransitive(additionalInputs)
-              .addAll(bootclasspathEntries)
-              .addAll(sourceJars)
-              .addAll(sourceFiles)
-              .addTransitive(tools)
-              .build();
-
-      boolean noFallback =
-          ruleContext.getFragment(JavaConfiguration.class).headerCompilationDisableJavacFallback();
-      // The action doesn't require annotation processing and either javac-turbine fallback is
-      // disabled, or the action doesn't distinguish between direct and transitive deps, so
-      // use a plain SpawnAction to invoke turbine.
-      if ((noFallback || directJars.isEmpty()) && !requiresAnnotationProcessing) {
-        SpawnAction.Builder builder = new SpawnAction.Builder();
-        NestedSet<Artifact> classpath;
-        final ParamFileInfo paramFileInfo;
-        if (!directJars.isEmpty() || classpathEntries.isEmpty()) {
-          classpath = directJars;
-          paramFileInfo = null;
-        } else {
-          classpath = classpathEntries;
-          // Transitive classpath actions may exceed the command line length limit.
-          paramFileInfo =
-              ParamFileInfo.builder(ParameterFileType.UNQUOTED).setUseAlways(true).build();
-        }
-        CustomCommandLine.Builder commandLine =
-            baseCommandLine(CustomCommandLine.builder(), classpath);
-        if (noFallback) {
-          commandLine.add("--nojavac_fallback");
-        }
-        Artifact headerCompiler = javaToolchain.getHeaderCompiler().getExecutable();
-        // The header compiler is either a jar file that needs to be executed using
-        // `java -jar <path>`, or an executable that can be run directly.
-        if (!headerCompiler.getExtension().equals("jar")) {
-          builder.setExecutable(headerCompiler);
-          builder.addTool(javaToolchain.getHeaderCompiler());
-        } else {
-          builder.setJarExecutable(
-              hostJavabase.javaBinaryExecPath(), headerCompiler, javaToolchain.getJvmOptions());
-        }
-        ruleContext.registerAction(
-            builder
-                .addTransitiveTools(tools)
-                .addTransitiveInputs(baseInputs)
-                .addTransitiveInputs(classpath)
-                .addOutputs(outputs)
-                .addCommandLine(commandLine.build(), paramFileInfo)
-                .setMnemonic("Turbine")
-                .setProgressMessage(getProgressMessage())
-                .build(ruleContext));
-        return;
-      }
-
-      CustomCommandLine.Builder commandLine = getBaseArgs(javaToolchain, hostJavabase);
-      CommandLine paramFileCommandLine = transitiveCommandLine();
-      NestedSetBuilder<Artifact> transitiveInputs =
-          NestedSetBuilder.<Artifact>stableOrder()
-              .addTransitive(baseInputs)
-              .addTransitive(classpathEntries)
-              .addTransitive(plugins.processorClasspath())
-              .addTransitive(plugins.data())
-              .addTransitive(compileTimeDependencyArtifacts);
-      final CommandLines commandLines;
-
-      if (ruleContext.getConfiguration().deferParamFiles()) {
-        commandLines =
-            CommandLines.builder()
-                .addCommandLine(commandLine.build())
-                .addCommandLine(
-                    paramFileCommandLine,
-                    ParamFileInfo.builder(ParameterFile.ParameterFileType.UNQUOTED)
-                        .setUseAlways(true)
-                        .setCharset(ISO_8859_1)
-                        .build())
-                .build();
-      } else {
-        PathFragment paramFilePath = ParameterFile.derivePath(outputJar.getRootRelativePath());
-        Artifact paramsFile =
-            ruleContext
-                .getAnalysisEnvironment()
-                .getDerivedArtifact(paramFilePath, outputJar.getRoot());
-        transitiveInputs.add(paramsFile);
-        commandLine.addFormatted("@%s", paramsFile.getExecPath());
-        commandLines = CommandLines.of(commandLine.build());
-        ParameterFileWriteAction parameterFileWriteAction =
-            new ParameterFileWriteAction(
-                ruleContext.getActionOwner(),
-                paramsFile,
-                paramFileCommandLine,
-                ParameterFile.ParameterFileType.UNQUOTED,
-                ISO_8859_1);
-        ruleContext.registerAction(parameterFileWriteAction);
-      }
-
-      if (requiresAnnotationProcessing) {
-        // turbine doesn't support API-generating annotation processors, so skip the two-tiered
-        // turbine/javac-turbine action and just use SpawnAction to invoke javac-turbine.
-        ruleContext.registerAction(
-            new SpawnAction(
-                ruleContext.getActionOwner(),
-                tools,
-                transitiveInputs.build(),
-                outputs,
-                outputJar,
-                LOCAL_RESOURCES,
-                commandLines,
-                ruleContext.getConfiguration().getCommandLineLimits(),
-                false,
-                // TODO(b/63280599): This is missing the config's action environment.
-                JavaCompileAction.UTF8_ACTION_ENVIRONMENT,
-                /* executionInfo= */ ImmutableMap.of(),
-                getProgressMessageWithAnnotationProcessors(),
-                javaToolchain.getHeaderCompiler().getRunfilesSupplier(),
-                "JavacTurbine",
-                /* executeUnconditionally= */ false,
-                /* extraActionInfoSupplier= */ null));
-        return;
-      }
-
-      // The action doesn't require annotation processing, javac-turbine fallback is enabled, and
-      // the target distinguishes between direct and transitive deps. Try a two-tiered spawn
-      // the invokes turbine with direct deps, and falls back to javac-turbine on failures to
-      // produce better diagnostics. (At the cost of slower failed actions and a larger
-      // cache footprint.)
-      // TODO(cushon): productionize --nojavac_fallback and remove this path
-      checkState(!directJars.isEmpty());
-      NestedSet<Artifact> directInputs =
-          NestedSetBuilder.fromNestedSet(baseInputs).addTransitive(directJars).build();
-      CustomCommandLine directCommandLine = baseCommandLine(
-          getBaseArgs(javaToolchain, hostJavabase), directJars)
-          .build();
-      ruleContext.registerAction(
-          new JavaHeaderCompileAction(
-              ruleContext.getActionOwner(),
-              tools,
-              directInputs,
-              transitiveInputs.build(),
-              outputs,
-              outputJar,
-              commandLines,
-              directCommandLine,
-              ruleContext.getConfiguration().getCommandLineLimits(),
-              getProgressMessage(),
-              javaToolchain.getHeaderCompiler().getRunfilesSupplier()));
-    }
-
-    private LazyString getProgressMessageWithAnnotationProcessors() {
-      List<String> shortNames = new ArrayList<>();
-      for (String name : plugins.processorClasses()) {
-        shortNames.add(name.substring(name.lastIndexOf('.') + 1));
-      }
-      String tail = " and running annotation processors (" + Joiner.on(", ").join(shortNames) + ")";
-      return getProgressMessage(tail);
-    }
-
-    private LazyString getProgressMessage() {
-      return getProgressMessage("");
-    }
-
-    private LazyString getProgressMessage(String tail) {
-      Artifact outputJar = this.outputJar;
-      int fileCount = sourceFiles.size() + sourceJars.size();
-      return new LazyString() {
-        @Override
-        public String toString() {
-          return String.format(
-              "Compiling Java headers %s (%d files)%s", outputJar.prettyPrint(), fileCount, tail);
-        }
-      };
-    }
-
-    private CustomCommandLine.Builder getBaseArgs(
-        JavaToolchainProvider javaToolchain, JavaRuntimeInfo hostJavabase) {
-      Artifact headerCompiler = javaToolchain.getHeaderCompiler().getExecutable();
-      if (!headerCompiler.getExtension().equals("jar")) {
-        return CustomCommandLine.builder().addExecPath(headerCompiler);
-      } else {
-        return CustomCommandLine.builder()
-            .addPath(hostJavabase.javaBinaryExecPath())
-            .add("-Xverify:none")
-            .addAll(javaToolchain.getJvmOptions())
-            .addExecPath("-jar", headerCompiler);
-      }
-    }
-
-    /**
-     * Adds the command line arguments shared by direct classpath and transitive classpath
-     * invocations.
-     */
-    private CustomCommandLine.Builder baseCommandLine(
-        CustomCommandLine.Builder result, NestedSet<Artifact> classpathEntries) {
-      result.addExecPath("--output", outputJar);
-
-      if (outputDepsProto != null) {
-        result.addExecPath("--output_deps", outputDepsProto);
-      }
-
-      result.add("--temp_dir").addPath(tempDirectory);
-
-      result.addExecPaths("--bootclasspath", bootclasspathEntries);
-
-      result.addExecPaths("--sources", sourceFiles);
-
-      if (!sourceJars.isEmpty()) {
-        result.addExecPaths("--source_jars", ImmutableList.copyOf(sourceJars));
-      }
-
-      if (!javacOpts.isEmpty()) {
-        result.addAll("--javacopts", javacOpts);
-        // terminate --javacopts with `--` to support javac flags that start with `--`
-        result.add("--");
-      }
-
-      if (targetLabel != null) {
-        result.add("--target_label");
-        if (targetLabel.getPackageIdentifier().getRepository().isDefault()
-            || targetLabel.getPackageIdentifier().getRepository().isMain()) {
-          result.addLabel(targetLabel);
-        } else {
-          // @-prefixed strings will be assumed to be params filenames and expanded,
-          // so add an extra @ to escape it.
-          result.addPrefixedLabel("@", targetLabel);
-        }
-      }
-      if (injectingRuleKind != null) {
-        result.add("--injecting_rule_kind", injectingRuleKind);
-      }
-      result.addExecPaths("--classpath", classpathEntries);
-      return result;
-    }
-
-    /** Builds a transitive classpath command line. */
-    private CommandLine transitiveCommandLine() {
-      CustomCommandLine.Builder result = CustomCommandLine.builder();
-      baseCommandLine(result, classpathEntries);
-      result.addAll("--processors", plugins.processorClasses());
-      result.addExecPaths("--processorpath", plugins.processorClasspath());
-      if (strictJavaDeps != BuildConfiguration.StrictDepsMode.OFF) {
-        result.addExecPaths("--direct_dependencies", directJars);
-        if (!compileTimeDependencyArtifacts.isEmpty()) {
-          result.addExecPaths("--deps_artifacts", compileTimeDependencyArtifacts);
-        }
-      }
-      return result.build();
-    }
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileActionBuilder.java
new file mode 100644
index 0000000..8cbe594
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileActionBuilder.java
@@ -0,0 +1,370 @@
+// Copyright 2016 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.lib.rules.java;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static java.util.stream.Collectors.joining;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.ParamFileInfo;
+import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
+import com.google.devtools.build.lib.analysis.FilesToRunProvider;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.rules.java.JavaPluginInfoProvider.JavaPluginInfo;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import com.google.devtools.build.lib.util.LazyString;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import java.util.ArrayList;
+import java.util.Collection;
+import javax.annotation.Nullable;
+
+/**
+ * Action builder for Java header compilation, to be used if --java_header_compilation is enabled.
+ *
+ * <p>The header compiler consumes the inputs of a java compilation, and produces an interface jar
+ * that can be used as a compile-time jar by upstream targets. The header interface jar is
+ * equivalent to the output of ijar, but unlike ijar the header compiler operates directly on Java
+ * source files instead post-processing the class outputs of the compilation. Compiling the
+ * interface jar from source moves javac off the build's critical path.
+ *
+ * <p>The implementation of the header compiler tool can be found under {@code
+ * //src/java_tools/buildjar/java/com/google/devtools/build/java/turbine}.
+ */
+public class JavaHeaderCompileActionBuilder {
+
+  private final RuleContext ruleContext;
+
+  private Artifact outputJar;
+  @Nullable private Artifact outputDepsProto;
+  private ImmutableSet<Artifact> sourceFiles = ImmutableSet.of();
+  private final Collection<Artifact> sourceJars = new ArrayList<>();
+  private NestedSet<Artifact> classpathEntries = NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER);
+  private ImmutableList<Artifact> bootclasspathEntries = ImmutableList.of();
+  @Nullable private Label targetLabel;
+  @Nullable private String injectingRuleKind;
+  private PathFragment tempDirectory;
+  private BuildConfiguration.StrictDepsMode strictJavaDeps = BuildConfiguration.StrictDepsMode.OFF;
+  private NestedSet<Artifact> directJars = NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER);
+  private NestedSet<Artifact> compileTimeDependencyArtifacts =
+      NestedSetBuilder.emptySet(Order.STABLE_ORDER);
+  private ImmutableList<String> javacOpts;
+  private JavaPluginInfo plugins = JavaPluginInfo.empty();
+
+  private NestedSet<Artifact> additionalInputs = NestedSetBuilder.emptySet(Order.STABLE_ORDER);
+  private Artifact javacJar;
+  private NestedSet<Artifact> toolsJars = NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER);
+
+  public JavaHeaderCompileActionBuilder(RuleContext ruleContext) {
+    this.ruleContext = ruleContext;
+  }
+
+  /** Sets the output jdeps file. */
+  public JavaHeaderCompileActionBuilder setOutputDepsProto(@Nullable Artifact outputDepsProto) {
+    this.outputDepsProto = outputDepsProto;
+    return this;
+  }
+
+  /** Sets the direct dependency artifacts. */
+  public JavaHeaderCompileActionBuilder setDirectJars(NestedSet<Artifact> directJars) {
+    checkNotNull(directJars, "directJars must not be null");
+    this.directJars = directJars;
+    return this;
+  }
+
+  /** Sets the .jdeps artifacts for direct dependencies. */
+  public JavaHeaderCompileActionBuilder setCompileTimeDependencyArtifacts(
+      NestedSet<Artifact> dependencyArtifacts) {
+    checkNotNull(dependencyArtifacts, "dependencyArtifacts must not be null");
+    this.compileTimeDependencyArtifacts = dependencyArtifacts;
+    return this;
+  }
+
+  /** Sets Java compiler flags. */
+  public JavaHeaderCompileActionBuilder setJavacOpts(ImmutableList<String> javacOpts) {
+    checkNotNull(javacOpts, "javacOpts must not be null");
+    this.javacOpts = javacOpts;
+    return this;
+  }
+
+  /** Sets the output jar. */
+  public JavaHeaderCompileActionBuilder setOutputJar(Artifact outputJar) {
+    checkNotNull(outputJar, "outputJar must not be null");
+    this.outputJar = outputJar;
+    return this;
+  }
+
+  /** Adds Java source files to compile. */
+  public JavaHeaderCompileActionBuilder setSourceFiles(ImmutableSet<Artifact> sourceFiles) {
+    checkNotNull(sourceFiles, "sourceFiles must not be null");
+    this.sourceFiles = sourceFiles;
+    return this;
+  }
+
+  /** Adds a jar archive of Java sources to compile. */
+  public JavaHeaderCompileActionBuilder addSourceJars(Collection<Artifact> sourceJars) {
+    checkNotNull(sourceJars, "sourceJars must not be null");
+    this.sourceJars.addAll(sourceJars);
+    return this;
+  }
+
+  /** Sets the compilation classpath entries. */
+  public JavaHeaderCompileActionBuilder setClasspathEntries(NestedSet<Artifact> classpathEntries) {
+    checkNotNull(classpathEntries, "classpathEntries must not be null");
+    this.classpathEntries = classpathEntries;
+    return this;
+  }
+
+  /** Sets the compilation bootclasspath entries. */
+  public JavaHeaderCompileActionBuilder setBootclasspathEntries(
+      ImmutableList<Artifact> bootclasspathEntries) {
+    checkNotNull(bootclasspathEntries, "bootclasspathEntries must not be null");
+    this.bootclasspathEntries = bootclasspathEntries;
+    return this;
+  }
+
+  /** Sets the annotation processors classpath entries. */
+  public JavaHeaderCompileActionBuilder setPlugins(JavaPluginInfo plugins) {
+    checkNotNull(plugins, "plugins must not be null");
+    checkState(this.plugins.isEmpty());
+    this.plugins = plugins;
+    return this;
+  }
+
+  /** Sets the label of the target being compiled. */
+  public JavaHeaderCompileActionBuilder setTargetLabel(@Nullable Label targetLabel) {
+    this.targetLabel = targetLabel;
+    return this;
+  }
+
+  /** Sets the injecting rule kind of the target being compiled. */
+  public JavaHeaderCompileActionBuilder setInjectingRuleKind(@Nullable String injectingRuleKind) {
+    this.injectingRuleKind = injectingRuleKind;
+    return this;
+  }
+
+  /**
+   * Sets the path to a temporary directory, e.g. for extracting sourcejar entries to before
+   * compilation.
+   */
+  public JavaHeaderCompileActionBuilder setTempDirectory(PathFragment tempDirectory) {
+    checkNotNull(tempDirectory, "tempDirectory must not be null");
+    this.tempDirectory = tempDirectory;
+    return this;
+  }
+
+  /** Sets the Strict Java Deps mode. */
+  public JavaHeaderCompileActionBuilder setStrictJavaDeps(
+      BuildConfiguration.StrictDepsMode strictJavaDeps) {
+    checkNotNull(strictJavaDeps, "strictJavaDeps must not be null");
+    this.strictJavaDeps = strictJavaDeps;
+    return this;
+  }
+
+  /** Sets the javabase inputs. */
+  public JavaHeaderCompileActionBuilder setAdditionalInputs(NestedSet<Artifact> additionalInputs) {
+    checkNotNull(additionalInputs, "additionalInputs must not be null");
+    this.additionalInputs = additionalInputs;
+    return this;
+  }
+
+  /** Sets the javac jar. */
+  public JavaHeaderCompileActionBuilder setJavacJar(Artifact javacJar) {
+    checkNotNull(javacJar, "javacJar must not be null");
+    this.javacJar = javacJar;
+    return this;
+  }
+
+  /** Sets the tools jars. */
+  public JavaHeaderCompileActionBuilder setToolsJars(NestedSet<Artifact> toolsJars) {
+    checkNotNull(toolsJars, "toolsJars must not be null");
+    this.toolsJars = toolsJars;
+    return this;
+  }
+
+  /** Builds and registers the action for a header compilation. */
+  public void build(JavaToolchainProvider javaToolchain, JavaRuntimeInfo hostJavabase) {
+    checkNotNull(outputDepsProto, "outputDepsProto must not be null");
+    checkNotNull(sourceFiles, "sourceFiles must not be null");
+    checkNotNull(sourceJars, "sourceJars must not be null");
+    checkNotNull(classpathEntries, "classpathEntries must not be null");
+    checkNotNull(bootclasspathEntries, "bootclasspathEntries must not be null");
+    checkNotNull(tempDirectory, "tempDirectory must not be null");
+    checkNotNull(strictJavaDeps, "strictJavaDeps must not be null");
+    checkNotNull(directJars, "directJars must not be null");
+    checkNotNull(compileTimeDependencyArtifacts, "compileTimeDependencyArtifacts must not be null");
+    checkNotNull(javacOpts, "javacOpts must not be null");
+
+    // Invariant: if strictJavaDeps is OFF, then directJars and
+    // dependencyArtifacts are ignored
+    if (strictJavaDeps == BuildConfiguration.StrictDepsMode.OFF) {
+      directJars = NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER);
+      compileTimeDependencyArtifacts = NestedSetBuilder.emptySet(Order.STABLE_ORDER);
+    }
+
+    // The compilation uses API-generating annotation processors and has to fall back to
+    // javac-turbine.
+    boolean requiresAnnotationProcessing = !plugins.isEmpty();
+
+    SpawnAction.Builder builder = new SpawnAction.Builder();
+
+    builder.setEnvironment(JavaCompileAction.UTF8_ENVIRONMENT);
+
+    builder.setProgressMessage(
+        new ProgressMessage(
+            this.outputJar, sourceFiles.size() + sourceJars.size(), plugins.processorClasses()));
+
+    builder.addTool(javacJar);
+    builder.addTransitiveTools(toolsJars);
+
+    builder.addOutput(outputJar);
+    builder.addOutput(outputDepsProto);
+
+    builder.addTransitiveInputs(hostJavabase.javaBaseInputsMiddleman());
+    builder.addTransitiveInputs(additionalInputs);
+    builder.addInputs(bootclasspathEntries);
+    builder.addInputs(sourceJars);
+    builder.addInputs(sourceFiles);
+
+    // The header compiler is either a jar file that needs to be executed using
+    // `java -jar <path>`, or an executable that can be run directly.
+    FilesToRunProvider headerCompiler = javaToolchain.getHeaderCompiler();
+    if (!headerCompiler.getExecutable().getExtension().equals("jar")) {
+      builder.setExecutable(headerCompiler);
+    } else {
+      builder.setJarExecutable(
+          hostJavabase.javaBinaryExecPath(),
+          headerCompiler.getExecutable(),
+          javaToolchain.getJvmOptions());
+    }
+
+    CustomCommandLine.Builder commandLine =
+        CustomCommandLine.builder()
+            .addExecPath("--output", outputJar)
+            .addExecPath("--output_deps", outputDepsProto)
+            .addPath("--temp_dir", tempDirectory)
+            .addExecPaths("--bootclasspath", bootclasspathEntries)
+            .addExecPaths("--sources", sourceFiles)
+            .addExecPaths("--source_jars", sourceJars)
+            .add("--injecting_rule_kind", injectingRuleKind);
+
+    if (!javacOpts.isEmpty()) {
+      commandLine.addAll("--javacopts", javacOpts);
+      // terminate --javacopts with `--` to support javac flags that start with `--`
+      commandLine.add("--");
+    }
+
+    if (targetLabel != null) {
+      commandLine.add("--target_label");
+      if (targetLabel.getPackageIdentifier().getRepository().isDefault()
+          || targetLabel.getPackageIdentifier().getRepository().isMain()) {
+        commandLine.addLabel(targetLabel);
+      } else {
+        // @-prefixed strings will be assumed to be params filenames and expanded,
+        // so add an extra @ to escape it.
+        commandLine.addPrefixedLabel("@", targetLabel);
+      }
+    }
+
+    // The action doesn't require annotation processing, so use the non-javac-based turbine
+    // implementation.
+    if (!requiresAnnotationProcessing) {
+      NestedSet<Artifact> classpath;
+      if (!directJars.isEmpty() || classpathEntries.isEmpty()) {
+        classpath = directJars;
+      } else {
+        classpath = classpathEntries;
+      }
+      builder.addTransitiveInputs(classpath);
+
+      commandLine.addExecPaths("--classpath", classpath);
+      commandLine.add("--nojavac_fallback");
+
+      ruleContext.registerAction(
+          builder
+              .addCommandLine(
+                  commandLine.build(), ParamFileInfo.builder(ParameterFileType.UNQUOTED).build())
+              .setMnemonic("Turbine")
+              .build(ruleContext));
+      return;
+    }
+
+    // If we get here the action requires annotation processing, so add additional inputs and
+    // flags needed for the javac-based header compiler implementatino that supports
+    // annotation processing.
+
+    builder.addTransitiveInputs(classpathEntries);
+    builder.addTransitiveInputs(plugins.processorClasspath());
+    builder.addTransitiveInputs(plugins.data());
+    builder.addTransitiveInputs(compileTimeDependencyArtifacts);
+
+    commandLine.addExecPaths("--classpath", classpathEntries);
+    commandLine.addAll("--processors", plugins.processorClasses());
+    commandLine.addExecPaths("--processorpath", plugins.processorClasspath());
+    if (strictJavaDeps != BuildConfiguration.StrictDepsMode.OFF) {
+      commandLine.addExecPaths("--direct_dependencies", directJars);
+      if (!compileTimeDependencyArtifacts.isEmpty()) {
+        commandLine.addExecPaths("--deps_artifacts", compileTimeDependencyArtifacts);
+      }
+    }
+
+    ruleContext.registerAction(
+        builder
+            .addCommandLine(
+                commandLine.build(),
+                ParamFileInfo.builder(ParameterFileType.UNQUOTED).setCharset(ISO_8859_1).build())
+            .setMnemonic("JavacTurbine")
+            .build(ruleContext));
+  }
+
+  /** Static class to avoid keeping a reference to this builder after build() is called. */
+  @AutoCodec.VisibleForSerialization
+  @AutoCodec
+  static class ProgressMessage extends LazyString {
+
+    private final Artifact outputJar;
+    private final int fileCount;
+    private final NestedSet<String> processorClasses;
+
+    public ProgressMessage(Artifact outputJar, int fileCount, NestedSet<String> processorClasses) {
+      this.outputJar = outputJar;
+      this.fileCount = fileCount;
+      this.processorClasses = processorClasses;
+    }
+
+    @Override
+    public String toString() {
+      return String.format(
+          "Compiling Java headers %s (%d files)%s",
+          outputJar.prettyPrint(),
+          fileCount,
+          processorClasses.isEmpty()
+              ? ""
+              : processorClasses.toCollection().stream()
+                  .map(name -> name.substring(name.lastIndexOf('.') + 1))
+                  .collect(joining(", ", " and running annotation processors (", ")")));
+    }
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
index 2b9cbec..0d3472c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
@@ -578,7 +578,6 @@
     // incremental build performance is important.
     host.useIjars = useIjars;
     host.headerCompilation = headerCompilation;
-    host.headerCompilationDisableJavacFallback = headerCompilationDisableJavacFallback;
 
     host.javaDeps = javaDeps;
     host.javaClasspath = javaClasspath;
diff --git a/src/test/shell/integration/java_integration_test.sh b/src/test/shell/integration/java_integration_test.sh
index a1b4f15..108e67b 100755
--- a/src/test/shell/integration/java_integration_test.sh
+++ b/src/test/shell/integration/java_integration_test.sh
@@ -807,7 +807,7 @@
 EOF
   bazel build --java_header_compilation=true \
     //$pkg/java/test:a >& "$TEST_log" && fail "Unexpected success"
-  expect_log "package missing does not exist"
+  expect_log "symbol not found missing.NoSuch"
 }
 
 function test_java_import_with_empty_jars_attribute() {