Repository: bazelbuild/bazel
Issue: @bazel_tools//tools/java/runfiles:auto_bazel_repository_processor does not compile with JDK 8
Labels: type: bug
team-Rules-Java
untriaged

### Description of the bug:


Our internal build uses JDK 11 to build code against JDK 8, using the JDK 8 bootclasspath.  When upgrading to Bazel 6, the Java runfiles library fails to compile:

```
external/bazel_tools/tools/java/runfiles/AutoBazelRepositoryProcessor.java:84: error: method iterate in interface Stream<T#2> cannot be applied to given types;
        Stream.iterate(
              ^
  required: T#1,UnaryOperator<T#1>
  found: TypeElement,(element)-[...]ement,Element::g[...]ement
  reason: cannot infer type-variable(s) T#1
    (actual and formal argument lists differ in length)
  where T#1,T#2 are type-variables:
    T#1 extends Object declared in method <T#1>iterate(T#1,UnaryOperator<T#1>)
    T#2 extends Object declared in interface Stream
Target @bazel_tools//tools/java/runfiles:auto_bazel_repository_processor failed to build
```

This appears to be occurring because the three-argument `Stream.iterate` method used here:

https://github.com/bazelbuild/bazel/blob/338bbc02132da7de8681196b6a0afbb6297038aa/tools/java/runfiles/AutoBazelRepositoryProcessor.java#L84-L90 

does not exist in JDK 8, there is only a [two-argument one](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#iterate-T-java.util.function.UnaryOperator-).  It was added in JDK 9 (JDK 11 docs [here](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Stream.html#iterate(T,java.util.function.Predicate,java.util.function.UnaryOperator)).

A simple enough fix would be to replace this `Stream` call with a `for` loop, which seems to work for me locally.  I can prepare a PR should this be desirable.  My understanding is that while Bazel itself needs JDK 11, Bazel should still be able to compile code for JDK 8, including libraries intended to be loaded by end-users like this one.

### What's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.


Since this only uses the standard library, you can just use `javac` from JDK 8 without invoking Bazel:

```javac tools/java/runfiles/AutoBazelRepositoryProcessor.java```

Reproduced using OpenJDK 11 using the OpenJDK 8 bootclasspath, and OpenJDK 8 itself.

### Which operating system are you running Bazel on?


Linux (Alma 8 aarch64, CentOS 7 amd64)

### What is the output of `bazel info release`?


6.0.0-vmware

### If `bazel info release` returns `development version` or `(@non-git)`, tell us how you built Bazel.


_No response_

### What's the output of `git remote get-url origin; git rev-parse master; git rev-parse HEAD` ?


_No response_

### Have you found anything relevant by searching the web?

https://github.com/bazelbuild/bazel/issues/17281 is in the same area, but does not correspond to this precise issue.

### Any other information, logs, or outputs that you want to share?

_No response_

Issue comments:
Thanks for the detailed report, I prepared a fix at https://github.com/bazelbuild/bazel/issues/17458 that can be cherry-picked into Bazel 6.1.
I'm seeing this issue with bazel 6.1.2. (It worked in 5.3.2.) Looking at https://github.com/bazelbuild/bazel/commit/420659a9ad2a98f57e057d8c22eb621e3b12803e, it looks like it made it into various `7.0.0-pre.*` builds, but not into any `6.*` build. Is it possible to cherry-pick it?

Pull request review comments:

Patch that resolved the issue:
diff --git a/tools/java/runfiles/AutoBazelRepositoryProcessor.java b/tools/java/runfiles/AutoBazelRepositoryProcessor.java
index ae356d800f6d03..f323cf211ccfc5 100644
--- a/tools/java/runfiles/AutoBazelRepositoryProcessor.java
+++ b/tools/java/runfiles/AutoBazelRepositoryProcessor.java
@@ -14,22 +14,18 @@
 
 package com.google.devtools.build.runfiles;
 
-import static java.util.stream.Collectors.joining;
-import static java.util.stream.Collectors.toList;
 
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.Collections;
-import java.util.List;
+import java.util.ArrayDeque;
+import java.util.Deque;
 import java.util.Set;
-import java.util.stream.Stream;
 import javax.annotation.processing.AbstractProcessor;
 import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.annotation.processing.SupportedOptions;
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.Element;
-import javax.lang.model.element.Name;
 import javax.lang.model.element.TypeElement;
 import javax.tools.Diagnostic.Kind;
 
@@ -51,7 +47,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
         .flatMap(element -> roundEnv.getElementsAnnotatedWith(element).stream())
         .map(element -> (TypeElement) element)
         .forEach(this::emitClass);
-    return true;
+    return false;
   }
 
   private void emitClass(TypeElement annotatedClass) {
@@ -80,18 +76,14 @@ private void emitClass(TypeElement annotatedClass) {
     // AutoBazelRepository_Outer_Middle_Inner.
     // Note: There can be collisions when local classes are involved, but since the definition of a
     // class depends only on the containing Bazel target, this does not result in ambiguity.
-    List<String> nestedClassNames =
-        Stream.iterate(
-                annotatedClass,
-                element -> element instanceof TypeElement,
-                Element::getEnclosingElement)
-            .map(Element::getSimpleName)
-            .map(Name::toString)
-            .collect(toList());
-    Collections.reverse(nestedClassNames);
-    String generatedClassSimpleName =
-        Stream.concat(Stream.of("AutoBazelRepository"), nestedClassNames.stream())
-            .collect(joining("_"));
+    Deque<String> classNameSegments = new ArrayDeque<>();
+    Element element = annotatedClass;
+    while (element instanceof TypeElement) {
+      classNameSegments.addFirst(element.getSimpleName().toString());
+      element = element.getEnclosingElement();
+    }
+    classNameSegments.addFirst("AutoBazelRepository");
+    String generatedClassSimpleName = String.join("_", classNameSegments);
 
     String generatedClassPackage =
         processingEnv.getElementUtils().getPackageOf(annotatedClass).getQualifiedName().toString();


Test patch: