使用ASM獲得JAVA類方法參數名


在Java1.8之后,可以通過反射API java.lang.reflect.Executable.getParameters來獲取到方法參數的元信息,
(在使用編譯器時加上-parameters參數,它會在生成的.class文件中額外存儲參數的元信息)
但是在JDK1.7及以下版本的API並不能獲取到函數的參數名稱,這時候可以使用字節碼工具ASM來實現這一功能.

package yyl.example.demo.asm;

import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;

/**
 * 使用ASM獲得JAVA類方法參數名
 */
public class GetMethodParamNameTest {

    static class Test {
        void method(String name, Object value) {
        }
    }

    public static void main(String[] args) throws SecurityException, NoSuchMethodException, IOException {
        Method method1 = Test.class.getDeclaredMethod("method", String.class, Object.class);
       System.out.println(Arrays.toString(getMethodParamNames(method)));
    }
/** 使用字節碼工具ASM來獲取方法的參數名 */
    public static String[] getMethodParamNames(final Method method) throws IOException {

        final String methodName = method.getName();
        final Class<?>[] methodParameterTypes = method.getParameterTypes();
        final int methodParameterCount = methodParameterTypes.length;
        final String className = method.getDeclaringClass().getName();
        final boolean isStatic = Modifier.isStatic(method.getModifiers());
        final String[] methodParametersNames = new String[methodParameterCount];

        ClassReader cr = new ClassReader(className);
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        cr.accept(new ClassAdapter(cw) {
            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {

                MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);

                final Type[] argTypes = Type.getArgumentTypes(desc);

                //參數類型不一致
                if (!methodName.equals(name) || !matchTypes(argTypes, methodParameterTypes)) {
                    return mv;
                }
                return new MethodAdapter(mv) {
                    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
                        //如果是靜態方法,第一個參數就是方法參數,非靜態方法,則第一個參數是 this ,然后才是方法的參數
                        int methodParameterIndex = isStatic ? index : index - 1;
                        if (0 <= methodParameterIndex && methodParameterIndex < methodParameterCount) {
                            methodParametersNames[methodParameterIndex] = name;
                        }
                        super.visitLocalVariable(name, desc, signature, start, end, index);
                    }
                };
            }
        }, 0);
        return methodParametersNames;
    }

    /**
     * 比較參數是否一致
     */
    private static boolean matchTypes(Type[] types, Class<?>[] parameterTypes) {
        if (types.length != parameterTypes.length) {
            return false;
        }
        for (int i = 0; i < types.length; i++) {
            if (!Type.getType(parameterTypes[i]).equals(types[i])) {
                return false;
            }
        }
        return true;
    }

}

 

備注:JDK 自帶類 ,接口方法和抽象方法無法使用這種方式獲取參數名


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM