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