Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8253168

Surprising 'multiple elements' behaviour from getTypeElement when cross-compiling with --release

    XMLWordPrintable

Details

    • CSR
    • Resolution: Approved
    • P3
    • 16
    • core-libs
    • None
    • behavioral
    • minimal
    • Java API
    • SE

    Description

      Summary

      Avoid surprising null result from Elements.getTypeElement(CharSequence) and Elements.getPackageElement(CharSequence) when a (uniquely) visible element clashes with an invisible element.

      Problem

      Unqualified Elements.getTypeElement(CharSequence) and Elements.getPackageElement(CharSequence) search for elements across all modules in the module graph, and only return a value when they find exactly one element. This is troublesome, as an element (uniquely) visible from a root module may be "hidden" by an invisible element.

      For example, consider:

      ---m1:
      module m1 {}
      package test; public class Test {}
      
      ---m2:
      module m2 { exports test; }
      package test; public class Test{}
      
      ---mt:
      module mt { requires m1; requires m2; }

      While compiling "mt", Elements.getTypeElement("test.Test") will return null, as it will find two copies of test.Test (one in each m1 and m2). But, in the context of mt compilation, only the element from m2 makes sense.

      Solution

      Prefer elements (uniquely) visible from root modules. Only if none is found, search for invisible elements. Root modules are the modules javac is currently compiling.

      Specification

      Proposed change to javax.lang.model.util.Elements:

      diff --git a/src/java.base/share/classes/java/lang/module/package-info.java b/src/java.base/share/classes/java/lang/module/package-info.java
      index ff7448c9c7f..2750c99a216 100644
      --- a/src/java.base/share/classes/java/lang/module/package-info.java
      +++ b/src/java.base/share/classes/java/lang/module/package-info.java
      @@ -147,7 +147,7 @@
        * <p> Otherwise, resolution succeeds, and the result of resolution is the
        * readability graph.
        *
      - * <h3> Root modules </h3>
      + * <h3><a id="root-modules"></a> Root modules </h3>
        *
        * <p> The set of root modules at compile-time is usually the set of modules
        * being compiled. At run-time, the set of root modules is usually the
      diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java
      index 81344311869..aad204336e8 100644
      --- a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java
      +++ b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java
      @@ -51,11 +51,30 @@
       public interface Elements {
      
           /**
      -     * Returns a package given its fully qualified name if the package is unique in the environment.
      -     * If running with modules, all modules in the modules graph are searched for matching packages.
      -     *
      -     * @param name  fully qualified package name, or an empty string for an unnamed package
      -     * @return the specified package, or {@code null} if it cannot be uniquely found
      +     * Returns a package given its fully qualified name if the package is uniquely
      +     * determinable in the environment.
      +     *
      +     * If running with modules, packages of the given name are searched in a
      +     * two-stage process:
      +     * <ul>
      +     *     <li>find non-empty packages with the given name returned by
      +     *         {@link #getPackageElement(ModuleElement, CharSequence)},
      +     *         where the provided ModuleSymbol is any
      +     *         <a href="../../../../../java.base/java/lang/module/package-summary.html#root-modules">root module</a>,
      +     *     </li>
      +     *     <li>if the above yields an empty list, search
      +     *         {@link #getAllModuleElements() all modules} for observable
      +     *         packages with the given name
      +     *     </li>
      +     * </ul>
      +     *
      +     * If this process leads to a list with a single element,
      +     * the single element is returned, otherwise null is returned.
      +     *
      +     * @param name fully qualified package name,
      +     *             or an empty string for an unnamed package
      +     * @return the specified package,
      +     *         or {@code null} if no package can be uniquely determined.
            */
           PackageElement getPackageElement(CharSequence name);
      
      @@ -119,12 +138,29 @@ default PackageElement getPackageElement(ModuleElement module, CharSequence name
           }
      
           /**
      -     * Returns a type element given its canonical name if the type element is unique in the environment.
      -     * If running with modules, all modules in the modules graph are searched for matching
      -     * type elements.
      -     *
      -     * @param name  the canonical name
      -     * @return the named type element, or {@code null} if it cannot be uniquely found
      +     * Returns a type element given its canonical name if the type element is uniquely
      +     * determinable in the environment.
      +     *
      +     * If running with modules, type elements of the given name are
      +     * searched in a two-stage process:
      +     * <ul>
      +     *     <li>find type elements with the given name returned by
      +     *         {@link #getTypeElement(ModuleElement, CharSequence)},
      +     *         where the provided ModuleSymbol is any
      +     *         <a href="../../../../../java.base/java/lang/module/package-summary.html#root-modules">root module</a>,
      +     *     </li>
      +     *     <li>if the above yields an empty list, search
      +     *         {@link #getAllModuleElements() all modules} for observable
      +     *         type elements with the given name
      +     *     </li>
      +     * </ul>
      +     *
      +     * If this process leads to a list with a single element,
      +     * the single element is returned, otherwise null is returned.
      +     *
      +     * @param name the canonical name
      +     * @return the named type element,
      +     *         or {@code null} if no type element can be uniquely determined.
            */
           TypeElement getTypeElement(CharSequence name);

      Rendered javadoc with these changes is available for convenience here:

      Attachments

        Issue Links

          Activity

            People

              jlahoda Jan Lahoda
              cushon Liam Miller-Cushon
              Joe Darcy, Vicente Arturo Romero Zaldivar
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: