【问题标题】:javassist Field check initializationjavassist 字段检查初始化
【发布时间】:2013-03-20 18:14:56
【问题描述】:

我目前正在实现一个注释,它强制字段通过 javassist 遵守条件。我想检查一个字段在被读取时是否被初始化......所以,目前,我通过在VM通过Translator.onLoad(ClassPool pool, String className)加载它们时加载它们来获取类,并使用ExprEditor on每个类通过覆盖edit(FieldAccess arg) 方法。现在,我设法通过在onLoad 中运行以下方法来注入代码来检查条件:

    private void processFields(FieldsAndMethods data) {
        final FieldsAndMethods copy = data;
        Stack<CtClass> classes = data.getThisClass();
        for(CtClass cc : classes ){
            try {
                cc.instrument(new ExprEditor(){

                @Override
                public void edit(FieldAccess arg) throws CannotCompileException{
                   try{
                        CtField field = arg.getField();
                        if(copy.getFields().contains(field) &&
                           field.hasAnnotation(Assertion.class)){

                            Assertion a =
                                ((Assertion)field.getAnnotation(Assertion.class))   
                            String condition = assertion.value();
                            String fieldName = field.getName();
                            String processCondition = 
                                transformCondition(condition, fieldName);

                            if(arg.isWriter()){

                                String code = "{if(" + evaledCondition + ")" +                                         
                                              "$proceed($$) ;" +
                                              "else throw new " + 
                                              "RuntimeException(\"The assertion " + 
                                                   condition + " is false.\");}";                                                                               
                                arg.replace(code);

            }else if (arg.isReader()){
                                //Here is where I would like to check if the field 
                                //has been initialized... 
            }

                        }catch(ClassNotFoundException e){
                            System.out.println("could not find Annotation " + 
                            Assertion.class.getName() );
                        }catch(NotFoundException e){
                            System.out.println("could not find field " + 
                            arg.getFieldName() );
                        }                                       
                    }
                });
            } catch (CannotCompileException e) {                
                System.out.println("Could not interpret the expression");
                System.out.println(e);
            }
        }       
    }

    private String transformCondition(String condition, String fieldName){
        return condition.replace(fieldName, "$1");      
    }

您能否指出正确的方向来确定字段是否已初始化?请注意,字段可以是原始字段,也可以不是原始字段。

提前致谢。

【问题讨论】:

  • 您的意思是要注入代码以检查字段是否已初始化,还是要检查字段是否在转换过程中已初始化?
  • 由于字段受断言约束,我必须检查它们是否尚未初始化(默认值可能会破坏条件)。每个字段都访问一个未初始化的变量(当然,构造函数或初始化程序中的任何初始化除外)。

标签: java reflection initialization field javassist


【解决方案1】:

假设

我假设如下:

  • 通过字段初始化,我们谈论的是为空的字段

  • 原始类型不能为空,因此无需检查它们。

代码

此示例验证适用于静态和非静态字段。

为了更好的可读性,我还在几行中创建了代码字符串。作为 arg 一个 FieldAccess 对象,您可以编写以下内容:

 if (arg.isReader() && !arg.getField().getType().isPrimitive()) {
  String code = "{ java.lang.Object var = $proceed();"
               +  "if(var == null) {"
                   + "java.lang.System.out.println(\"not initialized " + arg.getFieldName() + "\");"
               +  "}"
               + "$_=var;}";
            arg.replace(code);
        }

代码说明

如您所见,在这个小示例中,我使用了一些 javassist 标识符,有关此内容的完整参考,请阅读 javassist official tutorial(我链接到关于代码修改的部分)。

以下是使用的每个标识符的含义:

  • $proceed() :在访问字段的情况下,这将返回该字段的值。
  • $_ :这是在 read 模式下编辑 FieldAccess 时必需的标识符。此令牌包含将用于设置字段的值。

有了这些信息就很容易理解代码的思路了:

  1. 将字段值放入名为var的辅助对象中
  2. 检查该字段是否为空,如果是则打印带有字段名称的警告
  3. 用值设置字段名(无论是否为空);

我想这已经为您指明了正确的方向。但是,如果您需要其他任何东西,请告诉我。

【讨论】:

  • 嗯......事情是......它不是关于检查一个值是否为空......一个方法也可以做var = null......如果我把@Assertion("i&gt;0") 的断言,当 var 被声明为 int i; 时,它已经破坏了断言,因为它已经具有默认值,即 0。不过感谢您的回答...我设法通过其他方式做到了...
  • @CarlosFilipeCosta:现在我明白了您的示例中的 evaledCondition 是什么,它是来自 Assertion 注释的值,对吗? (归因不存在于其中)。关于 Asserting(i&gt;0) 不足以将 var==null 更改为 if (evaledCondition)?
  • @CarlosFilipeCosta:另外,如果您仍然需要 SO 用户的帮助,其中可以包括我重新编辑我的答案或其他用户的答案,我的建议是编辑您的答案以澄清更多内容你的意思是一个字段已经被初始化,也许可以给出一个完整的例子来说明你想要做什么。如果您不再对帮助感兴趣(因为您说您找到了其他方法),我建议您发布自己的答案并接受它,这样它就不会一直无人回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-27
  • 1970-01-01
  • 2018-05-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多