假设有方法:
String adminTest(String mobile,int age);
希望获取到参数名称: [mobile,age]
java反射提供了很多方法,获取所有的方法,获取所有的参数类型等,但是却没有一个方法能够帮助我们获取方法的参数名列表。
首先:
为什么我们需要获取到方法对应的参数名称?
原因是例如mybatis的mapper接口中定义了很多参数名称,在xml用占位符来标识,就可以类似通过这种方法来一一对应,
包括spring的参数解析,这个问题是我在参考别人的手写mybatis,中考虑到的一个问题,故贴出我查阅资料得到的方法,网上的大部分只能获取到类的方法的参数名称列表,对接口的方法参数名称获取较少.
其实也是基于spring中提供的类来实现的:需要jdk1.8及其以上:
在Java1.8之后,可以通过反射API java.lang.reflect.Executable.getParameters来获取到方法参数的元信息。这要求在使用编译器时加上-parameters参数,它会在生成的.class文件中额外存储参数的元信息,这会增加class文件的大小。
idea默认是开启的:
工具类:
package com.wm.ruanyan1.util;
import com.wm.ruanyan1.service.AdminService;
import com.wm.ruanyan1.service.UserService;
import com.wm.ruanyan1.service.impl.UserServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.util.Assert;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @author 半卷流年
* @date 2020-6-20 10:12
*/
@Slf4j
public class ReflectUtil {
/**
* 借助spring 的工具类,注意需要jdk8及其以上
* 获取方法的参数的名称(不是类型),这个兼容接口(可以没有实现类) 和 普通类的方法参数
*
* 例如: public String test(String name,Long id);
*
* 获取到的是: [name,id]
*
*
* @return
*/
public static String[] getMethodParamName(Method method){
Assert.notNull(method,"传入的方法对象为空");
method.setAccessible(true);
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
return discoverer.getParameterNames(method);
}
/**
* 借助spring 的工具类,注意需要jdk8及其以上
* * 获取方法的参数的名称(不是类型),普通类的方法参数,不能获取到接口的方法的参数名称
* *
* * 例如: public String test(String name,Long id);
* @param method
* @return
*/
public static String[] getMethodParamNameNoInterface(Method method){
Assert.notNull(method,"传入的方法对象为空");
method.setAccessible(true);
LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
return discoverer.getParameterNames(method);
}
public static void main(String[] args) throws Exception{
/*** 有实现类的接口**/
Method test = UserService.class.getMethod("userTest", String.class, Long.class, int.class);
String[] paramName = getMethodParamName(test);
log.info("userService有实现类的接口方法名称:{},方法的参数名称:{}",test.getName(), Arrays.toString(paramName));
/***没有实现类的接口方法参数名称获取***/
Method adminTest = AdminService.class.getMethod("adminTest", String.class, int.class);
String[] methodParamName = getMethodParamName(adminTest);
log.info("userService有实现类的接口方法名称:{},方法的参数名称:{}",adminTest.getName(), Arrays.toString(methodParamName));
/***获取类的方法参数名称**/
Method userTest = UserServiceImpl.class.getMethod("userTest", String.class, Long.class, int.class);
String[] name = getMethodParamName(userTest);
log.info("userService类的方法:{},方法的参数名称:{}",adminTest.getName(), Arrays.toString(name));
System.out.println("----------------------下面为测试只能获取类的方法参数名称,获取不到接口的方法的参数名称---------------------------");
/*****获取接口的方法参数名称******/
String[] nameNoInterface = getMethodParamNameNoInterface(test);
log.info("adminService有实现类的接口方法名称:{},方法的参数名称:{}",test.getName(), Arrays.toString(nameNoInterface));
/***获取类的方法参数名称**/
String[] noInterface = getMethodParamNameNoInterface(userTest);
log.info("adminService类的方法:{},方法的参数名称:{}",test.getName(), Arrays.toString(noInterface));
}
}
编写接口和实现类:
UserService
package com.wm.ruanyan1.service;
/**
* @author 半卷流年
* @date 2020-6-20 10:19
*/
public interface UserService {
String userTest(String name,Long id,int count);
}
实现类:
UserServiceImpl
package com.wm.ruanyan1.service.impl;
import com.wm.ruanyan1.service.UserService;
/**
* @author 半卷流年
* @date 2020-6-20 10:20
*/
public class UserServiceImpl implements UserService {
@Override
public String userTest(String name, Long id, int count) {
return "success";
}
}
编写一个没有实现类的接口:
AdminService
package com.wm.ruanyan1.service;
/**
* @author 半卷流年
* @date 2020-6-20 10:21
*/
public interface AdminService {
String adminTest(String mobile,int age);
}
测试结果:
可以看到成功获取到了方法的参数名称列表,是按照顺序的