Answers:
总结一下:
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
我在使用该库时遇到了问题,但最终还是可以使它正常工作。我希望将这些问题报告给维护人员。
ParameterNAmesNotFoundException
参见org.springframework.core.DefaultParameterNameDiscoverer类
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
String[] params = discoverer.getParameterNames(MathUtils.class.getMethod("isPrime", Integer.class));
是。必须使用兼容Java 8的编译器来编译
代码,并带有用于存储形式参数名称的选项(-parameters选项)。
然后,此代码段应该工作:
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());
}
}
您可以使用反射检索方法并检测其参数类型。检查http://java.sun.com/j2se/1.4.2/docs/api/java/lang/reflect/Method.html#getParameterTypes%28%29
但是,您不能说出所使用参数的名称。
Spring MVC 3可以做到这一点,但是我没有花时间去看确切的方法。
方法参数名称与URI模板变量名称的匹配只能在您的代码启用调试的情况下进行编译。如果未启用调试,则必须在@PathVariable批注中指定URI模板变量名称的名称,以便将变量名称的解析值绑定到方法参数。例如:
摘自Spring文档
请参阅java.beans.ConstructorProperties,这是一个为完成此操作而设计的注释。
因此,您应该能够:
Whatever.declaredMethods
.find { it.name == 'aMethod' }
.parameters
.collect { "$it.type : $it.name" }
但是您可能会得到如下列表:
["int : arg0"]
因此,目前的答案是:
也可以看看:
对于每种方法,则类似于:
Whatever.declaredMethods
.findAll { !it.synthetic }
.collect { method ->
println method
method.name + " -> " + method.parameters.collect { "[$it.type : $it.name]" }.join(';')
}
.each {
println it
}
aMethod
。我想为一个类中的所有方法获取它。
antlr
用来获取参数名称吗?
如@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>
然后,该课程应做您想要的。只需调用static方法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
方法。这是因为在这种情况下,ASM返回的参数数量有所不同,但这很容易解决。参数名称仅对编译器有用。编译器生成类文件时,不包括参数名称-方法的参数列表仅由其参数的数量和类型组成。因此,不可能使用反射(如您的问题中标记的那样)检索参数名称-它在任何地方都不存在。
但是,如果不是很需要使用反射,则可以直接从源代码中检索此信息(假设您已掌握)。
Parameter names are only useful to the compiler.
错误。查看翻新库。它使用动态接口来创建REST API请求。它的功能之一是能够在URL路径中定义占位符名称,并将这些占位符替换为其相应的参数名称。
再加上我的2美分;当您使用javac -g编译源代码时,参数信息在类文件“用于调试”中可用。它对APT可用,但是您需要一个注释,因此对您没有用。(有人在4-5年前在这里讨论过类似的内容:http : //forums.java.net/jive/thread.jspa?messageID=13467&tstart=0)
总的来说,除非直接处理源文件(类似于APT在编译时所做的工作),否则您将无法获得它。