-
CSR
-
Resolution: Approved
-
P2
-
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