JDK-8244367 : javax.lang.model for sealed classes
  • Type: CSR
  • Component: core-libs
  • Sub-Component: javax.lang.model
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 15
  • Submitted: 2020-05-04
  • Updated: 2020-06-01
  • Resolved: 2020-05-13
Related Reports
CSR :  
Relates :  
Description
Summary
-------

Add support for _sealed classes_ in javax.lang.model. Sealed classes are classes
or interfaces that restrict which other classes or interfaces may extend or
implement them.

Problem
-------

Sealed classes, see ([JEP 360](http://openjdk.java.net/jeps/360)), will be
previewed in Java SE 15 and support will be needed for them in `javax.lang.model`.
In particular new modifiers will be needed, corresponding to the new `sealed`
and `non-sealed` class modifiers. In addition, it will be necessary to provide a
way to access the permitted subclasses of a sealed class or interface.

Solution
--------

Enhance `javax.lang.model` to support sealed classes as follows:

-  Add two new modifiers to
`javax.lang.model.element.Modifier` representing the `sealed` and 
the `non-sealed` class modifiers. 

- Add a new method to
`javax.lang.model.element.TypeElement` which returns a list containing the
permitted subclasses. This list can only be empty if the given `TypeElement` is not
sealed. 

Specification
-------------

    diff --git a/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java b/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java
    --- a/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java
    +++ b/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java
    @@ -59,6 +59,36 @@ public enum Modifier {
          */
          DEFAULT,
         /** The modifier {@code static} */          STATIC,
    +
    +    /**
    +     * {@preview Associated with sealed classes, a preview feature of the Java language.
    +     *
    +     *           This enum constant is associated with <i>sealed classes</i>, a preview
    +     *           feature of the Java language. Preview features
    +     *           may be removed in a future release, or upgraded to permanent
    +     *           features of the Java language.}
    +     *
    +     * The modifier {@code sealed}
    +     * @since 15
    +     */
    +    @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
    +                                             essentialAPI=false)
    +    SEALED,
    +
    +    /**
    +     * {@preview Associated with sealed classes, a preview feature of the Java language.
    +     *
    +     *           This enum constant is associated with <i>sealed classes</i>, a preview
    +     *           feature of the Java language. Preview features
    +     *           may be removed in a future release, or upgraded to permanent
    +     *           features of the Java language.}
    +     *
    +     * The modifier {@code non-sealed}
    +     * @since 15
    +     */
    +    @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
    +            essentialAPI=false)
    +    NON_SEALED,
         /** The modifier {@code final} */           FINAL,
         /** The modifier {@code transient} */       TRANSIENT,
         /** The modifier {@code volatile} */        VOLATILE,
    diff --git a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java
    --- a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java
    +++ b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java
    @@ -204,6 +204,29 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
             return List.of();
         }
     
    +    /**
    +     * {@preview Associated with sealed classes, a preview feature of the Java language.
    +     *
    +     *           This method is associated with <i>sealed classes</i>, a preview
    +     *           feature of the Java language. Preview features
    +     *           may be removed in a future release, or upgraded to permanent
    +     *           features of the Java language.}
    +     * Returns the permitted subclasses of this type element in
    +     * declaration order.
    +     *
    +     * @implSpec The default implementations of this method returns an
    +     * empty and unmodifiable list.
    +     *
    +     * @return the permitted subclasses, or an empty list if there are none
    +     *
    +     * @since 15
    +     */
    +    @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
    +                                 essentialAPI=false)
    +    default List<? extends TypeMirror> getPermittedSubclasses() {
    +        return List.of();
    +    }
    +
         /**
          * Returns the package of a top-level type and returns the
          * immediately lexically enclosing element for a {@linkplain

Additional links
-------

* javadoc: http://cr.openjdk.java.net/~vromero/sealed_CSRs/javax.lang.model/javadoc.00/module-summary.html
* specdiff: http://cr.openjdk.java.net/~vromero/sealed_CSRs/javax.lang.model/specdiff.00/overview-summary.html
Comments
Moving amended specification to Approved.
13-05-2020

[~darcy] I have updated the CSR as we discussed and finalized it
13-05-2020

In a separate discussion with [~vromero] and [~jjg], we decided to drop the Elements::isSealed method from the version of the CSR that will be Finalized.
12-05-2020

[~vromero], if we have Elements::isSealed, I think we should have Elements::isNonSealed too. Also, to repeat a comment from JDK-8242521, since "non-sealed" is treated as a keyword if the sealing feature is enabled, SourceVersion::isKeyword should be updated to do this check for source 15 when enable preview is true.
09-05-2020

Moving to Provisional. For Modifier, while putting new constants at the end is conventional and maximizing behavioral compatibility, in this case it is more important to preserve the relative ordering of the constants for purpose of sorting the output. If computing "is-sealed" is just checking for the presence of the modifier, the javax.lang.model API has avoided using isFoo methods like that to do (unlike core reflection). If the computation is more involved, than having an isSealed method on Elements is reasonable. However, the method should describe that is-NON_SEALED is *not* !(isSealed). In other words, the law of the excluded middle does not hold: a class can be sealed, non-sealed, or neither sealed nor non-sealed (such as being final).
09-05-2020

[~darcy] I was checking the code and method javax.lang.model.util.Elements::isSealed is being used by javadoc to show if a class is `sealed` or `non-sealed` so I assume that we should keep it right?
09-05-2020

[~vromero], in that case, yes, please remove the isSealed method before the CSR is finalized; thanks. (If experience shows "is-sealed" has high usage, we can consider adding it back later.)
08-05-2020

[~darcy] the implementation at com.sun.tools.javac.model.JavacElements is just checking checking for the modifier. I assume then that your opinion is that the method should be removed then right?
08-05-2020