2

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.

cb4
  • 6,689
  • 7
  • 45
  • 57
Binoy Dalal
  • 866
  • 10
  • 25
  • Have you added `@EnableAspectJAutoProxy` annotation on your bean configuration class? – Harshil Sharma Sep 26 '16 at 15:46
  • I am pretty new to both spring and aspectj so please correct me if I'm wrong. Will this be necessary seeing as I already have a spring config file where the aspect autoproxy has been set and I'm defining my beans there? – Binoy Dalal Sep 26 '16 at 17:06
  • Invoking the aspectj plugin in the `process-sources` phase is quite strange for me, as it precedes the normal compile phase. Is the default `maven-compiler-plugin` even disabled in your build? I'm not sure what would happen if it's not disabled, because then you would run both the aspectj compiler and the normal java compiler, the java compiler being invoked in a later phase than the phase in which the aspectj compiler is invoked, possibly overwriting the compiled classes create by the aspectj compile. Change your build so you're using only the aspectj compiler in the proper phase: `compile`. – Nándor Előd Fekete Sep 26 '16 at 18:26
  • @NándorElődFekete No, my `maven-compiler-plugin` wasn't disabled. I tried changing the `phase` for my ajc to `compile` but it did not work. I still got the message that join point was advised. I'm wondering if this has something to do with fact that I'm using the war created in this project to build an ear in another project which I'm then deploying. Let me know your thoughts. – Binoy Dalal Sep 27 '16 at 05:17
  • Try disabling `maven-compiler-plugin` completely and attach the aspectj compiler to the `compile` phase. – Nándor Előd Fekete Sep 27 '16 at 14:32
  • @NándorElődFekete I got it to work. Please check the answer and comment if you know why this worked. Thanks. – Binoy Dalal Sep 30 '16 at 07:00

1 Answers1

3

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.

Binoy Dalal
  • 866
  • 10
  • 25
  • Weird. I had the exact same problem. When I annotated my Aspect with @Component it suddenly got picked up by Spring. Unfortunately I don't know more. – Keya Kersting Mar 06 '19 at 16:53