Java获取函数参数名称的另一种方法

版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/79308845

关于获取java 方法的参数名(这里指java 1.8以前的版本,java 1.8已经提供了相关的原生方法),网上可以找到不少文章,这篇文章讲得比较全面了:《Java获取函数参数名称的几种方法》,无外乎是借用asm,javasist等第三方库。

我的项目中也有此需求,看了这篇文章还是觉得比较麻烦,为了这个小小的需求,要多引入一系列依赖库,有点不划算。

我对axis2比较熟悉,知道axis2中在生成client代码时也需要获取方法的参数名,于是通过分析源码找到了axis2的实现代码。 axis2获取java参数名的实现代码的package为org.apache.axis2.description.java2wsdl.bytecode,在axis2核心jar包axis2-kernel-1.6.2.jar中(源码下载地址:axis2-kernel-1.6.2-sources.jar) 好就好在这个package没有引用package之外的代码,所以可以单独提取出来独立调用。

于是我把这部分代码单独复制出来(完整代码参见gitee仓库: https://gitee.com/l0km/common-java/tree/master/common-base/src/main/java/org/apache/bytecode),并在此基础上封装了一个类ParameterNames,方便调用:

ParameterNames.java

package net.gdface.utils;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import net.gdface.utils.Assert;

import org.apache.bytecode.ChainedParamReader;

/**
 * 获取构造函数或方法的参数名<br>
 * 当不能获取参数名的情况下,
 * {@link returnFakeNameIfFail}为{@code false}时返回{@code null},否则返回返回arg,arg2...格式的替代名<br>
 * {@link returnFakeNameIfFail}默认为{@code true}
 * @author guyadong
 *
 */
public class ParameterNames {
    private final Map<Class<?>, ChainedParamReader> readers = new HashMap<Class<?>, ChainedParamReader>();
    private final Class<?> clazz;
    /** 当获取无法参数名时是否返回arg,arg2...格式的替代名字 */
    private boolean returnFakeNameIfFail = true;
    public ParameterNames setReturnFakeNameIfFail(boolean returnFakeNameIfFail) {
        this.returnFakeNameIfFail = returnFakeNameIfFail;
        return this;
    }

    /**
     * @param clazz 要构造函数或方法的参数名的类,为{@code null}时所有getParameterNames方法返回{@code null}
     */
    public ParameterNames(Class<?> clazz) {
        this.clazz = clazz;
        if(null != clazz){
            try {
                Class<?> c = clazz;
                do {
                    readers.put(c, new ChainedParamReader(c));
                } while (null != (c = c.getSuperclass()));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 获取构造函数或方法的参数名
     * @param reader
     * @param member 构造函数或方法对象
     * @return
     */
    private final String[] getParameterNames(ChainedParamReader reader, Member member) {
        String [] parameterNames = null;
        int paramCount ;
        if (member instanceof Method){
            parameterNames = reader.getParameterNames((Method) member);
            paramCount = ((Method) member).getParameterTypes().length;
        } else if (member instanceof Constructor){
            parameterNames = reader.getParameterNames((Constructor<?>) member);
            paramCount = ((Constructor<?>) member).getParameterTypes().length;
        } else {
            throw new IllegalArgumentException("member type must be Method or Constructor");
        }
        if(this.returnFakeNameIfFail){
            if (null == parameterNames) {
                parameterNames = new String[paramCount];
                for (int i = 0; i < parameterNames.length; i++)
                    parameterNames[i] = String.format("arg%d", i);
            }
        }
        return parameterNames;
    }

    /**
     * 获取构造函数或方法的参数名
     * @param member 构造函数或方法对象
     * @return
     * @see #getParameterNames(ChainedParamReader, Member)
     */
    public final String[] getParameterNames(Member member) {
        if(null == clazz){
            return null;
        }
        Assert.notNull(member, "member");
        Class<?> declaringClass = member.getDeclaringClass();
        ChainedParamReader reader;
        if (null == (reader = readers.get(declaringClass))) {
            throw new IllegalArgumentException(String.format("%s is not member of %s", member.toString(),
                    declaringClass.getName()));
        }
        return getParameterNames(reader, member);
    }

    /**
     * 获取构造函数或方法的参数名<br>
     * {@code name}为{@code null}时,获取构造函数的参数名
     * @param name 方法名
     * @param parameterTypes 构造函数或方法的参数类型
     * @return
     * @throws NoSuchMethodException
     * @see #getParameterNames(String, Class)
     */
    public final String[] getParameterNames(String name, Class<?>[] parameterTypes) throws NoSuchMethodException {
        if(null == clazz){
            return null;
        }
        try {
            Member member = null == name ? clazz.getConstructor(parameterTypes) : clazz.getMethod(name, parameterTypes);
            return getParameterNames(member);
        } catch (SecurityException e) {
            throw new IllegalArgumentException(e);
        }
    }
}

完整代码参见gitee仓库:https://gitee.com/l0km/common-java/blob/master/common-base/src/main/java/net/gdface/utils/ParameterNames.java

调用示例:

    private static void outputParameterNames(Method method){
        // 抽象方法不能正确获取参数名,只能用假名替代
        System.out.printf("%s abstract = %b\n parameter names:",
                method.getName(),
                Modifier.isAbstract(method.getModifiers()));
        ParameterNames pt = new ParameterNames(method.getDeclaringClass());
        String[] names = pt.getParameterNames(method);
        for(String name:names){
            System.out.print(name + ",");
        }
        System.out.println();
    }

完整的代码参见gitee仓库: https://gitee.com/l0km/common-java/blob/master/common-base/src/test/java/net/gdface/common/ClassTest.java

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券