I'm building up a simple project to learn aspectj.
It's from aspect in action 2nd and the idea is very simple ---- the MessageCommunicator will be responsible for delivering the message and it's the main business logic. Meanwhile, Authenticator will be responsible for authentication and will be weaved as declared SecurityAspect.
Though it's very straightforward to see in the log that the aspect is working. Still I want to ensure it works in junit case.
In my project, I'm using maven 3.0.4 with aspectj 1.7.3 and aspect-maven-plugin 1.5.
Now the problem is below warning is there when compile the test case. As the consequence, the aspects in test package doesn't work. However, if you write a Main class in source package and run, the aspect in source package will work.
The warning message while build:
[INFO] --- aspectj-maven-plugin:1.5:test-compile (test-compile_with_aspectj) # aspectj ---
[WARNING] advice defined in org.javen.study.aspectj.c02.aspects.MockAuthenticationAspect has not been applied [Xlint:adviceDidNotMatch]
[WARNING] advice defined in org.javen.study.aspectj.c02.aspects.SecurityAspect has not been applied [Xlint:adviceDidNotMatch]
[WARNING] advice defined in org.javen.study.aspectj.c02.aspects.TrackingAspect has not been applied [Xlint:adviceDidNotMatch]
I will also attach all the related source code below:
MessageCommunicator who is responsible for the main business:
package org.javen.study.aspectj.c02;
public class MessageCommunicator {
public void deliver(String message) {
System.out.println(message);
}
public void deliver(String person, String message) {
System.out.println(person + ", " + message);
}
}
Simple version of authenticator which will do the authentication:
public class Authenticator {
public void authenticate() {
System.out.println("authenticated");
}
}
SecurityAspect which will advice on MessageCommunicator:
package org.javen.study.aspectj.c02.aspects;
import org.javen.study.aspectj.c02.Authenticator;
public aspect SecurityAspect {
private Authenticator authenticator = new Authenticator();
declare warning
: call(void Authenticator.authenticate())
&& !within(SecurityAspect)
: "Authentication should be performed only by SecurityAspect";
pointcut secureAccess() : execution(* org.javen.study.aspectj.c02.MessageCommunicator.deliver(..));
before() : secureAccess() {
System.out.println("Checking and authenticating user");
authenticator.authenticate();
}
}
MockAuthenticationAspect in test package to advice the authenticator to inject some verification logic(no need to look into advice detail, the advice implementation is problematic):
package org.javen.study.aspectj.c02.aspects;
import org.javen.study.aspectj.c02.Authenticator;
public aspect MockAuthenticationAspect {
declare parents: Authenticator implements Callable;
private boolean Callable.isCalled;
public void Callable.call() {
isCalled = true;
}
public boolean Callable.isCalled() {
return isCalled;
}
Object around(Callable accessTracked) : execution(* Authenticator.authenticate(..))
&& !execution(* Callable.*(..))
&& this(accessTracked) {
accessTracked.call();
return null;
}
private static interface Callable {
}
}
The pom of whole project:
<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.javen.study</groupId>
<artifactId>aspectj</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<aspectj.version>1.7.3</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<executions>
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.5</version>
<configuration>
<complianceLevel>1.6</complianceLevel>
<includes>
<include>**/*.java</include>
<include>**/*.aj</include>
</includes>
</configuration>
<executions>
<execution>
<id>compile_with_aspectj</id>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile_with_aspectj</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
When build with command "mvn clean install", the warning texts will be printed and the test package advice will not work. However, if check with AJDT in eclipse, all the pointcut and advice is working.
Could someone help me? Thanks a lot.
The problem is solved by added below configuration in test-compile execution.
<execution>
<id>test-compile_with_aspectj</id>
<goals>
<goal>test-compile</goal>
</goals>
<configuration>
<weaveDirectories>
<weaveDirectory>target/classes</weaveDirectory>
</weaveDirectories>
</configuration>
</execution>
Don't know it's a good pratice or not, but at least now it works.
Related
I'm trying to run a little annotation over function that will log before and after the method execution.
What I've done: (all classes are under src/main/kotlin)
Annotation class
#Target(AnnotationTarget.FUNCTION)
#Retention(AnnotationRetention.RUNTIME)
annotation class LogMe
Aspect class
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
#Aspect
abstract class Aspect {
#Around("#annotation(LogMe) && execution(* *(..))")
fun logMe(joinPoint: ProceedingJoinPoint): Any {
beforeExecution(joinPoint)
afterExecution(joinPoint)
return joinPoint.proceed()
}
private fun beforeExecution(joinPoint: JoinPoint) {
println("[${joinPoint.signature.name} has started its execution]")
}
private fun afterExecution(joinPoint: JoinPoint) {
println("[${joinPoint.signature.name} has ended its execution]")
}
}
Foo class with annotated method
class Foo {
#LogMe
fun yourMethodAround() {
println("Executing foo.yourMethodAround()")
}
}
main file
fun main(args: Array<String>) {
val foo = Foo()
foo.yourMethodAround()
}
my POM.xml (cut version)
...
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>1.3.40</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>1.3.40</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.4</version>
</dependency>
<!-- TEST -->
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>1.3.40</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit</artifactId>
<version>1.3.40</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/kotlin</sourceDirectory>
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<jvmTarget>1.8</jvmTarget>
</configuration>
<groupId>org.jetbrains.kotlin</groupId>
<version>1.3.40</version>
<executions>
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
</execution>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals> <goal>compile</goal> </goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals> <goal>test-compile</goal> </goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-maven-plugin</artifactId>
<version>0.14.1</version>
<executions>
<execution>
<goals>
<goal>ajc</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>MainKt</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
When I basically run this main, what I'm obtaining is the println that it's into my Foo class method:
Executing foo.yourMethodAround()
But I'm not getting the before and after execution prinln that I was expecting from the Aspect class.
Does any of you ever faced this issue before? This is struggling me, because I can't understand what's going on here.
Disclaimer:
I have never used the Jcabi plugin before, normally I always use AspectJ Maven plugin, also for binary weaving.
I have never used the Kotlin language before, normally I use Java or Groovy.
Now some things are not okay in your aspect:
It must not be abstract, otherwise no instance can be created.
For void methods it must be able to return null, so the Kotlin return type should be Any?
You should proceed() in between the before and after log messages, otherwise the log output will be wrong.
Assuming that your classes, especially the annotation class, do not reside in the default package but have an actual package name, you need to use the fully qualified class name in your pointcut, e.g. #annotation(de.scrum_master.app.LogMe)
Using an aspect class name Aspect, i.e. the same name as the #Aspect annotation, just in another package, is kind of ugly. You should rename it.
For me this works nicely:
package de.scrum_master.aspect
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
#Aspect
class LogAspect {
#Around("#annotation(de.scrum_master.app.LogMe) && execution(* *(..))")
fun logMe(joinPoint: ProceedingJoinPoint): Any? {
beforeExecution(joinPoint)
val result = joinPoint.proceed()
afterExecution(joinPoint)
return result
}
private fun beforeExecution(joinPoint: JoinPoint) {
println("[${joinPoint.signature.name} has started its execution]")
}
private fun afterExecution(joinPoint: JoinPoint) {
println("[${joinPoint.signature.name} has ended its execution]")
}
}
Besides, maybe you also should configure the Jcabi plugin to language level Java 8. It works without it here, but maybe it is better depending on which language features you use:
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
My console after mvn clean verify looks like this:
$ java -jar target/so-aj-kotlin-56890630-1.0-SNAPSHOT.jar
[yourMethodAround has started its execution]
Executing foo.yourMethodAround()
[yourMethodAround has ended its execution]
My IDE IntelliJ IDEA does not quite pick up the binary weaving stuff because it does not know Jcabi, only AspectJ Maven. So I just configured the project to delegate compilation to Maven:
Then the log output is the same when running the application from IDEA directly.
I followed this SO question and tried to implement it for java8. My project is not a spring project.
Aspect
#Aspect
public class MethodLogger {
#Pointcut("execution(#org.junit.Test * *())")
public void testMethodEntryPoint() {}
#Before("testMethodEntryPoint()")
public void executeBeforeEnteringTestMethod() {
System.out.println("EXECUTE ACTION BEFORE ENTERING TEST METHOD");
}
#After("testMethodEntryPoint()")
public void executeAfterEnteringTestMethod() {
System.out.println("EXECUTE ACTION AFTER ENTERING TEST METHOD");
}
}
JUnit Test
#RunWith(JUnit4.class)
public class POSTaggerTest {
#Test
public void test() {
...
}
}
POM.xml
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<aspectLibraries>
<aspectLibrary>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</aspectLibrary>
</aspectLibraries>
<!-- java version -->
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<!-- End : java version -->
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
<configuration>
<showWeaveInfo>true</showWeaveInfo>
</configuration>
</execution>
</executions>
</plugin>
:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.2</version>
</dependency>
<dependency>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<type>maven-plugin</type>
</dependency>
I don't see any error. Am I missing something? Or any wrong artifact? What I want when I run junit tests, all the aspects whould work fine.
The situation you want to recreate is like this:
There is one Maven module with aspects. It is compiled with AspectJ Maven Plugin.
There is another module with the actual application and test code. It is also compiled with AspectJ Maven, this time referring to the first module as an aspect library.
What you are doing though is:
You have a single module. This is not a problem in and of itself because it is easily possible to keep aspects and Java code within the same module if you want the aspects applied on this module only.
But now you declare JUnit as an aspect library. Why? It does not contain any aspects. You should remove that declaration.
I'm creating a maven plugin, MVN clean install build succeeds but plugin.xml is not getting generated.
#Mojo( name = "cover", defaultPhase = LifecyclePhase.POST_INTEGRATION_TEST)
public class RunCoverage extends AbstractMojo
{
#Parameter( property = "cover.wadl", defaultValue = "test")
private String wadl;
#Parameter( property = "cover.endpoints",defaultValue = "test")
private String endpoints;
#Override
public void execute() throws MojoExecutionException
{
<somecode>
}
}
And the pom.xml is
<?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>
<artifactId>end-point-test-coverage</artifactId>
<version>1</version>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.2</version>
<executions>
<execution>
<id>default-descriptor</id>
<goals>
<goal>descriptor</goal>
</goals>
<phase>process-classes</phase>
</execution>
<execution>
<id>help-descriptor</id>
<goals>
<goal>helpmojo</goal>
</goals>
<phase>process-classes</phase>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Maven clean install doesn't generate plugin.xml
When used in a dependent project, I'm getting the following error
Failed to parse plugin descriptor for it.gruppopam.common:end-point-test-coverage:1 (/home/d/.m2/repository/it/common/end-point-test-coverage/1/end-point-test-coverage-1.jar): No plugin descriptor found at META-INF/maven/plugin.xml -> [Help 1]
[ERROR]
First i would try to set the packaging type to maven-plugin instead of the default which is jar. Furthermore i would suggest to use more up-to-date versions of plugins (maven-compiler-plugin: 3.1) and use a more up-to-date version of maven-plugin-api (3.0? but not 2.0).
you have to remember to change it in your pom.xml to:
<packaging>maven-plugin</packaging>
it is by default:
<packaging>jar</packaging>
I have a JPA Entity class and am trying to secure the remove method by adding a secured annotation to that method. My JPA entities are not defined in my application context xml so I have used the following in my context.xml to try to enable Aspect J.
<sec:global-method-security secured-annotations="enabled" mode="aspectj" />
I am using a maven plugin to do static compile time weaving and in my log I can see no issues
Generating code...
[INFO]
[INFO] --- aspectj-maven-plugin:1.2:compile (default) # SubmissionTool ---
[WARNING] advice defined in org.springframework.scheduling.aspectj.AbstractAsyncExecutionAspect has not been applied [Xlint:adviceDidNotMatch]
[WARNING] advice defined in org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl has not been applied [Xlint:adviceDidNotMatch]
[WARNING] advice defined in org.springframework.mock.staticmock.AbstractMethodMockingControl has not been applied [Xlint:adviceDidNotMatch]
[INFO]
My JPA entity that I have defined the annotation on is a abstract class and it has child classes that use the remove method. The following annotations exists on my JPA class
#Entity
#Configurable
and the remove method is like
#Transactional
#Secured(value = {"ROLE_ADMINS"})
public void remove() {
if (this.entityManager == null) this.entityManager = entityManager();
if (this.entityManager.contains(this)) {
this.entityManager.remove(this);
} else {
Submission attached = Submission.findSubmission(this.id);
this.entityManager.remove(attached);
}
}
The Role ROLE_ADMINS should only allow those users with that role to delete a entity however all users are able to delete the entity. Any ideas?
Below is how my pom looks for weaving plugin
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.2</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<configuration>
<sources>
<source>
<basedir>src/main/java/</basedir>
<includes>
<include>**/entity/*.java</include>
</includes>
</source>
</sources>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
I banged my head for two days to integrate aspectj with maven, But did not work.
I am writing a simple program with two advices (which works fine in eclipse, so I am sure it's not a code side error).
I have recently started using maven for project building. Can't think of why I am not able to kick off aspectj compiler.
During compilation through maven - I get only class file for java without weaving. .aj file is not compiled.
Please Help!!!!
the first aspect file - ExceptionAspects.aj
package com.aspectSample;
public aspect ExceptionAspects {
pointcut ExceptionHandler(Exception e) : handler(Exception+) && args(e) && within(com.clickable.*);
pointcut callbeforeMethod():execution( public void HelloWorldExclude.*(..)) ;
before(Exception ex) : ExceptionHandler(ex)
{
System.out.println("Added Aspects before Exception :"+ex.toString());
}
before(): callbeforeMethod()
{
System.out.println("Aspect Before Method Call");
}
pointcut sysOutOrErrAccess() : get(* System.out) || get(* System.err);
declare error
: sysOutOrErrAccess()
: "Don't write to the console";
}
The source java file HelloWorldExclude.java
package com.aspectSample;
import java.sql.SQLException;
public class HelloWorldExclude {
private void FoulIntro(String message, String name) throws SQLException
{
throw new SQLException("WriteSomething");
}
public void GiveMeFoulIntro(String message, String name)
{
try
{
this.FoulIntro(message, name);
}catch(SQLException exp)
{
System.out.println("catching exception");
}
}
}
and the pom.xml file is
<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>com.clickable.HelloWorld-Maven</groupId>
<artifactId>HelloWorldAspect-Maven</artifactId>
<version>1.0.0</version>
<name>HelloWorld Aspect</name>
<packaging>jar</packaging>
<description>Hello World Code</description>
<properties>
<java-version>1.6</java-version>
<org.aspectj-version>1.6.11</org.aspectj-version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
</dependencies>
</project>
A couple of things that you can try:
Explicitly provide the dependencies of the maven-aspectj plugin:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.4</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
with the version of aspectjrt and aspectjtools matching the version of aspectj that you are using.
Do you by any chance have any of your sources in the test folder,
with the src/test folder, then to weave the aspects to the test sources you will have to explicitly mention that in the maven-aspectj plugin:
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
There was a stupid mistake in pom file.
aspectj plugin was added under element, which is just a configuration of all plugins. It doesn't tell compiler what to use.
It worked as soon as I removed plugin out of this element.
Thanks
Pankaj