JDK-8267506 : Add implSpec's to AccessibleObject and seal Executable
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Priority: P3
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 17
  • Submitted: 2021-05-20
  • Updated: 2021-05-25
  • Resolved: 2021-05-25
Related Reports
CSR :  
Description
Summary
-------

Add `implSpec` tags `AccessibleObject`, deprecate its constructor, and seal `Executable`.

Problem
-------

Conceptually,  `AccessibleObject` is a sealed class with a protected constructor stating

> Constructor: only used by the Java Virtual Machine.

Several of the methods defined on `AccessibleObject` unconditionally throw exceptions as they are meant to be overridden in all subclasses.

However, it is problematic to mark `AccessibleObject` as sealed given the existence of several subclasses outside of the JDK.

Solution
--------

Rather than sealing `AccessibleObject`,  the public `AccessibleObject` constructor will be marked as deprecated, the need-to-be-overridden methods on  `AccessibleObject` will be documented with  `implSpec` tags stating the default implementation is to thrown an exception. (Within the JDK, all the `AccessibleObject` subclasses already override these methods, so they would not need to be documented if  `AccessibleObject` could be sealed.)

In addition, `Executable` is sealed, permitting its two existing final subclasses, Method and Constructor.


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

     diff --git a/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java b/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
    index a3346b8c3f80..560b93f82365 100644
    --- a/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
    +++ b/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java
    @@ -497,6 +497,7 @@ public final boolean canAccess(Object obj) {
         /**
          * Constructor: only used by the Java Virtual Machine.
          */
    +    @Deprecated(since="17")
         protected AccessibleObject() {}
     
         // Indicates whether language-level access checks are overridden
    @@ -520,12 +521,16 @@ protected AccessibleObject() {}
          * <p> Note that any annotation returned by this method is a
          * declaration annotation.
          *
    +     * @implSpec
    +     * The default implementation throws {@link
    +     * UnsupportedOperationException}; subclasses should override this method.
    +     *
          * @throws NullPointerException {@inheritDoc}
          * @since 1.5
          */
         @Override
         public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {

    @@ -545,12 +550,16 @@ public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
          * <p> Note that any annotations returned by this method are
          * declaration annotations.
          *
    +     * @implSpec
    +     * The default implementation throws {@link
    +     * UnsupportedOperationException}; subclasses should override this method.
    +     *
          * @throws NullPointerException {@inheritDoc}
          * @since 1.8
          */
         @Override
         public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {

     
    @@ -606,11 +615,15 @@ public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
          * <p> Note that any annotations returned by this method are
          * declaration annotations.
          *
    +     * @implSpec
    +     * The default implementation throws {@link
    +     * UnsupportedOperationException}; subclasses should override this method.
    +     *
          * @since 1.5
          */
         @Override
         public Annotation[] getDeclaredAnnotations()  {

    diff --git a/src/java.base/share/classes/java/lang/reflect/Executable.java b/src/java.base/share/classes/java/lang/reflect/Executable.java
    index ad399cb86d95..d86a454c7511 100644
    --- a/src/java.base/share/classes/java/lang/reflect/Executable.java
    +++ b/src/java.base/share/classes/java/lang/reflect/Executable.java
    @@ -47,11 +47,12 @@
      *
      * @since 1.8
      */
    -public abstract class Executable extends AccessibleObject
    -    implements Member, GenericDeclaration {
    +public abstract sealed class Executable extends AccessibleObject
    +    implements Member, GenericDeclaration permits Constructor, Method {
Comments
Moving to Approved.
25-05-2021

If this was conceptually intended to be a "sealed" class, only subclassed within the JDK (not sure why it mentions JVM) then why was the constructor not declared with package access only instead of protected? As it stands we have a public class with an accessible protected constructor which allows subclassing outside of the package, and we are now going to remove that ability.
20-05-2021