2011-05-04

AOP: AspectJ field access to inject dependencies

Since I’m reading a book on AspectJ, I figured out it would be possible to use AOP for dependency injection. I was sure the code would be concise and elegant, but I was wrong. Let’s start from the beginning.

This is what I wanted to have:

@Log
private static Logger log;

As you can see, I have a private static field, no getters or setters for it, it’s annotated with my custom @Log annotation.

Now, I wanted to use AspectJ to
  • seamlessly initialize this field
  • do it only once for every class where it’s used
  • and I wanted the initialized logger to be a logger for this particular class

Solution


Sadly, that’s the best I was able to come up with.

package me.m1key.test;

import java.lang.reflect.Field;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public aspect LogInjectAspect {

    pointcut loggerAccessed(Object a): get(@Log Logger me.m1key.test.*.*) && this(a);

    before(Object objectWithLog): loggerAccessed(objectWithLog) {
        for (Field field : objectWithLog.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            if (field.getName().equals(thisJoinPoint.getSignature().getName())) {
                try {
                    if (field.get(null) == null) {
                        System.out.println("OMG I'm setting the value.");
                            field.set(objectWithLog, LoggerFactory.getLogger(objectWithLog.getClass()));
                    }
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (SecurityException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

I achieved what I wanted to achieve, but I had to use reflection. Also, this code fires every time log is accessed, although it is initialized only once (there’s a check). The code is pretty ugly and convoluted.
Shame, but that’s the best I could do.

Conclusion: use CDI for this purpose.

3 comments:

  1. Quite a neat trick and a good conclusion :-) Avoid static fields anyways, even if it's a logger IMHO.

    ReplyDelete
  2. Stumbled over your example, good stuff. Maybe not of interest to you anymore, but you can get the field more conveniently by

    Field field = ((FieldSignature) thisJoinPointStaticPart.getSignature())
    .getField();

    Cheers,

    Felix

    ReplyDelete