-1

I am using the BCEL library to analyze some code. I came across a method (getAllNames()) whose return type is List< Name >. I want to be able to obtain the return type of this method.

I want to be able to obtain the full class of "Name".

I have tried using the < Instruction.getReturnType() > method in my method visitor class but for this specific method I get the result "java.util.List". I want the generic type "com.instant.Name" instead.

The signature for the method is like so:

public List<Name> getAllNames() {
...
}

I also have a org.apache.bcel.generic.MethodGen object that I create before visiting the method using org.apache.bcel.classfile.Method

When I try to get return type it again gives "java.util.List"

I expect the output of MethodGen.getReturnType() to be "com.instant.Name" but the actual output is "java.util.List"

Brian
  • 5,064
  • 7
  • 33
  • 44
user161733
  • 21
  • 5
  • You will not be able to get it as Generics are available only during the compile time. They are erased and the information is not available in byte code. The information will be made available after Project Valhalla is implemented and released. https://openjdk.java.net/projects/valhalla/ – Abhijith Nagarajan May 08 '19 at 22:52
  • This will give you the reason https://stackoverflow.com/questions/339699/java-generics-type-erasure-when-and-what-happens – Jimmy May 08 '19 at 22:57
  • this may give you a start. Assuming you are using reflection, where field is the list/arraylist (or other collection) object, this may be of some use `field.getAnnotatedType().getType()`. If viewed in the object inspector during runtime, you will see a collection which includes the _generic_ class type. Using full reflection (to the furtherest extent), use `field.getAnnotatedType().getType().getClass().getDeclaredField("actualTypeArguments")`. I hope it can be of some use to you. – CybeX May 08 '19 at 23:04

1 Answers1

0

Contrary to some comments the information is obviously there, type erasure does not happen on the interface level - just as Eclipse/NetBeans/IntelliJ/etc. can get the exact type/return type of class members, you can do that too:

public class Name {
  public List<Name> getAllNames(){return null;}

  public static void main(String[] args) throws Exception {
    Method m=Name.class.getMethod("getAllNames");
    ParameterizedType pt=(ParameterizedType)m.getGenericReturnType();
    System.out.println(pt.getActualTypeArguments()[0]);
  }
}

BCEL is another story, I am not familiar with it, however the very end of FieldOrMethod.java, there is a method called getGenericSignature(). You may find it useful already (though presumably it produces a signature), or you can replicate the loop inside, over the attributes (you can get them via getAttributes()), checking for an occurrence of instanceof Signature:

Attribute a[]=m.getAttributes(); // where is the org.apache.bcel.classfile.Method you have
for(int i=0;i<a.length;i++)
  if(a[i] instanceof Signature)
    System.out.println(a[i]); // this is just a test of course.

The real code suggests that there can be only one such attribute and the loop could exit afterwards, but it made me think about types having multiple parameters, like Map-s...
getGenericSignature() itself does not occur anywhere else (neither tested, nor used), so I can only hope that it (and consequently, the approach described above) really works.

tevemadar
  • 9,697
  • 2
  • 15
  • 36