Actually, it will be more complex question. I want use AspectJ only in test purpose. Have found suggestion to use if() JointPoint and some static boolean field. Also, first I start using aspect as inner static class of my base test method. After some experiments I replaced it to own class, but actually don’t got the result, that I want. So, I just create some test project. Maven pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <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.example</groupId>
<artifactId>Testing</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<mockito.version>3.11.2</mockito.version>
<aspectj.version>1.9.7</aspectj.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M5</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-surefire-provider
-->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<!--<configuration>
<argLine>-javaagent:${user.home}/.m2/repository/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar</argLine>
</configuration>-->
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.14.0</version>
<configuration>
<complianceLevel>${maven.compiler.source}</complianceLevel>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
<executions>
<execution>
<goals>
<!-- use this goal to weave all your main classes -->
<goal>compile</goal>
<!-- use this goal to weave all your test classes -->
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Classes: A:
package classes;
public class A {
private String a = "classes.A";
public String getA()
{
return a;
}
public String getFromB()
{
return new B().getB();
}
}
B:
package classes;
public class B {
private String b = "classes.B";
public String getB() {
return b;
}
}
test class:
package aspectj;
import classes.A;
import classes.B;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class NewTest {
private static boolean useAspect = false;
public static boolean isUseAspect() {
return useAspect;
}
@BeforeEach
void init()
{
useAspect = true;
}
@Test
public void changeValue()
{
B b = new B();
System.out.println(b.getB());
}
@Test
public void changeValueInA()
{
A a = new A();
System.out.println(a.getFromB());
}
}
Aspect class
package aspectj;
import org.aspectj.lang.Aspects;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class AspectB {
@Pointcut("if()")
public static boolean useAspect()
{
return NewTest.isUseAspect();
}
@Pointcut("call(* classes.B.getB())")
public void callTestMethod() {}
@Around("callTestMethod()")
public String myAdvice(ProceedingJoinPoint point) throws Throwable {
return "You have been hacked!";
}
}
Main class:
package classes;
public class TestOutputHere {
public static void main(String[] args) {
System.out.println(new A().getFromB());
}
}
And I got result after running test and main method:
- changeValue() -> You have been hacked!
- changeValueInA() -> classes.B
- main(String[] args) -> classes.B
Second result dont feet for me... So after some experiments and removing test scope for AspectJ dependencies, removing if() JointPoint (we can't use test classes from src) and placing Aspect class in src I got the result:
- changeValue() -> You have been hacked!
- changeValueInA() -> You have been hacked!
- main(String[] args) -> You have been hacked!
Lust result dont feet to me too. And I really don’t want to use aspect for all project. After that I just tried to use some Load-Time weaving with configuration for maven surefire plugin:
<configuration>
<argLine>
-javaagent:${user.home}/.m2/repository/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
</argLine>
</configuration>
And I got result, that I want:
- changeValue() -> You have been hacked!
- changeValueInA() -> You have been hacked!
- main(String[] args) -> classes.B
So, where the question after thousands of these letters?) Questions are:
- Can I get this result with compile weaving and without using AspectJ classLoader?
- As I have performance restrictions in real project - how can AspectJ classLoader affect performance of non-test environment in this case?
- In case of load-time weaving that I describe - all classes of the project will recompile by AspectJ? Only test? How recompiling work in load-time?
I will greatfull for this answers!