获取方法参数名称
转自http://www.javaeye.com/topic/657837
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) {
- }
- }
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]
- Hello.zip (1.3 KB)
- 下载次数: 0
用的是jclasslib,网址在这儿:
http://www.ej-technologies.com/products/jclasslib/overview.html
看了一下jclasslib的源码,它在处理字节码方面的结构和javassist非常相似。
浙公网安备 33010602011771号