Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AspectJ pointcut on constructor object

I need to inject few methods to every initialized object using AspectJ.

I thought using this :

pointcut vistaInjection(Object o)
    : initialization(java.lang.Object.new() ) 
    && target(o)
    && !within(objectAspect);

before(Object o): methodInjection(o){System.err.println("INIT");}

to pointcut initialization of object, so I can inject these methods directly into the object that is part of every other object.

However, it does't work. Do you have any idea why? Or what may be an other way how to make 100% sure that every single initialized object will be pointcut? *.new does not work for stuff such String, Lists and others.

Thank you!

like image 546
Marosh Avatar asked Jun 27 '13 08:06

Marosh


People also ask

What is AspectJ pointcut?

AspectJ provides primitive pointcuts that capture join points at these times. These pointcuts use the dynamic types of their objects to pick out join points. They may also be used to expose the objects used for discrimination.

Is AspectJ used?

AspectJ is very widely used in a lot of Java frameworks (like Spring), but still most developers do not know AspectJ. Developers often think that AspectJ is difficult to learn or it makes your code complex, and they decide not to learn this very powerful and useful technology.

What is advice in AspectJ?

AspectJ supports three kinds of advice. The kind of advice determines how it interacts with the join points it is defined over. Thus AspectJ divides advice into that which runs before its join points, that which runs after its join points, and that which runs in place of (or "around") its join points.

What is Pointcut Java?

Pointcut is a set of one or more JoinPoint where an advice should be executed. You can specify Pointcuts using expressions or patterns as we will see in our AOP examples. In Spring, Pointcut helps to use specific JoinPoints to apply the advice.


2 Answers

User selig is right: You probably do not want to intercept all object creations, especially not those in JDK/JRE classes. But for what it is worth, here is an explanation of what works and how and what not:

A little driver application:

public class Application {
    public static void main(String[] args) {
        new Application();
        new String();
    }
}

An aspect with different types of constructor-related pointcuts/advice:

public aspect ObjectCreationAspect {
    before() : preinitialization(*.new(..)) && !within(ObjectCreationAspect) {
        System.out.println(thisJoinPointStaticPart);
    }

    before() : initialization(*.new(..)) && !within(ObjectCreationAspect) {
        System.out.println(thisJoinPointStaticPart);
    }

    before() : call(*.new(..)) && !within(ObjectCreationAspect) {
        System.out.println(thisJoinPointStaticPart);
    }

    before() : execution(*.new(..)) && !within(ObjectCreationAspect) {
        System.out.println(thisJoinPointStaticPart);
    }
}

The woven driver application's output:

call(Application())
preinitialization(Application())
initialization(Application())
execution(Application())
call(java.lang.String())

Explanation:

There are different types of weaving in AspectJ:

  • Compile-time weaving (CTW): Only classes which are compiled by ajc (AspectJ compiler) can be woven. This excludes JDK/JRE classes and also 3rd party libraries which you do not compile from source. the sample output from above shows the effect of compile-time weaving.
  • Binary weaving (BW): The AspectJ compiler is used to compile aspect code directly into existing byte code. This works with your own precompiled application classes as well as with 3rd party libraries. Theoretically it also works with JDK/JRE classes if you put rt.jar on the AspectJ compiler's in-path. JDK/JRE weaving is a bit tricky, but I have done it before. You can produce a newly woven version of rt.jar or just a small JAR file with a few woven JDK classes which then you prepend to the boot-classpath of the JDK/JRE when firing up your application.
  • Load-time weaving (LTW): Basically this is BW, but done dynamically during class-loading. In this AspectJ scenario you can only weave classes which are loaded by a classloader under the influence of an aspect weaver. Thus, it works with you own code and 3rd party libraries, but usually not with JDK/JRE bootstrapping classes which are loaded before the aspect weaver is loaded. It is a hen-and-egg type of problem: The weaver needs the JRE to be running before it can be loaded, but in order to weave JRE classes the weaver would have to be there before those classes are bootstrapped.

Now what you can easily do is intercept calls to JDK/JRE constructors from your own code oder woven 3rd party code, as you can see in the log output line saying call(java.lang.String()). You cannot intercept internal calls from JRE class to JRE class though.

Having said all that I really wonder what kind of horrible thing you want to do. I mean, you explain it and it sounds like a tremendous design error. Or you want to re-invent the wheel and write some kind of profiler or debugger which already exists. What do you expect from intercepting each single object creation? It would tremendously slow down your application, drastically increase memory consumption and create even more objects, if only the strings you are logging. Please reconsider and try to think about what you really want to do. Maybe then we can suggest a smart way of achieving your goal.

like image 121
kriegaex Avatar answered Sep 30 '22 07:09

kriegaex


Have you tried

pointcut vistaInjection(Object o)
    : (initialization(*.new()) || (initialization(*.new(..)))
    && target(o)
    && !within(objectAspect);

i.e. calling .new() on anything and allowing no and some arguments.

Note - you probably don't want to pick up all object creations.. what are you planning on doing with them!

like image 25
selig Avatar answered Sep 30 '22 05:09

selig