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

getAnnotatedReceiverType parameterizes types too eagerly

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P2 P2
    • 16
    • core-libs
    • None
    • behavioral
    • minimal
    • Hide
      The proposal of this CSR is to change the type of the instance returned by java.lang.reflect.Executable::getAnnotatedReceiverType and java.lang.reflect.AnnotateType::getType in some cases. Programs that were written typetesting the returned instances may see a behavioral change.
      Show
      The proposal of this CSR is to change the type of the instance returned by java.lang.reflect.Executable::getAnnotatedReceiverType and java.lang.reflect.AnnotateType::getType in some cases. Programs that were written typetesting the returned instances may see a behavioral change.
    • Java API
    • SE

      Summary

      Method java.lang.reflect.Executable::getAnnotatedReceiverType has always returned a java.lang.reflect.AnnotatedType whose underlying java.lang.reflect.Type is a raw type (instance of java.lang.Class), even if the type of the receiver type is parameterized. This makes it impossible to query the annotations on any type parameters even though they are present in the class file.

      This issue was fixed in JDK-8202471, but that introduce a new problem, that the java.lang.reflect.AnnotatedType returned was always an instance of java.lang.reflect.AnnotatedParameterizedType even if there were no type parameters present on this class or any of its transitive owner classes.

      This CSR is proposing to add a note to the spec of method java.lang.reflect.AnnotatedParameterizedType::getAnnotatedActualTypeArguments in order to clarify in which cases the returned array can be empty. The corresponding code change also narrows the cases when an java.lang.reflect.AnnotatedParameterizedType is chosen to lessen the compatibility impact.

      Problem

      Method java.lang.reflect.Executable::getAnnotatedReceiverType always used to return a java.lang.reflect.AnnotatedType with a raw underlying type. The underlying type is accessed with method AnnotatedType::getType and should model the "un"-annotated type this AnnotatedType is based on. Since this underlying type is always an instance of java.lang.Class it is impossible to read type annotations that are present on the receiver type's type parameters despite them being present in a class file.

      After JDK-8202471 a java.lang.reflect.AnnotatedParameterizedType was always retruned even though there were no type parameters present. This caused compatibility issues of its own and should be either reverted or fixed. Note that if completely reverted, the fix for the primary issue has to be abandoned since there is no way to attach the state needed for solving JDK-8202471 without switching to a java.lang.reflect.AnnotatedParameterizedType in some cases.

      Solution

      The proposed solution to both the underlying problem and the follow up is to change the type of the object returned by method java.lang.reflect.Executable::getAnnotatedReceiverType to be an instance of java.lang.reflect.AnnotatedParemeterizedType in some but not all cases. This will make sure that invoking method getType() on the instance will result in an instance of java.lang.reflect.ParameterizedType instead of java.lang.Class when appropriate.

      An instance of java.lang.reflect.AnnotatedParameterizedType supporting the correct implementation of method getType should be selected if the type of the receiver modeled by method java.lang.reflect.Executable::getAnnotatedReceiverType is either:

      • A parameterized type or
      • Is directly or transitively nested within a type that is a parameterized type

      When a java.lang.reflect.AnnotatedParameterizedType is not needed the behaviour from before JDK-8202471 should be restored, that is an instance of sun.reflect.annotation.AnnotatedTypeFactory.AnnotatedTypeBaseImpl should be returned, and calling getType() on the AnnotatedType should return an instance of java.lang.Class.

      After this change programs that were written assuming the return value of java.lang.reflect.Executable::getAnnotatedReceiverType was always an instance of sun.reflect.annotation.AnnotatedTypeFactory.AnnotatedTypeBaseImpl or that the result of java.lang.reflect.AnnotatedType::getType is always an instance of java.lang.Class must be updated. This is expected to be rare, but a corpus experiment has not been performed. The alternative to implementing this CSR is to revert JDK-8202471 and declare the primary problem not worth fixing.

      A special case for consideration is when the receiver type itself does not have any type parameters but is directly or transitively nested within a type that has type parameters. In this case even though the type itself is not parameterized it will be represented as an instance of java.lang.reflect.AnnotatedParameterizedType so that the parameterized (transitive) owner may be found. This is similar to java.lang.reflect.ParameterizedType as documented in the javadoc. The proposed spec clarification is similar to the note at java.lang.reflect.ParameterizedType explaining this.

      Specification

      diff --git src/java.base/share/classes/java/lang/reflect/AnnotatedParameterizedType.java src/java.base/share/classes/java/lang/reflect/AnnotatedParameterizedType.java
      index fc32e910116..12e99170b5d 100644
      --- src/java.base/share/classes/java/lang/reflect/AnnotatedParameterizedType.java
      +++ src/java.base/share/classes/java/lang/reflect/AnnotatedParameterizedType.java
      @@ -38,6 +38,10 @@ public interface AnnotatedParameterizedType extends AnnotatedType {
           /**
            * Returns the potentially annotated actual type arguments of this parameterized type.
            *
      +     * <p>Note that in some cases, the returned array can be empty. This can occur
      +     * if this annotated type represents a non-parameterized type nested within
      +     * a parameterized type.
      +     *
            * @return the potentially annotated actual type arguments of this parameterized type
            * @see ParameterizedType#getActualTypeArguments()
            */

            jfranck Joel Borggrén-Franck (Inactive)
            kganapureddy Krushnareddy Ganapureddy
            Vicente Arturo Romero Zaldivar
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: