JDK-8257078 : getActualTypeArguments returns array with null values for older Java versions
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 13
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • Submitted: 2020-11-24
  • Updated: 2020-12-02
  • Resolved: 2020-12-02
Related Reports
Relates :  
Description
ADDITIONAL SYSTEM INFORMATION :
Linux 5.4.74-1-MANJARO #1 SMP PREEMPT Sun Nov 1 13:43:13 UTC 2020 x86_64 GNU/Linux
OpenJDK 8-15, Oracle JDK 11.0.9, Oracle JDK 15.0.1
Default configuration
Dependencies: java.lang.reflect.ParameterizedType, java.lang.reflect.Type


A DESCRIPTION OF THE PROBLEM :
Description of the bug can be found at https://github.com/albsch/java_types_matrix

For Java versions <13 getActualTypeArguments returns an array filled with null values.
This causes different java versions to have different semantics for the same source file (see attached code).


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Put the source code of the two classes into the test folder

Compile classes with Java 8-12 (javac test/*.java)
Run with Java 8-12, throws Exception (java test.Main)
Compile classes with Java 13-15 (javac test/*.java)
Run with Java 13-15, does not throw Exception (java test.Main)

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Same result for all supported Java version (either no exception thrown or exception thrown)
ACTUAL -
Different evaluation of java source code depending on java version
Java 8-13: exception thrown (actualTypeArguments array is filled with null values)
Java 13-15: No exception thrown (actualTypeArguments array is not filled with null values)

---------- BEGIN SOURCE ----------
Main class:
---

package test;
import test.T;
public class Main {
  public static void main(String[] args) { run(); }

  public static <A> void run() {
    Runnable r = () -> {
        T<A> t = new T<A>(){};
        if(t.type == null) throw new IllegalStateException();
    };
    r.run();
  }
}



Token class:
---
package test;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public abstract class T<X> {

    public final Type type;

    public T() {
        this.type = resolveType();
    }

    // this resolves and saves the type with generics at runtime
    public Type resolveType() {
        final Type genericSuperclass = getClass().getGenericSuperclass();
        final ParameterizedType parameterizedGenericSuperclass = (ParameterizedType) genericSuperclass;
        final Type[] actualTypeArguments = parameterizedGenericSuperclass.getActualTypeArguments();
        return actualTypeArguments[0];
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No workaround found.

FREQUENCY : always



Comments
Closing this as the new behaviour is correct.
02-12-2020

Additional Information from submitter: =========================== Might be related to https://bugs.openjdk.java.net/browse/JDK-8213465?jql=text%20~%20%22getActualTypeArguments%22
01-12-2020

I believe this is intentional and fixed by JDK-8215470 included in Java 13. Note that in the test provided the resolution of generic superclass occurs within a lambda, which is something that JDK-8215470 mentions: "A particularly vexing side effect of this occurs when the generic signature of a lambda-embedded inner type contains type variables declared by the lexically enclosing method. Those type variables will be out of scope from the perspective of the method identified by the `EnclosingMethod` attribute. Consequently, the `java.lang.reflect` APIs cannot resolve them." Looking at the provided test with javap ("% javap -v Main\$1.class") verifies that that the EnclosingMethod attribute changes when compiled with 13. Also, compiling with Java 13 --release 12 and running with Java 12 gives the successful outcome implying this is a compiler change. [~tongwan] This should be closed as not a bug.
30-11-2020

This might be an intentional change, moving across to JDK for further evaluation.
25-11-2020