杯具的写完代码才发现应用原来依赖的cglib使用了1.x的asm库,从最初使用3.x版本到2.x,然后使用1.x才搞定asm的兼容性。这里记录下不同版本如何读取annotation。
asm3.2:
这个版本非常方便,实现ClassVisitor接口,里面有个visitAnnotation方法,方法签名是: AnnotationVisitor visitAnnotation(String desc, boolean visible) ,其中desc是annotation的类型(Lxxx/xxx/xxx;),稍微处理下就可以将java byte code的表示形式变成Annotation的类名;visible表示该annotation是否运行时可见,因为我需要类加载后读取annotation的值,可以通过这个参数来判断。因为我只是用来获取annotation的名字,不需要读取annotation里面的key和value,所以直接返回null就可以了。如果要继续深入解析这个annotation,可以通过实现AnnotationVisitor接口并返回来解析。
asm2.2:
降到了这个版本,是运行时cglib库提示ClassWriter没有传入boolean参数的构造函数,这个应该算是asm升级到3.x之后没有做到向下兼容的一个地方。降级到asm2.2,修改的地方很少,就是ClassReader的accept函数,是否跳过debug信息标签,从int型的flag变成了个boolean型。读取annotation的方法没有变化。
asm1.5.3:
改用了2.2之后,还有运行时错误,木有找到CodeVisitor。只能降级到1.5.3了。降级到这个版本修改上面读取annotation的代码成本还是比较高的,这个版本里面ClassVisitor没有了visitAnnotation这个函数,而是把annotation当成了一个Attribute,所以只能通过visitAttribute函数。不过反而这个版本读取annotation官方有个文档:http://asm.ow2.org/doc/tutorial-annotations.html
当然我不需要这么复杂做动态代理什么的,只是读取annotation的名字。大体上就是,先通过visitAttribute函数,判断当前传入的Attribute是否是RuntimeVisibleAnnotations的实例,如果是就能够获取里面的公有变量annotations(类型是List<Annotation>)。我所需要的annotation名字,就在Annotation对象的type字段。这里的type也是bytecode中的类表示方法,如果需要获取能够直接被Class识别的类名,可以自己做简单的字符串处理,或者:
String type = annotation.type;
Type t = Type.getType(type);
String cname = t.getClassName();
这样来拿到className。
这次对向下兼容深有体会啊~~