0%

Method Parameter Reflection in Java

在Java8中,可以使用 java.lang.reflect.Executable.getParameters 获取方法或构造函数的形参名称,(Method 和 Constructor 类扩展了 Executable 类,因此继承了 Executable.getParameters 方法)。

但是 .class 文件默认不存储形式参数名称。因为许多生成和使用类文件的工具不希望具有更大静态和动态 Footprint^1的包含参数名称的 .class 文件。尤其是这些工具处理更大的 .class 文件时,Java 虚拟机 (JVM) 将使用更多内存。此外,某些参数名称(如 secret 或 password)可能会暴露有关安全敏感方法的信息。^2

因此,要将形式参数名称存储在特定的 .class 文件中,从而使反射 API 能够检索形式参数名称,请使用 javac 编译器的 -parameters 选项编译源文件。

在maven中,可以在pom.xml中声明这个选项^3

1
2
3
4
5
6
7
8
9
10
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgument>-parameters</compilerArgument>
</configuration>
</plugin>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Test
public void whenGetConstructorParams_thenOk() throws NoSuchMethodException, SecurityException {
Parameter[] parameters = Person.class.getConstructor(String.class)
.getParameters();

Assertions.assertTrue(Arrays.stream(parameters)
.allMatch(parameter -> "fullName".equals(parameter.getName())));
}

@Test
public void whenGetMethodParams_thenOk() throws NoSuchMethodException, SecurityException {
Parameter[] parameters = Person.class.getMethod("setFullName", String.class)
.getParameters();

Assertions.assertTrue(Arrays.stream(parameters)
.allMatch(parameter -> "fullName".equals(parameter.getName())));
}

public static class Person {
private String fullName;

public Person(String fullName) {
this.fullName = fullName;
}

public void setFullName(String fullName) {
this.fullName = fullName;
}

// other methods
}

实际的使用场景:mybatis的 org.apache.ibatis.reflection.ParamNameUtil#getParameterNames 方法,用来获取真实的参数名。通过使用-parameters参数,就不需要在Mapper中使用@Param注解指定参数别名了。