0

I am currently implementing an Annotation that forces the fields to respect a condition through javassist. I would like to check if a field is initialized when it is being read... so, currently, I am getting the classes by loading them when they are loaded by the VM through a Translator.onLoad(ClassPool pool, String className), and using an ExprEditor on each class through overriding the edit(FieldAccess arg) method. Right now, I managed to inject code to check the condition by running the following method inside 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");      
    }

Could you point me in the right direction for finding out if a field has been initialized? Notice that a field can be either a primitive or not.

Thanks in advance.

  • Do you mean you want to inject code to check if the field is initialized OR do you want to check if the field is already initialized during your transformation? – pabrantes Mar 20 '13 at 20:59
  • Since the fields are constrained by the Assertion, I must to check if they have not been initialized (the default values may break the condition). Every field access to a non initialized variable (except, of course, any initialization in a constructor or a initializer). – Carlos Filipe Costa Mar 20 '13 at 23:52

1 Answers1

1

Assumptions

I'll assume the following:

  • By field initialized we are talking about fields that are null.

  • Primitive types cannot be null so no bother to check them.

The code

This example verification will work for both static and non static fields.

I've also created the code String in several lines for better readability. Being arg a FieldAccess object, you can write the following:

 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);
        }

Code Explanation

As you can see, in this small example I've used a few javassist identifiers, for the complete reference about this please read the javassist official tutorial (I'm linking to the section about code modifications).

Here is what each identifier used means:

  • $proceed() : in the case of a field access this returns the value of the field.
  • $_ : this is an identifier that is mandatory when editing a FieldAccess in read mode. This token holds the value that will be used to set the field.

With this information it's easy to understand the code's idea:

  1. Put the field value into an auxiliary object named var
  2. Check if the field is null, if so print a warning with the field name
  3. Set the fieldname with the value (either it's null or not);

I guess this already points you to the right direction. But let me know if you need anything else.

Community
  • 1
  • 1
pabrantes
  • 2,161
  • 1
  • 28
  • 34
  • Well... the thing was... it wasn't about checking if a value was null or not... a method can just as well do var=null... if i put an assertion that says `@Assertion("i>0")`, when a **var** is declared as `int i;`, it already breaks the assertion because it already has the default value, which is 0. Thanks for your answer though... I managed to do it through other means... – Carlos Filipe Costa Mar 21 '13 at 18:16
  • @CarlosFilipeCosta: Now I understand what's the *evaledCondition* in your example, it's the value from the Assertion annotation, correct? (The attribution wasn't present in it). Regarding `Asserting(i>0)` wouldn't be enough to change the `var==null` to the if `(evaledCondition)`? – pabrantes Mar 21 '13 at 18:55
  • @CarlosFilipeCosta: Also, if you still want help from SO users, which can include me re-editing my answer or answers from other users, my suggestion is to edit your answer to clarify a bit more what do you mean by a field has been initialized and maybe give a full example on what you want to do. If you are not interested in help anymore (since you said you found other means), I suggest you to post your own answer and accept it so it doesn't stay unanswered. – pabrantes Mar 21 '13 at 21:17