获取方法参数名称

转自http://www.javaeye.com/topic/657837

struts2让人感觉很别扭的一个地方:由于Action中的方法都是无参数的,真实的参数要么写在Action的实例变量中,要么从request中读取。
如果一个Action只写一个命令,这还没有什么问题,但为了避免Action类数量的膨胀,我们一般将一个CRUD操作都放在同一个Action类中,用action!method的方式来访问。这时候严重影响方法的可读性。不读完代码通常不知道某个Action的方法需要哪些参数传递给它。
action方法的返回值也存在同样问题。
有时候在想,如果struts2的拦截器能自动选择要执行的方法,并且按照方法的参数名称名称来匹配方法参数就好了。这儿的问题是如何获取到方法参数名称。
好,下面我们来看一下怎么获取方法的参数名称。
我们知道,仅仅从class运行的角度,方法参数名称是没有必要的,方法参数类似局部变量一样,也是按照在局部变量表的偏移位置进行访问。为了调试方便(?)javac在编译时可选将方法参数以及局部变量名称存放在class文件中对应方法的局部变量表LocalVariableTable中。
我们看一个不包含局部变量表的class文件的结构:
810229f2-f424-3f3d-b484-4d00c1d5def7.jpg
再看一下包含局部变量表的class文件结构:
e2915513-f178-34e8-9053-8afa3e5719c0.jpg
要控制是否生成局部变量表,用javac –g参数选项:
87eb8f12-cd87-3f8e-b65a-b98dc5f8d596.jpg
在Eclipse中这样设置:
5cf3ccc8-0089-308c-93a9-82f9349dc14f.jpg
接下来借助于一款字节码工具来读取局部变量表信息。Javassist是东京工业大学Shigeru Chiba编写的开源的字节码工具包,相对于ASM,性能稍低,但可读性更好,如果用Struts2的话,它已经被包含在xwork-core.jar文件中,所以不需要额外导入了。

Java代码 复制代码

  1. package my;  
  2. import java.util.Arrays;  
  3. import javassist.ClassPool;  
  4. import javassist.CtClass;  
  5. import javassist.CtMethod;  
  6. import javassist.Modifier;  
  7. import javassist.NotFoundException;  
  8. import javassist.bytecode.CodeAttribute;  
  9. import javassist.bytecode.LocalVariableAttribute;  
  10. import javassist.bytecode.MethodInfo;  
  11. @SuppressWarnings("unchecked")  
  12. public class Hello {  
  13. public static void main(String[] args) throws Exception {  
  14. // 匹配静态方法
  15.         String[] paramNames = getMethodParamNames(Hello.class, "main", String[].class);  
  16.         System.out.println(Arrays.toString(paramNames));  
  17. // 匹配实例方法
  18.         paramNames = getMethodParamNames(Hello.class, "foo", String.class);  
  19.         System.out.println(Arrays.toString(paramNames));  
  20. // 自由匹配任一个重名方法
  21.         paramNames = getMethodParamNames(Hello.class, "getMethodParamNames");  
  22.         System.out.println(Arrays.toString(paramNames));  
  23. // 匹配特定签名的方法
  24.         paramNames = getMethodParamNames(Hello.class, "getMethodParamNames", Class.class, String.class);  
  25.         System.out.println(Arrays.toString(paramNames));  
  26.     }  
  27. /**
  28.      * 获取方法参数名称,按给定的参数类型匹配方法
  29.      * 
  30.      * @param clazz
  31.      * @param method
  32.      * @param paramTypes
  33.      * @return
  34.      * @throws NotFoundException
  35.      *             如果类或者方法不存在
  36.      * @throws MissingLVException
  37.      *             如果最终编译的class文件不包含局部变量表信息
  38.      */
  39. public static String[] getMethodParamNames(Class clazz, String method, Class... paramTypes)  
  40. throws NotFoundException, MissingLVException {  
  41.         ClassPool pool = ClassPool.getDefault();  
  42.         CtClass cc = pool.get(clazz.getName());  
  43.         String[] paramTypeNames = new String[paramTypes.length];  
  44. for (int i = 0; i < paramTypes.length; i++)  
  45.             paramTypeNames[i] = paramTypes[i].getName();  
  46.         CtMethod cm = cc.getDeclaredMethod(method, pool.get(paramTypeNames));  
  47. return getMethodParamNames(cm);  
  48.     }  
  49. /**
  50.      * 获取方法参数名称,匹配同名的某一个方法
  51.      * 
  52.      * @param clazz
  53.      * @param method
  54.      * @return
  55.      * @throws NotFoundException
  56.      *             如果类或者方法不存在
  57.      * @throws MissingLVException
  58.      *             如果最终编译的class文件不包含局部变量表信息
  59.      */
  60. public static String[] getMethodParamNames(Class clazz, String method) throws NotFoundException, MissingLVException {  
  61.         ClassPool pool = ClassPool.getDefault();  
  62.         CtClass cc = pool.get(clazz.getName());  
  63.         CtMethod cm = cc.getDeclaredMethod(method);  
  64. return getMethodParamNames(cm);  
  65.     }  
  66. /**
  67.      * 获取方法参数名称
  68.      * 
  69.      * @param cm
  70.      * @return
  71.      * @throws NotFoundException
  72.      * @throws MissingLVException
  73.      *             如果最终编译的class文件不包含局部变量表信息
  74.      */
  75. protected static String[] getMethodParamNames(CtMethod cm) throws NotFoundException, MissingLVException {  
  76.         CtClass cc = cm.getDeclaringClass();  
  77.         MethodInfo methodInfo = cm.getMethodInfo();  
  78.         CodeAttribute codeAttribute = methodInfo.getCodeAttribute();  
  79.         LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);  
  80. if (attr == null)  
  81. throw new MissingLVException(cc.getName());  
  82.         String[] paramNames = new String[cm.getParameterTypes().length];  
  83. int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;  
  84. for (int i = 0; i < paramNames.length; i++)  
  85.             paramNames[i] = attr.variableName(i + pos);  
  86. return paramNames;  
  87.     }  
  88. /**
  89.      * 在class中未找到局部变量表信息<br>
  90.      * 使用编译器选项 javac -g:{vars}来编译源文件
  91.      * 
  92.      * @author Administrator
  93.      * 
  94.      */
  95. public static class MissingLVException extends Exception {  
  96. static String msg = "class:%s 不包含局部变量表信息,请使用编译器选项 javac -g:{vars}来编译源文件。";  
  97. public MissingLVException(String clazzName) {  
  98. super(String.format(msg, clazzName));  
  99.         }  
  100.     }  
  101. static void foo() {  
  102.     }  
  103. void foo(String bar) {  
  104.     }  
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]
  • 810229f2-f424-3f3d-b484-4d00c1d5def7-thumb.jpg
  • 大小: 46.9 KB
  • e2915513-f178-34e8-9053-8afa3e5719c0-thumb.jpg
  • 大小: 51.1 KB
  • 87eb8f12-cd87-3f8e-b65a-b98dc5f8d596-thumb.jpg
  • 大小: 10.3 KB
  • 5cf3ccc8-0089-308c-93a9-82f9349dc14f-thumb.jpg
  • 大小: 64 KB

用的是jclasslib,网址在这儿:
http://www.ej-technologies.com/products/jclasslib/overview.html
看了一下jclasslib的源码,它在处理字节码方面的结构和javassist非常相似。

转载于:https://www.cnblogs.com/rongxh7/archive/2010/05/02/1726031.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值