Details
-
Bug
-
Resolution: Unresolved
-
P4
-
24
-
In Review
-
generic
-
generic
Description
The Kotlin compiler has a bug where it creates undefined type variables. This triggers a bug in the signature parser where the type arguments within the reflection API are represented as null. A reproducer can be found at: https://github.com/milgner/Repro-Kotlin-WildcardType-UpperBounds-Null
As an example, the following Kotlin class:
class Sample(val foo: NonEmptySet<Int>) { }
results in a class file such as:
public final class Sample {
private final java.util.Set<A> foo;
}
The type variable A is not defined anywhere which results in the argument to ParameterizedTypeImpl (https://github.com/openjdk/jdk/blob/034297a6bd9bfcea7fa48792f54c84a6e976b319/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/ParameterizedTypeImpl.java#L43) to be an array containing `null`. This is not normally expected by users, triggering an obscure error message through the null pointer which is also sometimes shown without a stack trace.
To me it seems like there was an attempt to validate such a missing definition later in the constructor, but this was possibly forgotten, given that the loop has an empty body? (https://github.com/openjdk/jdk/blob/034297a6bd9bfcea7fa48792f54c84a6e976b319/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/ParameterizedTypeImpl.java#L65)
I suggest that a generic type definition should produce an invalid value that throws a MalformedParameterizedTypeException upon resolution. The exception can either be thrown upon construction in the now empty loop. Alternatively, CoreReflectionFactory#findTypeVariable could return an instance of TypeVariable that still provides the name of the type variable, but throws an exception when the bounds or declaring type of the variable are attempted to be resolved. This would provide some value if the particular type argument to a parameterized type is not of interest.
I am happy to provide a fix and a unit test if I get an opinion on which of these two behaviors is prefered. In case that a NullPointerException is the desired behavior, where I would argue that this should be documented in the javadoc. Personally, I do not find this intuitive however. Note that this problem also occurs when one generates a faulty field such as:
public final class Sample {
private final A foo;
}
with A being a type variable. This would also indicate that this should be handled in CoreReflectionFactory#findTypeVariable.
As an example, the following Kotlin class:
class Sample(val foo: NonEmptySet<Int>) { }
results in a class file such as:
public final class Sample {
private final java.util.Set<A> foo;
}
The type variable A is not defined anywhere which results in the argument to ParameterizedTypeImpl (https://github.com/openjdk/jdk/blob/034297a6bd9bfcea7fa48792f54c84a6e976b319/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/ParameterizedTypeImpl.java#L43) to be an array containing `null`. This is not normally expected by users, triggering an obscure error message through the null pointer which is also sometimes shown without a stack trace.
To me it seems like there was an attempt to validate such a missing definition later in the constructor, but this was possibly forgotten, given that the loop has an empty body? (https://github.com/openjdk/jdk/blob/034297a6bd9bfcea7fa48792f54c84a6e976b319/src/java.base/share/classes/sun/reflect/generics/reflectiveObjects/ParameterizedTypeImpl.java#L65)
I suggest that a generic type definition should produce an invalid value that throws a MalformedParameterizedTypeException upon resolution. The exception can either be thrown upon construction in the now empty loop. Alternatively, CoreReflectionFactory#findTypeVariable could return an instance of TypeVariable that still provides the name of the type variable, but throws an exception when the bounds or declaring type of the variable are attempted to be resolved. This would provide some value if the particular type argument to a parameterized type is not of interest.
I am happy to provide a fix and a unit test if I get an opinion on which of these two behaviors is prefered. In case that a NullPointerException is the desired behavior, where I would argue that this should be documented in the javadoc. Personally, I do not find this intuitive however. Note that this problem also occurs when one generates a faulty field such as:
public final class Sample {
private final A foo;
}
with A being a type variable. This would also indicate that this should be handled in CoreReflectionFactory#findTypeVariable.
Attachments
Issue Links
- csr for
-
JDK-8338198 Undefined type variables now cause TypeNotPresentException
- Closed
- links to
-
Review(master) openjdk/jdk/20535