Search code examples
javascalaaopaspectjaspectj-maven-plugin

Make aspectj work with scala model


I have a domain made in Scala and some classes made in Java. I need to make some aspects with Aspectj that I know that work because with a Java class and it works. The problem is that when the Scala class is annotated it does not work. Other annotations like hibernate's work well with my Scala class.

This is my 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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>Group</groupId>
    <artifactId>Parent</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.source-target.version>1.8</java.source-target.version>
        <aspectj.version>1.8.2</aspectj.version>
    </properties>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.6.1</version>
                    <configuration>
                        <source>${java.source-target.version}</source>
                        <target>${java.source-target.version}</target>
                        <useIncrementalCompilation>false</useIncrementalCompilation>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-antrun-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>createClassesDir</id>
                            <phase>process-resources</phase>
                            <configuration>
                                <tasks>
                                    <mkdir dir="${project.build.directory}\unwoven-classes" />
                                    <mkdir dir="${project.build.directory}\classes" />
                                </tasks>
                            </configuration>
                            <goals>
                                <goal>run</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.7</version>
                    <configuration>
                        <complianceLevel>1.8</complianceLevel>
                        <source>${aspectj.version>}</source>
                        <target>${aspectj.version>}</target>
                        <weaveDirectories>
                            <weaveDirectory>${project.build.directory}\unwoven-classes</weaveDirectory>
                        </weaveDirectories>
                    </configuration>
                    <executions>
                        <execution>
                            <phase>process-classes</phase>
                            <goals>
                                <goal>compile</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>net.alchim31.maven</groupId>
                    <artifactId>scala-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>scala-compile-first</id>
                            <phase>process-resources</phase>
                            <goals>
                                <goal>add-source</goal>
                                <goal>compile</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>scala-test-compile</id>
                            <phase>process-test-resources</phase>
                            <goals>
                                <goal>testCompile</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>${aspectj.version}</version>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>org.scala-lang</groupId>
                <artifactId>scala-library</artifactId>
                <version>2.12.1</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <modules>
        <module>Aspects</module>
    </modules>
</project>

I think that I have to do something with maven, because the aspects and the rest of the code works fine. Is there anyway to do that?

Thank you!


Solution

  • First of all, make sure your aspects (annotation-based or native syntax) always have a .aj file extension (add them to your project via "New aspect" instead of "New class" menu in whatever IDE you use). I have removed the duplicate class from your repo in my fork and renamed the other one accordingly. I chose the native syntax one, by the way.

    What was worse, though, is that you somehow expect unwoven Scala classes in a specific directory, but you did not configure the Scala plugin to actually put them there. I fixed that by adding this snippet:

    <configuration>
        <outputDir>${project.build.directory}/unwoven-classes</outputDir>
    </configuration>
    

    Now the AspectJ Maven plugin finds the Scala classes there and performs binary weaving upon them. This fixes both your Java and Scala test. Both of them failed in Maven before, now at least the Java one works in IntelliJ, but not the Scala one. This is due to the fact that IDEA does not know about this strange Maven setup with the additional (intermediate) directory of yours.

    So there is nothing wrong with the aspect as such or AspectJ being unable to work with Scala binaries. The project setup was wrong and in a way it still is with respect to IDE support.

    So how can you fix it completely? You have several options:

    • Put the aspect code into another Maven module and there configure a weave dependency on the Java + Scala module, weaving all classes from there into the aspect module. But then you might still have issues with running the tests. But at least you could configure the IDEA project for post-compile weaving with the right dependency.
    • You could also put the Scala code in its own module instead, define it as a dependency for the Java + AspectJ module and apply binary weaving to it that way.

    Other variants are possible. I do not want to over-analyse here, I just fixed your Maven setup in a quick and simple approach to get you going:

    $ mvn clean verify
    
    (...)
    -------------------------------------------------------
     T E S T S
    -------------------------------------------------------
    Aktive Codepage: 65001.
    Running aspects.AnnotationAspectTest
    set(String model.JavaEntity.name)
    set(String model.ScalaEntity.name)
    Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.055 sec
    
    Results :
    
    Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
    
    [INFO]
    [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ aspectj-with-scala ---
    [INFO] Building jar: C:\Users\Alexander\Documents\java-src\aspectj-with-scala\target\aspectj-with-scala-1.0-SNAPSHOT.jar
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    (...)
    

    P.S.: I have also created a pull request for you to easily integrate my changes into your repo.

    P.P.S.: See, an MCVE is more helpful than what you did before: Post a separate question only showing an aspect and then post this question here with only a Maven POM. I needed both plus the other classes in order to reproduce and solve the problem. After you published the GitHub project it was pretty straightforward to find and fix.