The following test tries to get the type parameters <T, U, V> of the generic constructor declaration of a class:
1 import java.io.PrintStream;
2 import java.lang.reflect.Constructor;
3 import java.lang.reflect.TypeVariable;
4
5 class GetTypeParametersTest {
6 public <T, U, V> GetTypeParametersTest(T n, U m) {
7 }
8 }
9
10 public class Main {
11 public static void main(String[] args) {
12 try {
13 Class cls = Class.forName("GetTypeParametersTest");
14 Constructor c = cls.getConstructor(Object.class, Object.class);
15 System.out.println(c.toString());
16 TypeVariable[] tv = c.getTypeParameters();
17 System.out.println("Number of type parameters: " + tv.length + ", expected: 3");
18 if (tv.length == 3) {
19 System.out.println("<" + tv[0].toString() + ", " + tv[1].toString() + ", " + tv[2].toString() + ">");
20 }
21 } catch (ClassNotFoundException e1) {
22 System.err.println(e1);
23 } catch (NoSuchMethodException e2) {
24 System.err.println(e2);
25 }
26 }
27 }
The expected output is:
public GetTypeParametersTest(java.lang.Object,java.lang.Object)
Number of type parameters: 3, expected: 3
<T, U, V>
But the program got segfault at getTypeParameters().
The problem with the compiler is that the signature of formal type parameters portion of the constructor <T:Ljava/lang/Object;U:Ljava/lang/Object;V:Ljava/lang/Object;>
is not generated. Without this, getTypeParameters() will not be functional at runtime since there is no information about the type parameters declaration of the constructor.
Here is the related portion of the code generated by jbc2mpl in Main.mpl:
func &LGetTypeParametersTest_3B_7C_3Cinit_3E_7C_28Ljava_2Flang_2FObject_3BLjava_2Flang_2FObject_3B_29V public constructor (var %_this <* <$LGetTypeParametersTest_3B>>, var %Reg2_R40 <* <$Ljava_2Flang_2FObject_3B>>, var %Reg3_R40 <* <$Ljava_2Flang_2FObject_3B>>) void {
funcid 181046
var %Reg1_R164188 <* <$LGetTypeParametersTest_3B>>
var %Reg0_R164188 <* <$LGetTypeParametersTest_3B>>
var %Reg0_R40 <* <$Ljava_2Flang_2FObject_3B>>
ALIAS %m %Reg3_R40 <* <$Ljava_2Flang_2FObject_3B>> "TU;"
ALIAS %n %Reg2_R40 <* <$Ljava_2Flang_2FObject_3B>> "TT;"
dassign %Reg1_R164188 0 (dread ref %_this)
#LINE Main.java : 6, INSTIDX : 0||0000: aload_0
LOC 1 6
dassign %Reg0_R164188 0 (dread ref %Reg1_R164188)
#LINE Main.java : 6, INSTIDX : 1||0001: invokespecial
dassign %Reg0_R40 0 (retype ref <* <$Ljava_2Flang_2FObject_3B>> (dread ref %Reg0_R164188))
callassigned &Ljava_2Flang_2FObject_3B_7C_3Cinit_3E_7C_28_29V (dread ref %Reg0_R40) {}
#LINE Main.java : 7, INSTIDX : 4||0004: return
LOC 1 7
return ()
}
Corresponding portion in Main.irb.tmpl:
type $LGetTypeParametersTest_3B <class <$Ljava_2Flang_2FObject_3B> {
@INFO_srcfile "Main.java",
@INFO_classname "LGetTypeParametersTest_3B",
@INFO_classnameorig "LGetTypeParametersTest;",
@INFO_superclassname "Ljava_2Flang_2FObject_3B",
@INFO_attribute_string " ",
@INFO_access_flags 32,
&LGetTypeParametersTest_3B_7C_3Cinit_3E_7C_28Ljava_2Flang_2FObject_3BLjava_2Flang_2FObject_3B_29V public constructor (<* <$LGetTypeParametersTest_3B>>,<* <$Ljava_2Flang_2FObject_3B>>,<* <$Ljava_2Flang_2FObject_3B>>) void}>
In these file, there is no information found about the formal type parameters declaration <T, U, V>, or its signature <T:Ljava/lang/Object;U:Ljava/lang/Object;V:Ljava/lang/Object;>
which is expected to be passed to the runtime.
This problem exists with generic methods as well.