Uploaded image for project: 'CCC Migration Project'
  1. CCC Migration Project
  2. CCC-8173945

Add methods for Elements.getAll{Type, Package, Module}Elements

    XMLWordPrintable

    Details

    • Subcomponent:
    • Compatibility Kind:
      source
    • Compatibility Risk:
      low
    • Compatibility Risk Description:
      New default methods being added to an interface.
    • Interface Kind:
      Java API
    • Scope:
      SE

      Description

      Summary

      Add the three methods getAllTypeElements, getAllPackageElements, and getAllModuleElements with defaults to the utility interface javax.lang.model.Elements.

      Problem

      As part of adding modules to the platform, the long-standing condition that there would be at most one type/package for the same canonical name was rendered untrue: two modules can have (non-exported) types or packages whose names are the same.

      This is a wrinkle for the javax.lang.model.Elements methods which map from names to type or package elements. The existing methods

          PackageElement getPackageElement(CharSequence name)     TypeElement getTypeElement(CharSequence name)

      were redefined to return null if a type/package could not be uniquely found (JDK-8133896). In addition, overloads of these methods taking a module parameter were added to the API:

          PackageElement getPackageElement(ModuleElement module, CharSequence name)     TypeElement getTypeElement(ModuleElement module, CharSequence name)

      However, this still leaves no easy way to return the same-named elements from whichever module they may be defined in.

      One API approach to address this issue would be Elements.getAll{Type, Package}Elements methods. In addition, it is helpful to have a way to see all known modules.

      Solution

      Add the methods in question

      Specification

      diff -r f0bc0f34d2cc src/java.compiler/share/classes/javax/lang/model/util/Elements.java
      --- a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java Tue Feb 07 16:19:50 2017 -0800
      +++ b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java Thu Feb 09 18:48:11 2017 -0800
      @@ -25,9 +25,12 @@
      
       package javax.lang.model.util;
      
      -
      +import java.util.ArrayList;
      +import java.util.Collections;
       import java.util.List;
       import java.util.Map;
      +import java.util.Set;
      +import java.util.LinkedHashSet;
      
       import javax.lang.model.AnnotatedConstruct;
       import javax.lang.model.element.*;
      @@ -72,6 +75,47 @@
           }
      
           /**
      +     * Returns all package elements with the given canonical name.
      +     *
      +     * There may be more than one package element with the same canonical
      +     * name if the package elements are in different modules.
      +     *
      +     * @implSpec The default implementation of this method calls
      +     * {@link #getAllModuleElements(CharSequence)
      +     * getAllModuleElements} and stores the result. If the set of
      +     * modules is empty, {@link #getPackageElement(CharSequence)
      +     * getPackageElement(name)} is called passing through the name
      +     * argument. If {@code getPackageElement(name)} is null, an empty set
      +     * of package elements is returned; otherwise, a single-element set
      +     * with the found package element is returned. If the set of modules
      +     * is nonempty, the modules are iterated over and any nonnull
      +     * result of {@link getPackageElement(ModuleElement,
      +     * CharacterSequence) getPackageElement(module, name)} are
      +     * accumulated into a set. The set is then returned.
      +     *
      +     * @param name  the canonical name
      +     * @return the package elements, or an empty set if no package with the name can be found
      +     * @since 9
      +     */
      +    default Set<? extends PackageElement> getAllPackageElements(CharSequence name) {
      +        Set<? extends ModuleElement> modules = getAllModuleElements();
      +        if (modules.isEmpty()) {
      +            PackageElement packageElt = getPackageElement(name);
      +            return (packageElt != null) ?
      +                Collections.singleton(packageElt):
      +                Collections.emptySet();
      +        } else {
      +            Set<PackageElement> result = new LinkedHashSet<>(1); // Usually expect at most 1 result
      +            for (ModuleElement module: modules) {
      +                PackageElement packageElt = getPackageElement(module, name);
      +                if (packageElt != null)
      +                    result.add(packageElt);
      +            }
      +            return Collections.unmodifiableSet(result);
      +        }
      +    }
      +
      +    /**
            * 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.
      @@ -97,6 +141,47 @@
           }
      
           /**
      +     * Returns all type elements with the given canonical name.
      +     *
      +     * There may be more than one type element with the same canonical
      +     * name if the type elements are in different modules.
      +     *
      +     * @implSpec The default implementation of this method calls
      +     * {@link #getAllModuleElements(CharSequence)
      +     * getAllModuleElements} and stores the result. If the set of
      +     * modules is empty, {@link #getTypeElement(CharSequence)
      +     * getTypeElement(name)} is called passing through the name
      +     * argument. If {@code getTypeElement(name)} is null, an empty set
      +     * of type elements is returned; otherwise, a single-element set
      +     * with the found type element is returned. If the set of modules
      +     * is nonempty, the modules are iterated over and any nonnull
      +     * result of {@link getTypeElement(ModuleElement,
      +     * CharacterSequence) getTypeElement(module, name)} are
      +     * accumulated into a set. The set is then returned.
      +     *
      +     * @param name  the canonical name
      +     * @return the type elements, or an empty set if no type with the name can be found
      +     * @since 9
      +     */
      +    default Set<? extends TypeElement> getAllTypeElements(CharSequence name) {
      +        Set<? extends ModuleElement> modules = getAllModuleElements();
      +        if (modules.isEmpty()) {
      +            TypeElement typeElt = getTypeElement(name);
      +            return (typeElt != null) ?
      +                Collections.singleton(typeElt):
      +                Collections.emptySet();
      +        } else {
      +            Set<TypeElement> result = new LinkedHashSet<>(1); // Usually expect at most 1 result
      +            for (ModuleElement module: modules) {
      +                TypeElement typeElt = getTypeElement(module, name);
      +                if (typeElt != null)
      +                    result.add(typeElt);
      +            }
      +            return Collections.unmodifiableSet(result);
      +        }
      +    }
      +
      +    /**
            * Returns a module element given its fully qualified name.
            * If the named module cannot be found, null is returned. One situation where a module
            * cannot be found is if the environment does not include modules, such as
      @@ -117,6 +202,26 @@
           }
      
           /**
      +     * Returns all module elements in the current environment.
      +     *
      +     * If no modules are present, an empty set is returned. One
      +     * situation where no modules are present occurs when the
      +     * environment does not include modules, such as an annotation
      +     * processing environment configured for a {@linkplain
      +     * javax.annotation.processing.ProcessingEnvironment#getSourceVersion
      +     * source version} without modules.
      +     *
      +     * @implSpec The default implementation of this method returns
      +     * an empty set.
      +     *
      +     * @return the known module elements, or an empty set if there are no modules
      +     * @since 9
      +     */
      +    default Set<? extends ModuleElement> getAllModuleElements() {
      +        return Collections.emptySet();
      +    }
      +
      +    /**
            * Returns the values of an annotation's elements, including defaults.
            *
            * @see AnnotationMirror#getElementValues()

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              darcy Joe Darcy
              Reporter:
              darcy Joe Darcy
              Reviewed By:
              Jonathan Gibbons
              Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: