-
Type:
CSR
-
Resolution: Approved
-
Priority:
P2
-
Component/s: core-libs
-
None
-
behavioral
-
minimal
-
-
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()
*/
- csr of
-
JDK-8256693 getAnnotatedReceiverType parameterizes types too eagerly
-
- Closed
-
- relates to
-
JDK-8228531 Change Executable.getAnnotatedReceiverType to return an instance of AnnotatedParameterizedType if appropriate
-
- Closed
-