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.

4 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
  3. Qatar's national anthem is called 'As Salam al Amiri', which in English means 'Peace to the Amir'. It was adopted in 1996. The lyrics were written by Sheikh Mubarak bin Saïf al-Thani and the music was written by Abdul Aziz Nasser Obaidan. http://www.confiduss.com/en/jurisdictions/qatar/culture/

    ReplyDelete