Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i get the `signature` field of java reflection Method object

i'm using ASM to build class file base on another Interface , i could use java reflection to get methods of the Interface , but i need to get the signature of it . enter image description here

i found it's a private field , and there's no direct method to get it . is there any way out ? i use jdk7 . tks advance .

like image 990
Adams.H Avatar asked Oct 17 '25 00:10

Adams.H


2 Answers

If all you want is the signature field of java.lang.reflect.Method, that's simple:

java.lang.reflect.Field f = java.lang.reflect.Method.class.getDeclaredField("signature");
f.setAccessible(true);
String sigature = f.get(yourMethod);

Where yourMethod is a Method object.

Keep in mind: The signature field simply denotes the signature of a generic method, so attempting to get the signature of a non-generic method will simply return null.

For example, let's assess the following method:

public static <T> void test(Class<T> c){}

This will return a signature of <T:Ljava/lang/Object;>(Ljava/lang/Class<TT;>;)V

This shows that the method declares one generic type that must at least inherit java.lang.Object and takes a class of that type as a parameter.

But, say we were to remove the generic from the method:

public static void test(Class c){}

This would result in the signature field being null.

Edit:

If you want to get the signature of any method (generic or not), there are a couple of ways to do it, but I find the following to be the most concise (although possibly clunky):

public static String getSignature(Method m){
    String sig;
    try {
        Field gSig = Method.class.getDeclaredField("signature");
        gSig.setAccessible(true);
        sig = (String) gSig.get(m);
        if(sig!=null) return sig;
    } catch (IllegalAccessException | NoSuchFieldException e) { 
        e.printStackTrace();
    }

    StringBuilder sb = new StringBuilder("(");
    for(Class<?> c : m.getParameterTypes()) 
        sb.append((sig=Array.newInstance(c, 0).toString())
            .substring(1, sig.indexOf('@')));
    return sb.append(')')
        .append(
            m.getReturnType()==void.class?"V":
            (sig=Array.newInstance(m.getReturnType(), 0).toString()).substring(1, sig.indexOf('@'))
        )
        .toString();
}
like image 88
Gabriel Tofvesson Avatar answered Oct 18 '25 13:10

Gabriel Tofvesson


Replacing '.' with '/' makes Gabriel Tofvesson's answer complete:

... .toString().replace('.', '/');

Otherwise, the signature returned would be something like ()Ljava.lang.Object;. However, in signatures, the package names must be separated using slashes instead of periods: ()Ljava/lang/Object;.

like image 42
Jan Avatar answered Oct 18 '25 13:10

Jan