1. Preface
Generally, when we use reflections similar to the following to obtain the method parameter name, we usually get arg0 and arg1. The parameter name will be lost by default, resulting in the inability to obtain the real method parameter name. The following describes how to solve it in other ways.
class A { void getUser(String userName, String userId){} } Method method = (,); Parameter[] parameters = (); for (Parameter parameter : parameters) { String name = (); (name); // What you get is arg0, arg1 instead of userName, userId }
2. Solution
Method 2.1: Add compile parameter configuration -parameters
By default, when Java compiles the project code as a class file, the method parameter name will be erased and replaced with arg0, arg1, etc. However, we can configure the parameter names to be compiled at compile time, and add the following compilation plug-in configuration to maven
<plugin> <groupId></groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <!-- Keep method parameter names during configuration compilation --> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin>
For newer maven versions (>= 3.6.2), you can also use the parameters configuration item directly:
<plugin> <groupId></groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <parameters>true</parameters> </configuration> </plugin>
Add to-parameters
After compiling parameters, we can see that the compiled class file is the source code parameter name, not the original arg0 and arg1. Then we use native reflection()
You can get the real parameter name of the method parameter
Note: This method is only valid for JDK8 and above. Previous versions of JDK did not provide this retention mechanism.
Method 2.2: Use Spring's internal tool class - ParameterNameDiscoverer
If your project relies on spring, you can directly use spring's internal tool classParameterNameDiscoverer
Go to get the real parameter name of the method. The implementation class of ParameterNameDiscoverer mainly includes LocalVariableTableParameterNameDiscoverer and StandardReflectionParameterNameDiscoverer. Here is how to use it
1. StandardReflectionParameterNameDiscoverer usage
This discoverer needs to add the compile configuration the same as Method 2.1: Add the compile parameter configuration -parameters, because the underlying layer is just used to obtain it directly using reflective Parameters.
// Create parameter name discoverer ParameterNameDiscoverer discoverer = new StandardReflectionParameterNameDiscoverer(); Method method = (,); // Get the real parameter name of the method. userName, userId String[] parameterNames = (method);
2. Use of LocalVariableTableParameterNameDiscoverer
// Create parameter name discoverer ParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer(); Method method = (,); // Get the real parameter name of the method. userName, userId String[] parameterNames = (method);
The underlying principle of this discoverer is to generate a local variable table LocalVariableTable for debugging information when compiling the class, and then parse the LocalVariableTable based on ASM bytecode technology to get the parameter name, so it also needs to add additional compilation configuration during compilation. Please add the following -g compile parameter configuration in maven
<build> <plugins> <plugin> <groupId></groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <compilerArgs> <!-- Generate local variable tables --> <arg>-g:vars</arg> </compilerArgs> </configuration> </plugin> </plugins> </build>
The advantage of this method is that it can also be used in the JDK8 version, but the disadvantage is that it cannot obtain the method parameter name of the interface
3. Use of DefaultParameterNameDiscoverer
// Create parameter name discoverer ParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer(); Method method = (,); // Get the real parameter name of the method. userName, userId String[] parameterNames = (method);
This parameter name discoverer is a discoverer of combination modes. It does not implement the logic of obtaining parameter names, but combines other parameter name discoverers, and then iterates on each parameter name discoverer until the real parameter name is found. Judging from the following source code, the two StandardReflectionParameterNameDiscoverer mentioned above are mainly built-in. Therefore, if the corresponding parameter name discoverer is to be effective, it is necessary to cooperate with the usage logic of the corresponding discoverer. Otherwise, the method parameter name will not be obtained.
// Source codepublic class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer { public DefaultParameterNameDiscoverer() { if (!()) { if (()) { addDiscoverer(new KotlinReflectionParameterNameDiscoverer()); } addDiscoverer(new StandardReflectionParameterNameDiscoverer()); // Depend on compilation parameters -parameters addDiscoverer(new LocalVariableTableParameterNameDiscoverer()); // // Depend on compilation parameters -g } } }
Summary of use
1. The essence of parameter name acquisition
- All schemes rely on the parameter name information retained during compilation (through -parameters or -g parameters), so when compiling, there is, there is, there is, there is, there is, and there is no, especially for some third-party dependencies.
- If a class that is dependent on a third party does not carry debug information (if it is not compiled with the above compilation parameters), the real parameter name cannot be obtained in any case. Unless the third party library has been compiled with -parameters, it can still be obtained through reflection (but it is rare in actual scenarios)
2. Version adaptation suggestions
- JDK8+ project: Priority
-parameters
Compile parameters (best performance), cooperateStandardReflectionParameterNameDiscoverer
- JDK7 and below:
-g
Compile parameters, cooperateLocalVariableTableParameterNameDiscoverer
- Spring Project: Recommended
DefaultParameterNameDiscoverer
(Automatically adapt to the optimal policy), two compilation parameters can be configured at the same time to improve compatibility:
3. In some springBoot 2.0 and later versions, spring-boot-starter-parent will have built-in compilation parameter configuration, so you can directly use ParameterNameDiscoverer without matching. Of course, you need to ensure that the project has overwritten the default configuration and fails, and you need to reconfigure it.
Examples of well-known application scenarios
- The @RequestParam parameter name of spring-mvc can be omitted
- Mybatis @Param can also be configured without configuration
This is the article about Java's method of obtaining method parameter names through reflection. For more related contents of Java's reflection method parameter names, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!