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
    Replies
    1. Great Article android based projects

      Java Training in Chennai

      Project Center in Chennai

      Java Training in Chennai

      projects for cse

      The Angular Training covers a wide range of topics including Components, Angular Directives, Angular Services, Pipes, security fundamentals, Routing, and Angular programmability. The new Angular TRaining will lay the foundation you need to specialise in Single Page Application developer. Angular Training

      Delete
  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