版权声明:本文为博主原创文章,转载请注明源地址。 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
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仓库: