0

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!

kriegaex
  • 63,017
  • 15
  • 111
  • 202
Motomine
  • 4,205
  • 5
  • 20
  • 23

2 Answers2

1

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.

Community
  • 1
  • 1
kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • Thank you very much! This solution works perfect on the project that I uploaded, I've already accepted the pull request and modified it a little bit to make it multi module. Thanks for your patience and help! – Motomine Apr 15 '17 at 02:08
  • I've just posted my last question [here](http://stackoverflow.com/questions/43422025/using-aspectj-when-i-run-the-application-with-tomcat), could you please help me with that if possible?? Thank you! – Motomine Apr 15 '17 at 04:22
  • For all the others who might read this: @Motomine's multi-module setup was broken, the tests all failed in Maven and for me also in IntelliJ IDEA. If fixed it in my [fork](https://github.com/kriegaex/aspectj-with-scala) and also issued another pull request. So if anyone is looking for a showcase for a Scala-enabled AspectJ multi-module setup, you find it there. – kriegaex Apr 15 '17 at 13:53
0

The problem is likely that aspects are often applied to the semantics of your java code - "find a method with a name like X and do the following around it." But Scala code, when viewed from Java, typically does not follow expected naming conventions. Without more detail on the specific pointcuts being made - and the code on which they're being applied - I couldn't give any more insight.

Keith Nordstrom
  • 354
  • 2
  • 9
  • I agree. As I said in your other question, please publish a complete [MCVE](http://stackoverflow.com/help/mcve) with code and build configuration on GitHub. Maybe then I can find a solution for you by analysing your setup. – kriegaex Apr 14 '17 at 10:21
  • I see your point and I understand it, but when I use annotation this might not happen I think. Is a lot of code, I will upload what I have to GitHub in a while to see if you can help me. Thank you – Motomine Apr 14 '17 at 15:34
  • @kriegaex I've just uploaded a complete example [here](https://github.com/tsandler/aspectj-with-scala). With this example the test that runs with the Java class works, while the one with the Scala class fails – Motomine Apr 14 '17 at 16:11
  • Well, my best shot is that you've applied your annotation to `var name`. Your set pointcut is expecting a property called "name" with a method that sets it, but like everything else on a scala object, it's implemented as methods rather than a field (you can see this from your java code by writing `new ScalaEntity().name();`). In this case, the implementation is going to be two methods, overloaded because var is mutable. AspectJ is probably even looking for "setName" if previous experience with aspects can be trusted. But nothing about the methods on ScalaEntity conform to that standard. – Keith Nordstrom Apr 14 '17 at 16:41
  • I understand what you say, but writing a method setName and calling it it does not work neither. I think it might be a way to do it, maybe because the scala classes are compiled after the aspect. Is that the solution that you suggested? – Motomine Apr 14 '17 at 17:48
  • You have a set pointcut so you'd have to annotate the internal field in the generated scala class to make that work. My suggestion would be to write a method in scala, try to access it via java (to verify the semantics), and write a new pointcut specifically designed to match its format. – Keith Nordstrom Apr 14 '17 at 18:04
  • I can access any method written in Scala from Java, but Scala auto generates the accessors, which are name() and name =, which translated to Java is name_$eq. The pointcut that I'm trying to implement is for a field, not for a method,I want to intercept every time a value is assigned to it – Motomine Apr 14 '17 at 18:54
  • As my own answer shows, the problem is not any hypothetic Scala vs. AspectJ incompatibility but simply the faulty Maven setup. – kriegaex Apr 14 '17 at 20:50
  • Good to know, worth a shot! Glad you figured it out. – Keith Nordstrom Apr 15 '17 at 01:30