Search code examples
springspring-aopaspectj-maven-plugin

aspectj maven joinpoint advised but advice not called


Before marking this question as a duplicate, please read through, as I've gone through a number of posts on SO and other places but have still failed to find a solution to my problem.

I'm trying to implement a project in Spring + AspectJ and as the title says, I can see the aspectj maven plugin applying the advice but it isn't actually called.

I'm trying to apply an advice based on an annotation. Following is the annotation class:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface LogThis {
    String name();    
    int id();    
    int eventID();    
}

This annotation has been applied to a method which is being called from a js script on the front end through an ajax call. The method being called is as follows:

@RequestMapping(value = "/handle", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.NO_CONTENT)
@LogThis(name = "name", ID = 12345, eventID = 12345)
public void create(@RequestBody TodoDTO todo, HttpServletRequest req) {
    //perform some action
}

The advice is being applied to the LogThis annotation and the advice is as follows:

@Pointcut("@annotation(LogThis)")
public void genericPointcut() {
}

@Pointcut("execution(* *(..))")
public void atExecution() {
}

@Async
@Before("genericPointcut() && atExecution()")
public void logBefore(JoinPoint joinPoint) throws NoSuchMethodException, SecurityException {
// Perform logging
}

The annotation class and the aspect are in the same package while the class which is being advised is in a different package but everything is in the same project.

I've configured my maven pom.xml file as follows (only relevant portions shown):

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.8</version>
    <configuration>
        <showWeaveInfo>true</showWeaveInfo>
        <source>${java.source-target.version}</source>
        <target>${java.source-target.version}</target>
        <Xlint>ignore</Xlint>
        <complianceLevel>${java.source-target.version}</complianceLevel>
        <encoding>${project.build.sourceEncoding}</encoding>
        <verbose>true</verbose>
    </configuration>
    <executions>
        <execution>
            <phase>process-sources</phase>
            <goals>
                <goal>compile</goal>
                <goal>test-compile</goal>
            </goals>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>${aspectj.version}</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.2</version>
    <configuration>
        <warSourceDirectory>WebContent</warSourceDirectory>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </configuration>
</plugin>

The properties are:

<properties>
    <sonar.language>java</sonar.language>
    <java.source-target.version>1.7</java.source-target.version>
    <aspectj.version>1.8.7</aspectj.version>
</properties>

The aspectj dependencies are:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>4.1.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${aspectj.version}</version>
</dependency>

Spring version being used is 4.1.3.RELEASE.

The spring config entry for my aspect is as follows:

<aop:aspectj-autoproxy />    
<bean id="logAspect" class="somep2.LoggingAspect" />

On running mvn clean install the build succeeds and the following log entry is present w.r.t aspectj:

[INFO] --- aspectj-maven-plugin:1.8:compile (default) @ myproj ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[INFO] Join point 'method-execution(void somep.SomeC.create(param1, param2))' in Type 'somep.SomeC' (SomeC.java:63) advised by before advice from 'somep2.LoggingAspect' (LoggingAspect.java:36)
[INFO]
[INFO] --- aspectj-maven-plugin:1.8:test-compile (default) @ myproj ---
[WARNING] No sources found skipping aspectJ compile

According to the logs, the join point was found and advised but the logBefore() method is never called when the create() method is called. I am certain of this because I'm writing to a file using a FileWriter but nothing is being written.

Deployment details: This project is built as part of another project which creates an ear file which is then deployed on JBoss 6.3

I've tried numerous approaches but nothing has worked. Please let me know what I'm missing.

Any help is appreciated.


Solution

  • I finally got it to work. Turns out I was complicating things too much. There was no need for the aspectj compiler. All that I had to do was tell spring that my aspect was a component as well so that it could inject my advice.

    So here's the complete list of changes:

    1. Removed the aspectj-maven-plugin from pom.xml. It is not required.
    2. Removed the aspectj-tools and spring-aop dependencies and added the aspectj-weaver dependency to pom.xml
    3. Removed the bean entry for my aspect from the spring config.
    4. Annotated my aspect class with @Component and made sure that it was being scanned as part of the Spring component scan.

    Hope this helps someone else as well.

    PS. I still do not completely understand why this worked so if someone has an explanation, please comment.