struts2让人感觉很别扭的一个地方:由于Action中的方法都是无参数的,真实的参数要么写在Action的实例变量中,要么从request中读取。
如果一个Action只写一个命令,这还没有什么问题,但为了避免Action类数量的膨胀,我们一般将一个CRUD操作都放在同一个Action类中,用action!method的方式来访问。这时候严重影响方法的可读性。不读完代码通常不知道某个Action的方法需要哪些参数传递给它。
action方法的返回值也存在同样问题。
有时候在想,如果struts2的拦截器能自动选择要执行的方法,并且按照方法的参数名称名称来匹配方法参数就好了。这儿的问题是如何获取到方法参数名称。
好,下面我们来看一下怎么获取方法的参数名称。
我们知道,仅仅从class运行的角度,方法参数名称是没有必要的,方法参数类似局部变量一样,也是按照在局部变量表的偏移位置进行访问。为了调试方便(?)javac在编译时可选将方法参数以及局部变量名称存放在class文件中对应方法的局部变量表LocalVariableTable中。
我们看一个不包含局部变量表的class文件的结构:
再看一下包含局部变量表的class文件结构:
要控制是否生成局部变量表,用javac –g参数选项:
在Eclipse中这样设置:
接下来借助于一款字节码工具来读取局部变量表信息。Javassist是东京工业大学Shigeru Chiba编写的开源的字节码工具包,相对于ASM,性能稍低,但可读性更好,如果用Struts2的话,它已经被包含在xwork-core.jar文件中,所以不需要额外导入了。
package my;
import java.util.Arrays;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
@SuppressWarnings("unchecked")
public class Hello {
public static void main(String[] args) throws Exception {
// 匹配静态方法
String[] paramNames = getMethodParamNames(Hello.class, "main", String[].class);
System.out.println(Arrays.toString(paramNames));
// 匹配实例方法
paramNames = getMethodParamNames(Hello.class, "foo", String.class);
System.out.println(Arrays.toString(paramNames));
// 自由匹配任一个重名方法
paramNames = getMethodParamNames(Hello.class, "getMethodParamNames");
System.out.println(Arrays.toString(paramNames));
// 匹配特定签名的方法
paramNames = getMethodParamNames(Hello.class, "getMethodParamNames", Class.class, String.class);
System.out.println(Arrays.toString(paramNames));
}
/**
* 获取方法参数名称,按给定的参数类型匹配方法
*
* @param clazz
* @param method
* @param paramTypes
* @return
* @throws NotFoundException
* 如果类或者方法不存在
* @throws MissingLVException
* 如果最终编译的class文件不包含局部变量表信息
*/
public static String[] getMethodParamNames(Class clazz, String method, Class... paramTypes)
throws NotFoundException, MissingLVException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get(clazz.getName());
String[] paramTypeNames = new String[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++)
paramTypeNames[i] = paramTypes[i].getName();
CtMethod cm = cc.getDeclaredMethod(method, pool.get(paramTypeNames));
return getMethodParamNames(cm);
}
/**
* 获取方法参数名称,匹配同名的某一个方法
*
* @param clazz
* @param method
* @return
* @throws NotFoundException
* 如果类或者方法不存在
* @throws MissingLVException
* 如果最终编译的class文件不包含局部变量表信息
*/
public static String[] getMethodParamNames(Class clazz, String method) throws NotFoundException, MissingLVException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get(clazz.getName());
CtMethod cm = cc.getDeclaredMethod(method);
return getMethodParamNames(cm);
}
/**
* 获取方法参数名称
*
* @param cm
* @return
* @throws NotFoundException
* @throws MissingLVException
* 如果最终编译的class文件不包含局部变量表信息
*/
protected static String[] getMethodParamNames(CtMethod cm) throws NotFoundException, MissingLVException {
CtClass cc = cm.getDeclaringClass();
MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
if (attr == null)
throw new MissingLVException(cc.getName());
String[] paramNames = new String[cm.getParameterTypes().length];
int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
for (int i = 0; i < paramNames.length; i++)
paramNames[i] = attr.variableName(i + pos);
return paramNames;
}
/**
* 在class中未找到局部变量表信息<br>
* 使用编译器选项 javac -g:{vars}来编译源文件
*
* @author Administrator
*
*/
public static class MissingLVException extends Exception {
static String msg = "class:%s 不包含局部变量表信息,请使用编译器选项 javac -g:{vars}来编译源文件。";
public MissingLVException(String clazzName) {
super(String.format(msg, clazzName));
}
}
static void foo() {
}
void foo(String bar) {
}
}
运行结果如下:
[args]
[bar]
[clazz, method, paramTypes]
[clazz, method]
- 大小: 46.9 KB
- 大小: 51.1 KB
- 大小: 10.3 KB
- 大小: 64 KB
分享到:
相关推荐
C# 获取调用函数 参数名称和值C# 获取调用函数 参数名称和值C# 获取调用函数 参数名称和值C# 获取调用函数 参数名称和值C# 获取调用函数 参数名称和值C# 获取调用函数 参数名称和值
C# 调用函数时动态获取参数名称和值 C# 调用函数时动态获取参数名称和值 C# 调用函数时动态获取参数名称和值
在java中,可以通过反射获取到类、字段、方法签名等相关的信息,像方法名、返回值类型、参数类型、泛型类型参数等,但是不能够获取方法的参数名。在实际开发场景中,有时需要根据方法的参数名做一些操作,那么该如何...
主要给大家介绍了在Java 8中如何获取参数名称的方法,文中给出了详细的介绍和方法示例,相信对大家的理解和学习具有一定的参考借鉴价值,有需要的朋友可以参考学习,下面来一起看看吧。
获取当前计算机的ID和预设参数配置文件;根据ID,从预设参数配置文件中匹配与ID对应的配置参数;根据配置参数配置VxWorks操作系统,加载应用程序。本发明提供的参数化配置方法,通过根据计算机ID和预设参数配置文件...
获取设备参数
js代码-获取 url 中的参数 1. 指定参数名称,返回该参数的值 或者 空字符串 2. 不指定参数名称,返回全部的参数对象 或者 {} 3. 如果存在多个同名参数,则返回数组
主要介绍了JUnit中获取测试类及方法的名称实现方法,本文使用了JUnit中提供的TestName实现,不过还有一些编程细节需要注意,需要的朋友可以参考下
获得请求头的各种参数信息jsp代码: 客户使用的协议是: HTTP/1.1 获取接受客户提交信息的页面: /004.jsp 接受客户提交信息的长度: -1 客户提交信息的方式: GET 获取 HTTP 头文件中 User-Agent 的值:: ...
C#获取本机各基础参数操作类,包含内容广泛,非常实用好用! 主要包括: 获取本机用户名、MAC地址、内网IP地址、公网IP地址、硬盘ID、CPU序列号、系统名称、物理内存。 操作系统的登录用户名 获取本机MAC地址 获取本...
JAVA 根据Url 接口 获取文件名称和类型,亲测可用。输入参数地址即可。
1,为了获取视频,你应该创建一个 VideoCapture 对象。他的参数可以是设备的索引号,或者是一个视频文件。设备索引号就是在指定要使用的摄像头。一般的笔记本电脑都有内置摄像头。所以参数就是 0。你可以通过设置成 1 ...
此程序demo详细描述的从发布接口到调用接口的全部过程,详细描述了Xfire调用webservice参数无法传递的问题。
PHP在cli模式下接收参数有两种方法 1.使用argv数组 2.使用getopt方法 1.使用argv数组 例如:需要执行一个php,并传递三个...可以看到argv[0]为当前执行的php文件名称,而argv[1]~argv[3]则是传递的参数的值 argv[1
利用java反射原理调用方法时,常先需要传入方法参数数组才能取得方法。该方法参数数组采用动态取得的方式比较合适
windows上使用C++ 获取电脑摄像头的个数和每个摄像头的名称。代码是windows C++版本, VS2013 测试可用。
能不能写个动态的业务,只输入存储过程名称,自动获取存储过程参数,并且参数的数据从前台传递过来,这个就通用了。只写一个通用方法,就可以调用所有的存储过程。只根据输入不同的存储过程名称、参数内容,自动调用...
我写了一个 JavaScript函数来解析函数的参数名称, 代码如下: function getArgs(func) { // 先用正则匹配,取得符合参数模式的字符串. // 第一个分组是这个: ([^)]*) 非右括号的任意字符 var args = func.toString...
//获取地址栏参数,name:参数名称 function getUrlParms(name){ var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)"); var r = [removed].search.substr(1).match(reg); if(r!=null) return unescape(r[2]);...