如果我有这样一个类:
public class Whatever
{
public void aMethod(int aParam);
}
有没有办法知道, aMethod
使用名为参数aParam
,即类型int
?
如果我有这样一个类:
public class Whatever
{
public void aMethod(int aParam);
}
有没有办法知道, aMethod
使用名为参数aParam
,即类型int
?
总结:
method.getParameterTypes()
对于编写自动填充功能的编辑器(如你在一个评论说)的缘故,有几个选项:
arg0
, arg1
, arg2
等。 intParam
, stringParam
, objectTypeParam
等。 在Java 8,你可以做到以下几点:
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
public final class Methods {
public static List<String> getParameterNames(Method method) {
Parameter[] parameters = method.getParameters();
List<String> parameterNames = new ArrayList<>();
for (Parameter parameter : parameters) {
if(!parameter.isNamePresent()) {
throw new IllegalArgumentException("Parameter names are not present!");
}
String parameterName = parameter.getName();
parameterNames.add(parameterName);
}
return parameterNames;
}
private Methods(){}
}
因此,对于你的类Whatever
我们可以做一个手工测试:
import java.lang.reflect.Method;
public class ManualTest {
public static void main(String[] args) {
Method[] declaredMethods = Whatever.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
if (declaredMethod.getName().equals("aMethod")) {
System.out.println(Methods.getParameterNames(declaredMethod));
break;
}
}
}
}
这应该打印[aParam]
如果你已经通过-parameters
参数到Java编译器8。
对于Maven用户:
<properties>
<!-- PLUGIN VERSIONS -->
<maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
<!-- OTHER PROPERTIES -->
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<!-- Original answer -->
<compilerArgument>-parameters</compilerArgument>
<!-- Or, if you use the plugin version >= 3.6.2 -->
<parameters>true</parameters>
<testCompilerArgument>-parameters</testCompilerArgument>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
欲了解更多信息,请参阅以下链接:
该Paranamer库的建立是为了解决这个同样的问题。
它试图确定在几个不同的方式方法名。 如果类与调试编译它可以通过读取类的字节码提取信息。
另一种方式是,它是编译后的私人静态成员注入类的字节码,但它被放置在一个罐子里了。 然后,它使用反射来提取的类别在运行时,这个信息。
https://github.com/paul-hammant/paranamer
我不得不使用这个库的问题,但我没有得到它到底工作。 我希望报告问题的维护者。
是。
必须对代码进行编译与Java兼容8编译器选项来存储形式参数名称开启(α参数选项)。
然后,此代码段应工作:
Class<String> clz = String.class;
for (Method m : clz.getDeclaredMethods()) {
System.err.println(m.getName());
for (Parameter p : m.getParameters()) {
System.err.println(" " + p.getName());
}
}
看到org.springframework.core.DefaultParameterNameDiscoverer类
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
String[] params = discoverer.getParameterNames(MathUtils.class.getMethod("isPrime", Integer.class));
您可以使用反射检索方法和检测它的参数类型。 检查http://java.sun.com/j2se/1.4.2/docs/api/java/lang/reflect/Method.html#getParameterTypes%28%29
但是,你不能告诉使用的参数的名称。
这是可能和Spring MVC 3做的,但我并没有花时间去看看到底怎么样。
如果您的代码启用调试编译方法参数名URI模板变量名的匹配才能完成。 如果你还没有启用调试,则必须在@PathVariable注释,以变量名的解析值绑定到方法参数指定URI模板变量名的名称。 例如:
摘自春天文档
虽然这是不可能的(如其他人所示),你可以使用注释来结转参数名,并获得,虽然反映。
不干净的解决方案,但它能够完成任务。 一些web服务真正做到这一点,以保持参数名称(即:部署的WS在GlassFish)。
见java.beans.ConstructorProperties ,它的设计正是这种做注解。
所以,你应该能够做到:
Whatever.declaredMethods
.find { it.name == 'aMethod' }
.parameters
.collect { "$it.type : $it.name" }
但是,你可能会得到像这样的列表:
["int : arg0"]
我相信,这将是固定在Groovy 2.5+
所以目前,答案是:
也可以看看:
对于每一个方法,则是这样的:
Whatever.declaredMethods
.findAll { !it.synthetic }
.collect { method ->
println method
method.name + " -> " + method.parameters.collect { "[$it.type : $it.name]" }.join(';')
}
.each {
println it
}
如果你用的是eclipse,看到波纹图像,让编译器来存储方法的参数信息
参数名称是只对编译器非常有用。 当编译器生成一个类文件,该参数名称不包括 - 一个方法的参数列表中只包括它的参数的数量和种类。 因此,这将是不可能恢复使用反射(如标记你的问题)参数名称 - 它不存在任何地方。
但是,如果使用反射不是硬性要求,你可以检索直接从源代码信息(假设有的话)。
要添加我的2美分; 参数信息是在一个类文件中提供“用于调试”当你使用javac -g来编译源。 而且它是提供给APT但你需要一个注解所以没有用的你。 (有人讨论类似的4 - 5年前在这里: http://forums.java.net/jive/thread.jspa?messageID=13467&tstart=0 )
整体而言,在短,除非你在源工作,你不能让它直接文件(类似于在编译时做什么APT)。
作为@Bozho说,这是可能的,如果在编译过程中包含调试信息,以做到这一点。 这里有一个很好的答案...
如何获得对象的构造函数(反射)的参数名称? 通过@AdamPaynter
使用... ASM库。 我放在一起展示如何实现自己的目标的例子。
首先,开始与这些依赖一个pom.xml。
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-all</artifactId>
<version>5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
然后,这个类应该做你想要什么。 只需调用静态方法getParameterNames()
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodNode;
public class ArgumentReflection {
/**
* Returns a list containing one parameter name for each argument accepted
* by the given constructor. If the class was compiled with debugging
* symbols, the parameter names will match those provided in the Java source
* code. Otherwise, a generic "arg" parameter name is generated ("arg0" for
* the first argument, "arg1" for the second...).
*
* This method relies on the constructor's class loader to locate the
* bytecode resource that defined its class.
*
* @param theMethod
* @return
* @throws IOException
*/
public static List<String> getParameterNames(Method theMethod) throws IOException {
Class<?> declaringClass = theMethod.getDeclaringClass();
ClassLoader declaringClassLoader = declaringClass.getClassLoader();
Type declaringType = Type.getType(declaringClass);
String constructorDescriptor = Type.getMethodDescriptor(theMethod);
String url = declaringType.getInternalName() + ".class";
InputStream classFileInputStream = declaringClassLoader.getResourceAsStream(url);
if (classFileInputStream == null) {
throw new IllegalArgumentException(
"The constructor's class loader cannot find the bytecode that defined the constructor's class (URL: "
+ url + ")");
}
ClassNode classNode;
try {
classNode = new ClassNode();
ClassReader classReader = new ClassReader(classFileInputStream);
classReader.accept(classNode, 0);
} finally {
classFileInputStream.close();
}
@SuppressWarnings("unchecked")
List<MethodNode> methods = classNode.methods;
for (MethodNode method : methods) {
if (method.name.equals(theMethod.getName()) && method.desc.equals(constructorDescriptor)) {
Type[] argumentTypes = Type.getArgumentTypes(method.desc);
List<String> parameterNames = new ArrayList<String>(argumentTypes.length);
@SuppressWarnings("unchecked")
List<LocalVariableNode> localVariables = method.localVariables;
for (int i = 1; i <= argumentTypes.length; i++) {
// The first local variable actually represents the "this"
// object if the method is not static!
parameterNames.add(localVariables.get(i).name);
}
return parameterNames;
}
}
return null;
}
}
下面是与一个单元测试的例子。
public class ArgumentReflectionTest {
@Test
public void shouldExtractTheNamesOfTheParameters3() throws NoSuchMethodException, SecurityException, IOException {
List<String> parameterNames = ArgumentReflection
.getParameterNames(Clazz.class.getMethod("callMe", String.class, String.class));
assertEquals("firstName", parameterNames.get(0));
assertEquals("lastName", parameterNames.get(1));
assertEquals(2, parameterNames.size());
}
public static final class Clazz {
public void callMe(String firstName, String lastName) {
}
}
}
你可以找到完整的示例GitHub上
static
方法。 这是becasue在这种情况下,由ASM返回参数的数量是不同的,但它的东西,可以很容易地固定。