0

我目前正在实现一个注释,它强制字段通过 javassist 遵守条件。我想检查一个字段在读取时是否已初始化......所以,目前,我通过在 VM 通过 a 加载它们时加载它们来获取这些类Translator.onLoad(ClassPool pool, String className),并ExprEditor通过覆盖edit(FieldAccess arg)方法在每个类上使用 a . 现在,我设法通过在内部运行以下方法来注入代码以检查条件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");      
    }

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

提前致谢。

4

1 回答 1

1

假设

我将假设以下内容:

  • 通过字段初始化,我们谈论的是 null的字段。

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

编码

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

我还在几行中创建了代码字符串,以提高可读性。作为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 官方教程(我链接到有关代码修改的部分)。

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

  • $proceed():在字段访问的情况下,这将返回字段的值。
  • $_ :这是在读取模式下编辑 FieldAccess 时必需的标识符。此标记保存将用于设置字段的值。

有了这些信息,就很容易理解代码的想法:

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

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

于 2013-03-21T11:59:18.647 回答