JDK-8236842 : Surprising 'multiple elements' behaviour from getTypeElement when cross-compiling with --release
  • Type: Bug
  • Component: core-libs
  • Sub-Component: javax.lang.model
  • Affected Version: 14
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2020-01-09
  • Updated: 2025-04-09
  • Resolved: 2020-11-02
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 16
16 b23Fixed
Related Reports
CSR :  
Causes :  
Description
The following example involves an annotation processor that uses Elements#getTypeElement to try to load com.sun.tools.javac.util.Context (which is defined in jdk.compiler). A definition of the class is also on the -classpath, from a JDK 8 tools.jar.

=== P.java ===
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;

@SupportedAnnotationTypes("*")
public class P extends AbstractProcessor {
  @Override
  public SourceVersion getSupportedSourceVersion() {
    return SourceVersion.latestSupported();
  }

  @Override
  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    TypeElement typeElement =
        processingEnv.getElementUtils().getTypeElement("com.sun.tools.javac.util.Context");
    processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, String.valueOf(typeElement));
    return false;
  }
}
=== T.java ===
@Deprecated class T {}
===

With the default target language level, a 'Multiple elements' note gets logged, and the element cannot be loaded:

```
$JAVA14_HOME/bin/javac P.java
$JAVA14_HOME/bin/javac -fullversion -processor P -cp $JAVA8_HOME/lib/tools.jar:. T.java
javac full version "14-ea+30-1385"
Note: Multiple elements named 'com.sun.tools.javac.util.Context' in modules 'unnamed module, jdk.compiler' were found by javax.lang.model.util.Elements.getTypeElement.
Note: null
Note: null
```

When cross-compiling (with --release 13) no note is logged, and the element is loaded.

```
$JAVA14_HOME/bin/javac -processor P -cp $JAVA8_HOME/lib/tools.jar:. --release 13 T.java
Note: com.sun.tools.javac.util.Context
Note: com.sun.tools.javac.util.Context
```

Is this inconsistency deliberate? If not, which of the two examples is correct?

Is the issue with `--release 13` that the ct.sym data for previous releases only includes modules that are supposed to be visible, so it doesn't have enough information to detect the clash?
Comments
Changeset: d05df7c1 Author: Jan Lahoda <jlahoda@openjdk.org> Date: 2020-11-02 10:15:16 +0000 URL: https://github.com/openjdk/jdk/commit/d05df7c1
02-11-2020

[~jlahoda] Interesting idea. Can that be readily specified?
20-02-2020

Just an idea: what if getTypeElement/getPackageElement would prefer elements visible in the module(s) that is/are currently being compiled? There could still be multiple indistinguishable elements available, but the set of cases where that would happen would be significantly limited. Just an idea.
20-02-2020

I am not completely sure that's the answer is so easy. Elements.getTypeElement generally can see any type, even implementation ones. The issue is that is does not have any context, and so if there are multiple elements available it is difficult to say which of them is the proper one. For example, the compilation above is a compilation of an unnamed module - and it could validly depend on com.sun.tools.javac.util.Context from classpath - and it could be inconsistent if Elements.getTypeElement would return the Context from jdk.compiler, to which the code cannot refer. Also for --release 13/no --release 13, there would still be a difference (it once would find Context from classpath and other times the jdk.compiler). Overall, not sure if there's a solution which wouldn't open further questions.
15-01-2020

A package on the classpath should not be observable when a like-named package is observable in a readable module.
14-01-2020