Search code examples
aopaspectj

AspectJ, cannot intercept super() constructor call


I want to catch the super() for a subclass of java.io.FileInputStream with this class

package de.scrum_master.app;

class ABC {
    public ABC() {
        System.out.println("Ctr ABC");
    }
}

public class DEF extends ABC {
    public DEF() throws Exception {
       System.out.println("Ctr DEF");
    }

    static class MyFileInputStream extends java.io.FileInputStream {
        MyFileInputStream() throws Exception {
            super("de/scrum_master/app/ABC.java"); // HERE
        }
    };

    public static void main(String[] args) throws Exception {
        new MyFileInputStream();
        new DEF();
    }
}

I can catch the initialization between DEF and ABC like this:

@Before("initialization(de.scrum_master.app.DEF.new(..))")
public void test(JoinPoint thisJoinPoint) throws AuditReactiveException {
    System.err.println("Aspect DEF:"+thisJoinPoint);
}

but not with java.io.FileInputStream

 @Before("initialization(java.io.FileInputStream.new(..))")
    public void test2(JoinPoint thisJoinPoint) throws Exception {
        System.err.println("Aspect FileInpputStream:"+thisJoinPoint);
    }

Why? Thanks.


Solution

  • Simple question, simple answer: because FileInputStream is not part of your own code base, but part of the JDK/JRE. The JDK is beyond AspectJ's influence because its classes are part of the runtime which your application and its aspects are executed within. You can capture calls to JDK classes, but not executions. Maybe you are luckier with

    call(java.io.FileInputStream.new(..))
    

    P.S.: You can also weave aspects right into the JRE classes by creating an aspect-enriched version of e.g. rt.jar, but this is neither recommended nor trivial. I have done it though, just to see if it works. But resorting to such measures is usually rather a symptom for bad aspect design than a solution for a real problem.

    Update: Well, I forgot about the semantics of the call() pointcut. The AspectJ documentation says:

    Method call: When a method is called, not including super calls of non-static methods.

    So actually, without creating a woven JDK/JRE you cannot capture the super() call to or initialisation of a JDK/JRE constructor. If you use call() or preinitialization() pointcuts in your advice, at least you can be sure that logging occurs before a possible exception in the super constructor - initialization() occurs after the super constructor has been called.

    Update 2: See this discussion if you want to know technical details of why this does not work. Attention, this really is not for AspectJ newbies, I am just adding it as a reference for any other people stumbling upon this question.