Javassist初体验
2024-10-14 03:26:25
最初接触javassist是在研究dubbo源码的时候,那会对其的理解还停留在动态生成字节码的位置,可以做动态代理之类的动态化处理。最近由于项目需要扫描springMVC中controller层的注解,同时还需要知道方法入参的名字。基于java反射拿到注解简单,但是要拿到入参名字却需要jdk8才提供支持。但是当前项目整体环境基于jdk7,因此又想起javassist,算是get一个新技能。
基本的代码如下:
private String[] getParamName(Method method) throws Exception {
CtClass cc = pool.get(method.getDeclaringClass().getName()); CtClass[] params = new CtClass[method.getParameterTypes().length];
for(int i = 0; i < method.getParameterTypes().length; i++) {
params[i] = pool.getCtClass(method.getParameterTypes()[i].getName());
} CtMethod cm = cc.getDeclaredMethod(method.getName(), params); MethodInfo methodInfo = cm.getMethodInfo();
CodeAttribute codeAttribute = methodInfo.getCodeAttribute(); LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
String[] paramNames = new String[cm.getParameterTypes().length];
int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
for(int i = 0; i < attr.tableLength(); i++) {
if(attr.index(i) >= pos && attr.index(i) < paramNames.length + pos) {
paramNames[attr.index(i) - pos] = attr.variableName(i);
}
} return paramNames;
}
关键的代码在于下面那个for循环。
先看看Java虚拟机规范的描述:
Java虚拟机使用局部变量表来完成方法调用时的参数传递,当一个方法被调用的时候,它的参数将会传递至从0开始的连续的局部变量表位置上。特别地,当一个实例方法被调用的时候,第0个局部变量一定是用来存储被调用的实例方法所在的对象的引用(即Java语言中的“this”关键字)。后续的其他参数将会传递至从1开始的连续的局部变量表位置上。
但此描述中第 0 个局部变量是指 slot 排号为 0,而不是位置为 0。
所以正确的做法就是遍历本地变量表,根据 slot 值确认是不是方法参数,体现在代码中的 API 就是 attr.index(i) 将会返回 slot。
pos 变量主要用于处理实例方法前面的 this 变量,静态方法 pos 将为 0。
ps:
目前遇到一个问题,在调试的时候偶然发现,attr.index()下标不一定按照自然增序添加。比如,0,1,2,3,5,6等。类似这样的顺序。此时,只有从小到大的顺序可以描述参数位置,因此,上述后面的部分代码修正为如下:
TreeMap<Integer, Integer> map = new TreeMap<>();
for(int i = 0; i < attr.tableLength(); i++) {
map.put(attr.index(i), i);
}
int index = 0;
boolean flag = false;
for(Integer key : map.keySet()) {
if (!flag) {
flag = true;
continue;
} if (index < paramNames.length) {
paramNames[index++] = attr.variableName(map.get(key));
} else {
break;
}
}
最新文章
- EntityFramework之数据库以及表基本创建(一)
- NSClassFromString 和 遍历UIView获取她所在的UIViewController的tips
- [转]JavaScript跨域总结与解决办法
- POJ3308 Paratroopers(最小割/二分图最小点权覆盖)
- 《认识你自己(Archetypes who are you?)》 10种原型的行为模式和性格特征
- Bootstrap迁移系列 - Navbar
- Hibernate注解学习1
- LintCode-乱序字符串
- python编写网络抓包分析脚本
- 每天一点点java---继承exception类来实现自己的异常类
- iis与 asp.net管道(asp.net应用程序什么周期)
- 201521123080《Java程序设计》第9周学习总结
- 一篇关于Maven项目的jar包Shell启动脚本
- 关于C#的new与override
- windows一键安装包的升级禅道
- angular之指令
- ORM常用字段介绍
- LayaBox IDE 安装后执行项目报错解决方案的一些记录
- Angular的一些用法或者结构技巧
- 核心一:DI