JDK-8215530 : NPE initializing ParameterizedType in lambda expression
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 8,11,12
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: x86_64
  • Submitted: 2018-12-17
  • Updated: 2018-12-18
  • Resolved: 2018-12-18
Related Reports
Duplicate :  
Description
A DESCRIPTION OF THE PROBLEM :
This is tangentially related to JDK-8215470: "Bad EnclosingMethod attribute on classes declared in lambdas".

When the generic signature on a class contains type variables that are out of scope, the parser/reifier facilities supporting java.lang.reflect allow 'null' type references to propagate silently.  This, in turn, causes ancillary effects like various toString() implementations throwing a NPE, e.g., GenericArrayType::toString() and ParameterizedType::toString().

It is debatable what the correct behavior should be when a type variable cannot be resolved, but at minimum, none of the toString() methods should be throwing a NPE.

The documentation for ParameterizedType suggests that getActualTypeArguments() should throw a TypeNotPresentException when "any of the actual type arguments refers to a non-existent type declaration".  That would seem to cover the case where a type variable is not in scope, but the current implementation does not throw such an exception (apparently, under *any* circumstances).  Similarly, GenericArrayType::getGenericComponentType() is documented as throwing a TypeNotPresentException when "the underlying array type's component type refers to a non-existent type declaration", but this seemingly never happens.

I would propose that methods documented to throw a TypeNotPresentException be updated to actually do so in cases of type resolution failure.  Further, I propose that the various toString() methods fill in the canonical name of any unresolved types (for type variables, the simple name) rather than throwing an exception.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run attached "source code for an executable test case".  Compare the output to that described under "expected result".

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Expected output:

ReflectBug<T>
ReflectBug<T[]>
ACTUAL -
Actual output:

java.lang.NullPointerException
        at java.base/sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.toString(ParameterizedTypeImpl.java:229)
        at java.base/java.lang.String.valueOf(String.java:2951)
        at java.base/java.io.PrintStream.println(PrintStream.java:897)
        at j.l.r.bugs.ReflectBug.<init>(Unknown Source)
        at j.l.r.bugs.ReflectBug$2.<init>(Unknown Source)
        at j.l.r.bugs.ReflectBug.lambda$test$0(Unknown Source)
        at j.l.r.bugs.ReflectBug.test(Unknown Source)
        at j.l.r.bugs.ReflectBug.main(Unknown Source)
java.lang.NullPointerException
        at java.base/sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl.toString(GenericArrayTypeImpl.java:68)
        at java.base/java.lang.reflect.Type.getTypeName(Type.java:46)
        at java.base/sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.toString(ParameterizedTypeImpl.java:229)
        at java.base/java.lang.String.valueOf(String.java:2951)
        at java.base/java.io.PrintStream.println(PrintStream.java:897)
        at j.l.r.bugs.ReflectBug.<init>(Unknown Source)
        at j.l.r.bugs.ReflectBug$3.<init>(Unknown Source)
        at j.l.r.bugs.ReflectBug.lambda$test$0(Unknown Source)
        at j.l.r.bugs.ReflectBug.test(Unknown Source)
        at j.l.r.bugs.ReflectBug.main(Unknown Source)


---------- BEGIN SOURCE ----------
class ReflectBug<T> {
    protected ReflectBug() {
        try {
            System.out.println(this.getClass().getGenericSuperclass());
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

    static <X> void test() {
        Runnable r = () -> {
            new ReflectBug<X>() {};
            new ReflectBug<X[]>() {};
        };
        r.run();
    }

    public static void main(final String[] args) {
        test();
    }
}

---------- END SOURCE ----------

FREQUENCY : always



Comments
Closing this as duplicate of JDK-8215328, which is recently reported by another submitter in JDK 11.
18-12-2018