我有一些(可能)奇怪的需求——我想检测给定接口名称的局部(方法)变量的定义。当找到这样一个变量时,我想检测将对该变量调用哪些方法(set/get*)。我尝试过Javassist,但运气不好,现在我对ASM有了更深入的了解,但不确定它是否可能是我想要的。这样做的原因是,我喜欢使用依赖于相同数据结构的bean的GraphViz生成依赖关系图。如果这件事是可能的,有没有人能给我一个提示,告诉我怎么做?也许有其他框架可以做?
01.09.2015
让事情变得更清楚:
接口是自己编写的——整个操作的目标是在第一步自动创建依赖关系图——之后应该实现基于依赖关系的图形化编辑器。我想知道FindBugs/PMD是如何工作的,因为它们也使用字节码并检测例如空指针调用(未初始化的变量和将在其上调用的方法)。所以我想我可以用同样的方式实现我的想法。整个代码都是基于Spring的——也许这是另一个解决方案?最后但并非最不重要的是,我可以在一个源jar上工作?
当考虑到这个问题时-是否有可能通过ASM/javassist从接口检测所有可用的方法并在其他类中找到对它们的调用?
恐怕,你想做的事是不可能的。在编译后的Java代码中,不存在源代码中那种形式的局部变量。方法使用堆栈帧,这些堆栈帧为局部变量保留内存,这些内存由数字索引寻址。该类型由写入它的指令所暗示,并且可能在方法的整个代码中更改,因为内存可能被具有分离作用域的不同变量重用。另一方面,名字是完全不相关的。
当字节码被验证时,所有指令对堆栈帧的影响将被建模,以推断每个执行点的每个堆栈帧槽的类型,以便可以检查所有操作的有效性。从类文件版本50
开始,将有StackMapTable
属性通过包含显式类型信息来帮助该过程,但仅适用于具有分支的代码。对于顺序代码,变量的类型仍然必须通过推理派生。
这些推断类型不一定是声明的类型。例如,在字节码级别上,
之间没有区别。CharSequence cs="foo";
cs.charAt(0);
和
String s="foo";
((CharSequence)s).charAt(0);
在这两种情况下,都将String
常量存储到一个局部变量中,然后调用接口方法。在这两种情况下,推断的类型都是String
,并且当String
实现CharSequence
时,调用CharSequence
方法被认为是有效的。
这否定了检测使用CharSequence
(interface
)类型声明的局部变量的想法,因为实际声明的类型是无关的,并且不存储在常规字节码中。
但是,有一些调试属性包含有关局部变量的信息,请参阅
LocalVariableTable
属性,如果存在此类信息,ASM等库会告诉您有关声明的信息。但你不能依赖这些可选信息。例如,Oracle的JRE库在默认情况下是不带这些库的。
我不知道你到底想要什么,但是。
你可以在每个对象上使用实现,每个有getter的对象都可以用getable类来实现。然后你只能在对象上做一些事情,这些对象具有你从类getable中实现的函数。
https://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html