40

I have a problem with applying aspects to my maven project. Probably I am missing something, so I've made a list of steps. Could you please check if it is correct?

Let say in projectA is an aspect class and in projectB classes, which should be changed by aspects.

  • Create maven project ProjectA with AspectJ class
  • add Aspectj plugin and dependency
  • Add ProjectA as a dependency to projectB pom.xml
  • Add to projectB pom.xml plugin
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.4</version>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
                <goal>test-compile</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <source>${maven.compiler.source}</source>
        <target>${maven.compiler.target}</target>
        <aspectLibraries>
            <aspectLibrary>
                <groupId>ProjectA</groupId>
                <artifactId>ProjectA</artifactId>
            </aspectLibrary>
        </aspectLibraries>
    </configuration>
</plugin>
  • Add aspectj dependency

After all these steps my problem is, that during compilation I get:

[WARNING] advice defined in AspectE has not been applied [Xlint:adviceDidNotMatch]

And then when I run my program:

Exception in thread "FeatureExcutionThread" java.lang.NoClassDefFoundError: AspectE
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
alicjasalamon
  • 4,171
  • 15
  • 41
  • 65
  • There is a tutorial in [Jayway blog with](https://blog.jayway.com/2015/09/15/configuring-maven-to-use-standalone-aspects/) a [sample project in Github](https://github.com/Nosfert/AspectJ-Tutorial-jayway). -- If you look at the Github, the `example-sample project` project uses aspects defined in the `annotations-element-value-pair-without-main-class` project. The `pom.xml` uses the `aspectj-maven-plugin` and includes an `aspectLibraries` tags to point to the projects including aspects. – Jaime May 01 '18 at 19:00
  • See also: https://stackoverflow.com/a/16248351/59087 – Dave Jarvis Aug 24 '18 at 17:27

5 Answers5

52

I traced some of your older questions to try to find out what you actually are trying to do. I have come up with the following structure and code and for me it works well.

$ tree .
.
├── pom.xml
├── ProjectA
|   ├── pom.xml
|   └── src
|       └── main
|           └── aspect
|               └── com
|                   └── stackoverflow
|                       └── aspects
|                           ├── AspectL.java
|                           └── Trace.aj
└── ProjectB
    ├── pom.xml
    └── src
        └── main
            └── java
                └── com
                    └── stackoverflow
                        └── App.java

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.stackoverflow</groupId>
    <artifactId>Q12423965</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <name>${project.artifactId}-${project.version}</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.6</maven.compiler.source>
        <maven.compiler.target>1.6</maven.compiler.target>
    </properties>

    <modules>
        <module>ProjectA</module>
        <module>ProjectB</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.stackoverflow</groupId>
                <artifactId>Q12423965-ProjectA</artifactId>
                <version>${project.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.4</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.5.1</version>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

ProjectA/pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.stackoverflow</groupId>
        <artifactId>Q12423965</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>Q12423965-ProjectA</artifactId>

    <name>${project.artifactId}-${project.version}</name>

    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.11</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

I have created two differenct aspects. One that uses @AspectJ annotations and another one that is defined as a classic AspectJ aspect.

AspectL.java

package com.stackoverflow.aspects;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 * @author maba, 2012-09-18
 */
@Aspect
public class AspectL {

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

    @Before("defineEntryPoint()")
    public void aaa(JoinPoint joinPoint) {
        System.out.println("aspect before");
    }

    @After("defineEntryPoint()")
    public void bbb(JoinPoint joinPoint) {
        System.out.println("aspect after");
    }
}

Trace.aj

package com.stackoverflow.aspects;

public aspect Trace {
    pointcut publicMethodExecuted(): execution(public !static * *(..));

    after(): publicMethodExecuted() {
        System.out.printf("Enters on method: %s. \n", thisJoinPoint.getSignature());

        Object[] arguments = thisJoinPoint.getArgs();
        for (int i =0; i < arguments.length; i++){
            Object argument = arguments[i];
            if (argument != null){
                System.out.printf("With argument of type %s and value %s. \n", argument.getClass().toString(), argument);
            }
        }
        System.out.printf("Exits method: %s. \n", thisJoinPoint.getSignature());
    }
}

Those two files are part of the ProjectA module and are part of a jar.

Now we want to use these aspects and weave them into the code of ProjectB.

ProjectB/pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.stackoverflow</groupId>
        <artifactId>Q12423965</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>Q12423965-ProjectB</artifactId>

    <name>${project.artifactId}-${project.version}</name>

    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.11</version>
        </dependency>
        <dependency>
            <groupId>org.stackoverflow</groupId>
            <artifactId>Q12423965-ProjectA</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <configuration>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>org.stackoverflow</groupId>
                            <artifactId>Q12423965-ProjectA</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>com.stackoverflow.App</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

App.java

package com.stackoverflow;

/**
 * @author maba, 2012-09-17
 */
public class App {

    public void hello(String name) {
    }

    public static void main(String[] args) {
        App app = new App();
        app.hello("world");
    }
}

I build everything from top pom:

mvn clean install

And then go into the ProjectB directory and run the app:

mvn exec:java

The result is:

aspect before
Enters on method: void com.stackoverflow.App.hello(String). 
With argument of type class java.lang.String and value world. 
Exits method: void com.stackoverflow.App.hello(String). 
aspect after

So to conclude both aspects are working and the maven setup also works.

maba
  • 47,113
  • 10
  • 108
  • 118
  • 4
    It's really a very nice description about compile time weaving among Maven projects. I was searching for same. This is exactly what I wanted to have. Thanks for sharing this. – Narendra Verma Mar 25 '13 at 12:18
  • 1
    -1, because it simply doesn't work. I myself spent the whole day in trying to make that example work. It will work with Eclipse AJDT, but if you try to compile it with just maven it won't. You have to add `maven-shade-plugin` or `maven-assembly-plugin` the `aspectj` libs include in your jar. – user3663882 May 16 '15 at 10:45
  • 3
    -1 to @user3663882 too (if I could) for giving no detail about exactly what "doesn't work", no error message, no versions, no clue to what problem you encountered. – Ed Randall Jul 26 '17 at 09:58
  • @maba This answer is great. I've been searching the web for a similar tutorial for load time weaving, but to no avail :(. Basically, I don't want the user to add anything except the ProjectA dependency. Like having to remember to add `aspectj-maven-plugin` seems a little out of the way. I guess Load time weaving would help me get what I want. Can you validate what I'm saying & if it's correct, provide a detailed example for load tie weaving also? – Pankaj Singhal Aug 04 '18 at 15:31
  • @maba Can you please answer this [question](https://stackoverflow.com/questions/51693552/aspectj-aop-ltw-not-working-with-dynamic-loading-of-javaagent) ? – Pankaj Singhal Aug 05 '18 at 10:44
  • @pankaj I’m really sorry but my answer is from 2012 and I haven’t been working with AspectJ since then. You’all have to create a new question and hope that someone can answer your question. – maba Aug 05 '18 at 14:21
  • @maba Hey, thanks for your reply. I've asked a question - https://stackoverflow.com/questions/51693552/aspectj-aop-ltw-not-working-with-dynamic-loading-of-javaagent . Can you please see if it is something you can answer? – Pankaj Singhal Aug 05 '18 at 14:39
  • 1
    Thank you for the answer. I have converted this answer into the repo for quick tryout. https://github.com/brsanthu/aspectj-test – singularity Oct 04 '18 at 22:10
  • 1
    Thank you. If I could upvote 10 times I would. This is the missing simple and very useful 'how-to' guide to AspectJ in the real world. Great answer. – egelev Jun 29 '20 at 06:54
8

This worked for me, a had to add the lookup for external dependencies (see weaveDependencies) in order to perform weaving to them, you should include this in ProjectA pom file:

<dependencies>
  <dependency>
    <groupId>com.ProjectB</groupId>
    <artifactId>ProjectB</artifactId>
  </dependency>
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.6.5</version>
  </dependency>
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>aspectj-maven-plugin</artifactId>
      <version>1.2</version>
      <executions>
        <execution>
          <goals>
            <goal>compile</goal><!-- to weave all your main classes -->
            <goal>test-compile</goal><!-- to weave all your test classes -->
          </goals>
        </execution>
      </executions>
      <configuration>
        <weaveDependencies>

          <weaveDependency>
            <groupId>com.ProjectB</groupId>
            <artifactId>ProjectB</artifactId>
          </weaveDependency>
        </weaveDependencies>
        <showWeaveInfo>true</showWeaveInfo>

        <source>${maven.compiler.source}</source>
        <target>${maven.compiler.target}</target>
      </configuration>
    </plugin>
  </plugins>
</build>

Hope it helps...

Roland Illig
  • 417
  • 1
  • 5
  • 15
Carlos Castellanos
  • 2,358
  • 4
  • 25
  • 43
  • 1
    This introduces the reverse dependency A ---depends-on--> B. This is going to result in cyclic dependency. And we have to know in advance which apps will require weaving. – egelev Jun 29 '20 at 06:41
0

I had had the same problem as you. The only solution i found was to create a wrapper for each aspect class inside the aspectJ project to let external projects get access to it

Carlos
  • 9
  • 1
  • 1
    Great to hear you have solved this problem :) Unfortunately I don't understand explanation. Could you please provide me with more details/ example? – alicjasalamon Sep 14 '12 at 12:16
0

I remember having this problem too, but solved it by switching to Java annotation-based aspects. You could give that a try.

Rein
  • 478
  • 3
  • 3
  • 1
    I am using @AspectJ already, so unfortunately it cannot help. Do you remember any other changes you've made to make it work? – alicjasalamon Sep 14 '12 at 12:26
-1

Take a look at a real-life example:

  • This is a module where we define aspects and compile them: pom.xml.
  • This is how we use them, in another project: pom.xml (pay attention to highlighted lines).

The problem in your case is that you don't include ProjectA as a runtime dependency of ProjectB.

Jaime
  • 5,435
  • 2
  • 18
  • 21
yegor256
  • 102,010
  • 123
  • 446
  • 597