我有一些(也许)奇怪的要求 - 我想检测给定接口(interface)名称的本地(方法)变量的定义。当找到这样的变量时,我想检测将在该变量上调用哪些方法(set/get*)。 我尝试过 Javassist,但没有成功,现在我对 ASM 有了更深入的了解,但不确定它是否可能是我想要的。 这样做的原因是我喜欢使用 GraphViz 生成依赖于相同数据结构的 beans 的依赖关系图。 如果这件事是可能的,有人可以给我一个关于如何完成它的提示吗?也许还有其他框架可以做到这一点?
2015年9月1日
为了让事情更清楚:
界面是自己编写的 - 整个操作的目标是在第一步自动创建依赖关系图 - 稍后应该实现基于依赖关系的图形编辑器。 我想知道 FindBugs/PMD 是如何工作的,因为它们也使用字节码并检测例如空指针调用(变量未初始化并且将在其上调用方法)。所以我想我可以用同样的方式实现我的想法。整个代码是基于Spring的——也许这会打开另一个解决方案?最后但并非最不重要的一点是我可以使用源 jar 吗?
在考虑问题时 - 是否可以通过 ASM/javassist 检测接口(interface)中的所有可用方法并在其他类中找到对它们的调用?
最佳答案
恐怕,你想做的事情是不可能的。在编译后的 Java 代码中,不存在源代码中形式的局部变量。使用方法stack frames它们为局部变量保留了内存,并通过数字索引进行寻址。类型由写入它的指令隐含,并且可能在整个方法的代码中发生变化,因为内存可能会被具有分离作用域的不同变量重用。另一方面,名称完全无关。
当字节码得到验证时,将对堆栈帧的所有指令的影响进行建模,以推断执行的每个点的每个堆栈帧槽的类型,以便可以检查所有操作的有效性。从类文件版本 50
开始,将有 StackMapTable
attributes通过包含显式类型信息来帮助该过程,但仅限于具有分支的代码。对于顺序代码,变量的类型仍然需要通过推理得出。
这些推断类型不一定是声明的类型。例如,在字节码级别上,之间没有区别
CharSequence cs="foo";
cs.charAt(0);
和
String s="foo";
((CharSequence)s).charAt(0);
在这两种情况下,都会将String
常量存储到局部变量中,然后调用接口(interface)方法。在这两种情况下,推断的类型都将为 String
,并且 CharSequence
方法的调用被视为有效,因为 String
实现了 CharSequence
.
这反驳了检测是否存在使用 CharSequence
(interface
)类型声明的局部变量的想法,因为实际声明的类型是不相关的,并且不存储在常规字节码。
但是,调试属性包含有关局部变量的信息,请参阅 LocalVariableTable
attribute以及像 ASM 这样的库 will tell you about the declarations如果存在此类信息。但您不能依赖这些可选信息。例如。 Oracle 的 JRE 库默认情况下不带它们。
关于java - 如何通过接口(interface)类型检测java局部变量,然后找到调用它们的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32311973/