0

私は現在、フィールドが javassist を介して条件を尊重するように強制するアノテーションを実装しています。フィールドが読み取られているときにフィールドが初期化されているかどうかを確認したい...そのため、現在、 を介してVMによってロードされたときにクラスをロードし、メソッドをオーバーライドして各クラスTranslator.onLoad(ClassPool pool, String className)で を使用してクラスを取得しています. 現時点では、内部で次のメソッドを実行することにより、コードを挿入して状態を確認することができました。ExprEditoredit(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");      
    }

フィールドが初期化されているかどうかを確認するための正しい方向を教えていただけますか? フィールドはプリミティブであってもなくてもよいことに注意してください。

前もって感謝します。

4

1 に答える 1

1

仮定

私は次のことを仮定します:

  • 初期化されたフィールドによって、 nullであるフィールドについて話しています。

  • プリミティブ型を null にすることはできないため、わざわざチェックする必要はありません。

コード

この検証例は、静的フィールドと非静的フィールドの両方で機能します。

また、読みやすくするために、コード String を数行で作成しました。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. フィールドが null かどうかを確認し、そうである場合はフィールド名とともに警告を出力します
  3. フィールド名に値 (null かどうか) を設定します。

これはすでにあなたを正しい方向に向けていると思います。しかし、他に何か必要な場合はお知らせください。

于 2013-03-21T11:59:18.647 に答える