使用Javassist添加语句

时间:2015-06-19 05:15:09

标签: java javassist

System.out.println("A read operation on a field is encountered "); 

我怎样才能添加一个声明,比方说,上面的声明,  每当在非本地字段上执行读操作时?  而且我还需要知道所读取的字段和设置的详细信息  细节应该对应于该领域的唯一性

示例(删除问题中的抽象):

public class Greet{
   int knowncount;
   public Greet()
   {
      System.out.println("Hello");
      knowncount++;
   }   
   public Greet(String language)
   {
     if(String.equals("ENGLISH"))  {System.out.println("Hello"); knowncount++; }
     else  if(String.equals("SPANISH")) {System.out.println("Hola"); knowncount++;}
     else  System.out.println("Language not recognized");
   }

   public void showCount() 
   {
     System.out.println("count : "+knowncount);
   }

}

用户类测试是:

class test{
  public static void main(String[] args){
    Greet g("SPANISH");
    g.showCount();

  }

}

在上面的例子中使用javassist后我们的代码应该输出:

A read operation on a field is encountered
1

1 个答案:

答案 0 :(得分:2)

您可以使用Javassist ExprEditor来执行您的要求。 ExprEditor允许您编辑FieldAccess中的内容,为了实现您的请求,您可以创建执行以下操作的注入器:

ClassPool classPool = ClassPool.getDefault();
CtClass greetCtClass = classPool.get(Greet.class.getName());

greetCtClass.instrument(new ExprEditor() {
        @Override
        public void edit(FieldAccess fieldAccess)
                throws CannotCompileException {
            if (fieldAccess.getFieldName().equals("knowncount")) {
                fieldAccess
                        .replace(" { System.out.println(\"A read operation on a field is encountered \"); $_ = $proceed($$); } ");
            }
        }
    });

    greetCtClass
            .writeFile("<ROOT DIRECTORY WHERE THE CLASSES ARE>");

解释参数的最佳方法是举例,假设Greet类(恰好位于greatPackage中)位于以下路径/home/user/dev/proj1/build/greetPackage/Greet.class中。在这种情况下,您的根目录将是/home/user/dev/proj1/build/

上述所有锅炉板的关注点如下:

{ System.out.println(\"A read operation on a field is encountered \"); $_ = $proceed($$); }

这里发生了什么?

  • 首先注意所有代码在大括号之间,如果你知道你在javassist中的方式这对你来说是微不足道的,如果不是它可能会让你松散几分钟试图理解什么是错的
  • 然后你有你要求的System.out
  • 最后你有一个魔术线$_ = $proceed($$);。您可以在javassist tutorial中找到有关此内容的更多信息(在该部分中搜索FieldAccess,因为他们没有直接锚定它,抱歉!)但基本上该行所说的是结果字段访问的值是为字段访问调用的虚拟方法的值,换句话说就是字段的实际值。

请记住,您必须在一个单独的JVM进程中使用注入器重写Greet类,然后才能使用具有注入行为的类,除非您使用类加载做一些技巧确定你加载修改后的版本。我没有进入这些主题,因为它超出了范围,但如果你需要帮助,请说出来。我很乐意帮助你。