Jus*_*s12 2 java scala bytecode java-bytecode-asm
假设某人给了我以下源代码的Java字节码:
class MyClass {
public static void foo() {
final String bar = "Hello";
}
}
Run Code Online (Sandbox Code Playgroud)
我想扫描这个类中的所有方法MyClass.如果任何方法包含一个final String被调用的变量bar,我需要输出变量的文字值.在这种情况下,Hello.
我设法得到bar方法中调用的变量如下:
// Scala code
import scala.collection.JavaConversions._
import org.objectweb.asm._
import org.objectweb.asm.tree._
def processClass(is:java.io.InputStream) = {
val cn = new ClassNode
val cr = new ClassReader(is)
cr.accept(cn, 0)
is.close
val methods = cn.methods.asInstanceOf[java.util.List[MethodNode]]
val m = methods(0) // get first method as an example
val vars = m.localVariables.asInstanceOf[java.util.List[LocalVariableNode]];
val bar = vars.find(_.name == "bar").find(v => Type.getType(v.desc) == Type.getType(classOf[String]))
if (bar.isDefined) {
// how to read value of final variable "bar"?
// also how to check for final?
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我无法弄清楚如何提取文字"Hello".任何帮助,将不胜感激.
您无法检查final,因为对于局部变量,它根本不存储在类文件中,因此ASM无法提取它.您只能检查变量是否已分配一次或多次,以查找astore*字节码指令.但是,即使是最终变量也可以在字节码中分配几次.例如,这是有效的Java代码:
public static void foo(boolean flag) {
final String bar;
if (flag)
bar = "Hello";
else
bar = "Goodbye";
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下你想打印什么?
此外,赋值可以是这样的表达式的结果:
public static void foo(String name) {
final String bar = "Hello "+name;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下你想打印什么?
如果不确切地知道你想要实现什么,很难帮助你.假设您想要跟踪变量的字符串的简单赋值,您应该访问方法字节码并查找类似的序列ldc #x/astore*.从ldc参数#x 可以了解加载了哪个常量.从astore操作码或参数中,您可以了解要将结果保存到哪个变量槽.之后,您应该查阅本地变量表(您已经知道如何操作),以了解此槽在给定代码位置中对应的变量名称(请注意,变量槽可以重用于不同的变量).
如果确实需要跟踪final局部变量上的关键字,则必须解析源Java文件.有一些方便的解析器,例如,在Eclipse JDT中.