前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java获取函数参数名称的另一种方法

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

作者头像
10km
发布2019-05-25 21:49:05
8520
发布2019-05-25 21:49:05
举报
文章被收录于专栏:10km的专栏10km的专栏

版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433555

关于获取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

代码语言:javascript
复制
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

调用示例:

代码语言:javascript
复制
    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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年02月11日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档