假設有方法:
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);
}
測試結果:
可以看到成功獲取到了方法的參數名稱列表,是按照順序的