Hot questions for Using AspectJ in aspect

Question:

I have this working code for a specific package, but i want to configure it for all controllers, service and dao packages Eg

  • com.abc.xyz.content.controller
  • com.abc.xyz.content.service
  • com.abc.xyz.content.dao
  • com.abc.xyz.category.controller
  • com.abc.xyz.category.service
  • com.abc.xyz.category.dao

and so on. . . that is the base package of my project, can someone please help how I can go about doing it so that it works for all classes of my web project including controllers, thanks in advance. . .

package com.abc.xyz.utilities;

import java.util.Arrays;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect
{
    private Log log = LogFactory.getLog(this.getClass());

    @Pointcut("execution(* com.abc.xyz.content.service..*(..))")
    protected void loggingOperation()
    {
    }

    @Before("loggingOperation()")
    @Order(1)
    public void logJoinPoint(JoinPoint joinPoint)
    {
    log.info("Signature declaring type : " + joinPoint.getSignature().getDeclaringTypeName());
    log.info("Signature name : " + joinPoint.getSignature().getName());
    log.info("Arguments : " + Arrays.toString(joinPoint.getArgs()));
    log.info("Target class : " + joinPoint.getTarget().getClass().getName());
    }

    @AfterReturning(pointcut = "loggingOperation()", returning = "result")
    @Order(2)
    public void logAfter(JoinPoint joinPoint, Object result)
    {
    log.info("Exiting from Method :" + joinPoint.getSignature().getName());
    log.info("Return value :" + result);
    }

    @AfterThrowing(pointcut = "execution(* com.abc.xyz.content.service..*(..))", throwing = "e")
    @Order(3)
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e)
    {
    log.error("An exception has been thrown in " + joinPoint.getSignature().getName() + "()");
    log.error("Cause :" + e.getCause());
    }

    @Around("execution(* com.abc.xyz.content.service..*(..))")
    @Order(4)
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable
    {
    log.info("The method " + joinPoint.getSignature().getName() + "() begins with " + Arrays.toString(joinPoint.getArgs()));
    try
    {
        Object result = joinPoint.proceed();
        log.info("The method " + joinPoint.getSignature().getName() + "() ends with " + result);
        return result;
    }
    catch (IllegalArgumentException e)
    {
        log.error("Illegal argument " + Arrays.toString(joinPoint.getArgs()) + " in " + joinPoint.getSignature().getName() + "()");
        throw e;
    }
    }

}

Answer:

How about one of these alternatives?

A) General execution pointcut with package restrictions:

execution(* *(..)) &&
(
    within(com.abc.xyz..controller..*) ||
    within(com.abc.xyz..service..*) ||
    within(com.abc.xyz..dao..*)
)

B) Package-restricted execution pointcuts:

execution(* com.abc.xyz..controller..*(..)) ||
execution(* com.abc.xyz..service..*(..)) ||
execution(* com.abc.xyz..dao..*(..))

I prefer B, by the way, just because it is a bit shorter and easier to read. As you have probably guessed, the .. notation means "any package or subpackage", whereas * at the end of the expression after .. means "any method in any class".

Question:

i have a Java EE Webservice (REST) and would now like to use AspectJ, to create a rule that will print-out every incoming service call and their params.

I just read this tutorial and implemented the following code:

POM.XML

        <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.10</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.10</version>
    </dependency>

</dependencies>
<build>
  <plugins>
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.7</version>
        <configuration>
            <complianceLevel>1.8</complianceLevel>
            <source>1.8</source>
            <target>1.8</target>
            <showWeaveInfo>true</showWeaveInfo>
            <verbose>true</verbose>
            <Xlint>ignore</Xlint>
            <encoding>UTF-8 </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>

...and created a Test.aj File, with a Pointcut which should print-out a teststring after calling the getSignOfLife():

import de.jack.businesspartner.service.BusinessPartnerServiceImpl;
public aspect TestAspectJ {

    pointcut getSignOfLife() : 
      call(void BusinessPartnerServiceImpl.getSignOfLife());

    before() : getSignOfLife() {
        System.err.println("ADKL TEST ASPECT");
    }

}

--> But nothing happens if i call the getSignOfLife() Method. Can you help me?


Answer:

Your point cut expression may be wrong:

pointcut getSignOfLife() : 
  call(void BusinessPartnerServiceImpl.getSignOfLife());

The expression in call should match the signature of your real method.

CheckList
  • return type: getSignOfLife seems has a return value, which you write a void return type in expression, which will fails the match;
  • parameter type: you can use f(..) to represent a method f with any parameter, but if you left it empty, it means no parameter. If your actual method has parameter, it will fails the match;
  • notice that int and Integer is different in expression, because primitives and boxing type is different;
  • you need original compiler plugin of maven in your pom;

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
    
More
  • You may refer to here if you want to dive into AspectJ
  • In the most common cases, Spring AOP is enough to handle jobs like logging, auth etc, which can be used with annotation and I think, is more convenient.
  • Runnable code.

Question:

Can anyone explain the difference between this() and target() pointcuts in aspectj. I tried finding this elsewhere but there doesnt seem to be a clear cut answer. Thank You


Answer:

At a matching join point, this() is the object you are in, target() is the object you are invoking/referencing. The confusion may arise because in the case of an execution() pointcut matching on a joint point they are the same thing - the object containing the execution join point which matched is the same as the object running the method you are matching on. But in the case of a call() join point they are different. The object making the call is different from the object on which the method is being called.

class A {
  public void m() {
    B b = new B();
    b.n();
  }
}
class B {
  public void n() {
  }
}

For that setup, the pointcut execution(* m(..)) will match on join point A.m() and have a this() of type A and target() of type A (and they will be the same instance of A). However the pointcut call(* n(..)) will match at the call site in method A.m() where it calls n() and at that point this() will be the instance of A making the call whilst target() will be the instance of B that the method is being invoked upon.

Question:

I build small library (Java and Maven) - using AspectJ. Library must be independent. Library deliver Aspects and Annotations. Function of library is - "call advice when executed a method with specific annotation". All is ok when I use everything in one module, but problem appers when i separate library and project with classes which advice must be applied. I create simple schema. Library B - my library (aspects and annotations) Project A - project with buisness methods which adivce must be applied Is any posibility to do this?


Answer:

According to the AspectJ Maven documentation, chapter "using aspect libraries", you need to

  • add the aspect library as a regular <dependency>,
  • also add the same dependency (without <version> because it is already assigned in step 1) in the plugin <configuration><aspectLibraries> section as an <aspectLibrary>.

Here is a concrete example:

Aspect library POM, marker annotation and sample aspect:

<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>de.scrum-master.stackoverflow</groupId>
    <artifactId>aspectj-lib</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <name>AspectJ Library</name>

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

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.3</version>
                    <configuration>
                        <source>${java.source-target.version}</source>
                        <target>${java.source-target.version}</target>
                        <!-- IMPORTANT -->
                        <useIncrementalCompilation>false</useIncrementalCompilation>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.7</version>
                    <configuration>
                        <!--<showWeaveInfo>true</showWeaveInfo> -->
                        <source>${java.source-target.version}</source>
                        <target>${java.source-target.version}</target>
                        <Xlint>ignore</Xlint>
                        <complianceLevel>${java.source-target.version}</complianceLevel>
                        <encoding>${project.build.sourceEncoding}</encoding>
                        <!--<verbose>true</verbose> -->
                        <!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn> -->
                    </configuration>
                    <executions>
                        <execution>
                            <!-- IMPORTANT -->
                            <phase>process-sources</phase>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                    <dependencies>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjtools</artifactId>
                            <version>${aspectj.version}</version>
                        </dependency>
                    </dependencies>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
            </plugin>
            <!--
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
            -->
        </plugins>
    </build>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>${aspectj.version}</version>
                <scope>runtime</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

    <organization>
        <name>Scrum-Master.de - Agile Project Management</name>
        <url>http://scrum-master.de</url>
    </organization>

</project>
package de.scrum_master.aspect;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Marker {}
package de.scrum_master.aspect;

public aspect MyAspect {
    before() : execution(* *(..)) && @annotation(Marker) {
        System.out.println(thisJoinPoint);
    }
}

Now run mvn clean install on the aspect library project so as to install the dependency into your local Maven repo.

Java application POM and sample application:

By the way, in the POM I have also added two optional plugins:

  • One-JAR plugin packages your application with all dependencies (e.g. aspect library and AspectJ runtime) into one artifact, here target/java-app-0.0.1-SNAPSHOT.one-jar.jar. You can just run your application via java -jar target/java-app-0.0.1-SNAPSHOT.one-jar.jar.
  • Exec Maven plugin is useful if you easily want to test your application from the command line via mvn clean install exec:java.

These two are only for convenience, you do not need them if you dislike them.

<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>de.scrum-master.stackoverflow</groupId>
    <artifactId>java-app</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <name>Java Application</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.source-target.version>1.8</java.source-target.version>
        <aspectj.version>1.8.7</aspectj.version>
        <main-class>de.scrum_master.app.Application</main-class>
    </properties>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.3</version>
                    <configuration>
                        <source>${java.source-target.version}</source>
                        <target>${java.source-target.version}</target>
                        <!-- IMPORTANT -->
                        <useIncrementalCompilation>false</useIncrementalCompilation>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.7</version>
                    <configuration>
                        <!--<showWeaveInfo>true</showWeaveInfo> -->
                        <source>${java.source-target.version}</source>
                        <target>${java.source-target.version}</target>
                        <Xlint>ignore</Xlint>
                        <complianceLevel>${java.source-target.version}</complianceLevel>
                        <encoding>${project.build.sourceEncoding}</encoding>
                        <!--<verbose>true</verbose> -->
                        <!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn> -->
                        <aspectLibraries>
                            <aspectLibrary>
                                <groupId>de.scrum-master.stackoverflow</groupId>
                                <artifactId>aspectj-lib</artifactId>
                            </aspectLibrary>
                        </aspectLibraries>
                    </configuration>
                    <executions>
                        <execution>
                            <!-- IMPORTANT -->
                            <phase>process-sources</phase>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                    <dependencies>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjtools</artifactId>
                            <version>${aspectj.version}</version>
                        </dependency>
                    </dependencies>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>1.4.0</version>
                    <configuration>
                        <mainClass>${main-class}</mainClass>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.dstovall</groupId>
                    <artifactId>onejar-maven-plugin</artifactId>
                    <version>1.4.4</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>one-jar</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <onejarVersion>0.96</onejarVersion>
                        <mainClass>${main-class}</mainClass>
                        <attachToBuild>true</attachToBuild>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
            </plugin>
            <!--
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
            </plugin>
            -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <configuration>
                    <mainClass>${main-class}</mainClass>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.dstovall</groupId>
                <artifactId>onejar-maven-plugin</artifactId>
                <configuration>
                    <mainClass>${main-class}</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <pluginRepositories>
        <pluginRepository>
            <id>OneJAR googlecode.com</id>
            <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
        </pluginRepository>
    </pluginRepositories>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>${aspectj.version}</version>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>de.scrum-master.stackoverflow</groupId>
                <artifactId>aspectj-lib</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
        </dependency>
            <dependency>
                <groupId>de.scrum-master.stackoverflow</groupId>
                <artifactId>aspectj-lib</artifactId>
            </dependency>
    </dependencies>

    <organization>
        <name>Scrum-Master.de - Agile Project Management</name>
        <url>http://scrum-master.de</url>
    </organization>

</project>

This little driver application demonstrates that you can now annotate methods with @Marker, in this case only foo and zot, but not bar:

package de.scrum_master.app;

import de.scrum_master.aspect.Marker;

public class Application {
    @Marker
    public static void foo() {}

    public static void bar() {}

    @Marker
    public static void zot() {}

    public static void main(String[] args) {
        foo();
        bar();
        zot();
    }
}

Console log:

java -jar target/java-app-0.0.1-SNAPSHOT.one-jar.jar

execution(void de.scrum_master.app.Application.foo())
execution(void de.scrum_master.app.Application.zot())

Question:

I'm developing a java (JDK1.6) application with Spring framework(4.0.5) and AspectJ for AOP Logging.

My Aspect classes work fine but I can't create a pointcut for constructor object.

This is my object:

@Controller
public class ApplicationController {
    public ApplicationController(String myString, MyObject myObject) {
        ...
    }
    ...
    ..
    .
}

This is my Aspect class:

@Aspect
@Component
public class CommonLogAspect implements ILogAspect {
    Logger log = Logger.getLogger(CommonLogAspect.class);

    // @Before("execution(my.package.Class.new(..)))
    @Before("execution(* *.new(..))")
    public void constructorAnnotatedWithInject() {
        log.info("CONSTRUCTOR");
    }
}

How can I create a pointcut for my constructor object?


Thanks


Answer:

Sotirios Delimanolis is right insofar as Spring AOP does not support constructor interception, you do need full AspectJ for it. The Spring manual, chapter 9.8 Using AspectJ with Spring applications, describes how to use it with LTW (load-time weaving).

Furthermore, there is a problem with your pointcut

@Before("execution(* *.new(..))")

Constructors do not have return types like methods in AspectJ syntax, so you need to remove the leading *:

@Before("execution(*.new(..))")

Question:

I'm having a bit of trouble working out how to create a pointcut that will operate on beans that have a specific annotated parameter. My eventual aim is to validate the value of the parameter before it's processed, but for the moment I just need to create the pointcut.

Consider the following annotation

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER })
public @interface MyAnnotation {}

I'd then like to apply this to a number of methods like:

public void method1(@MyAnnotation long i) {}
public void method2(String someThing, @MyAnnotation long i) {}
public void method3(String someThing, @MyAnnotation long i, byte value) {}

So

  • I don't care which class (or package) the methods are in
  • The position of the annotated argument will vary.
  • I do know that annotated value will only apply to a specific type

My pointcut implementation needs to be something along the lines of:

@Before(value = "* *(..) && args(verifyMe)")
public void verifyInvestigationId(long verifyMe) {}

I'm getting a bit confused about exactly what that @Before value needs to be and how to tie in the annotation and its type. At this point it's probably not worth listing the things I've tried!

Update: Based on the advice I've seen in http://stackoverflow.com/questions/3565718/pointcut-matching-methods-with-annotated-parameters/3567170#3567170 (and correcting a couple of misunderstandings and adding space I overlooked) I've got to the point where the following works:

@Before("execution(public * *(.., @full.path.to.MyAnnotation (*), ..))")
public void beforeMethod(JoinPoint joinPoint) {
    System.out.println("At least one of the parameters are annotated with @MyAnnotation");
}

This is almost what I need - all I need to do is pass the value of the annotated argument as an parameter to the method. I can't quite work out the syntax to get Spring to do this (the linked answer does not show this).


Answer:

Very similar to my answer here which sheltem already pointed to, the solution looks like this (in annotation-style syntax this time because in Spring AOP you cannot use native AspectJ syntax):

Original poster's annotation:

package annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.PARAMETER })
public @interface MyAnnotation {}

Driver Application:

I use the driver application in order to test my AspectJ solution. In Spring the class as well as the aspect need to be Spring beans/components in order for this to work.

package de.scrum_master.app;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import annotations.MyAnnotation;

public class Application {
    public void method1(@MyAnnotation int i) {}
    public void method2(String id, @MyAnnotation float f) {}
    public void method3(int i, @MyAnnotation List<String> strings, @MyAnnotation String s) {}
    public void method4(int i, @MyAnnotation Set<Integer> numbers, float f, boolean b) {}
    public void method5(boolean b, String s, @MyAnnotation String s2, float f, int i) {}
    public void notIntercepted(boolean b, String s, String s2, float f, int i) {}

    public static void main(String[] args) {
        List<String> strings = new ArrayList<String>();
        strings.add("foo");
        strings.add("bar");
        Set<Integer> numbers = new HashSet<Integer>();
        numbers.add(11);
        numbers.add(22);
        numbers.add(33);

        Application app = new Application();
        app.method1(1);
        app.method2("foo", 1f);
        app.method3(1, strings, "foo");
        app.method4(1, numbers, 1f, true);
        app.method5(false, "foo", "bar", 1f, 1);
        app.notIntercepted(false, "foo", "bar", 1f, 1);
    }
}

Aspect:

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.SoftException;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;

import annotations.MyAnnotation;

@Aspect
public class ArgCatcherAspect {
    @Before("execution(public * *(.., @MyAnnotation (*), ..))")
    public void interceptMethodsWithAnnotatedParameters(JoinPoint thisJoinPoint) {
        System.out.println(thisJoinPoint);
        MethodSignature signature = (MethodSignature) thisJoinPoint.getSignature();
        String methodName = signature.getMethod().getName();
        Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
        Annotation[][] annotations;
        try {
            annotations = thisJoinPoint.getTarget().getClass().
                getMethod(methodName, parameterTypes).getParameterAnnotations();
        } catch (Exception e) {
            throw new SoftException(e);
        }
        int i = 0;
        for (Object arg : thisJoinPoint.getArgs()) {
            for (Annotation annotation : annotations[i]) {
                if (annotation.annotationType() == MyAnnotation.class) {
                    System.out.println("  " + annotation + " -> " + arg);
                    // Verify 'arg' here or do whatever
                }
            }
            i++;
        }
    }
}

Console log:

execution(void de.scrum_master.app.Application.method1(int))
  @annotations.MyAnnotation() -> 1
execution(void de.scrum_master.app.Application.method2(String, float))
  @annotations.MyAnnotation() -> 1.0
execution(void de.scrum_master.app.Application.method3(int, List, String))
  @annotations.MyAnnotation() -> [foo, bar]
  @annotations.MyAnnotation() -> foo
execution(void de.scrum_master.app.Application.method4(int, Set, float, boolean))
  @annotations.MyAnnotation() -> [33, 22, 11]
execution(void de.scrum_master.app.Application.method5(boolean, String, String, float, int))
  @annotations.MyAnnotation() -> bar

Question:

I am studying Spring AOP and I have the following doubt.

From what I know there are 2 ways to implement AOP behavior into a Java application that are:

  1. AspectJ: that is the first original AOP technology that uses byte code modification for aspect weaving.

  2. Spring AOP: Java-based AOP framework with AspectJ integration that uses dynamic proxies for aspect weaving.

My doubts are: what exactly means that Spring AOP is a AOP framework with AspectJ integration? So it use in turn AspectJ? or what?

The second doubt is related to the Spring configuration of Spring AOP, I know that I can do it in these way:

1) Using Java configuration class:

@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages="com.example")
public class AspectConfig {
    ...
}

2) Using XML:

<beans>
    <aop:aspectj-autoproxy />
    <context:component-scan base-package="com.example" />
</beans>

So, in both configuration it seems that Spring AOP use AspectJ because in these configuration I have: @EnableAspectJAutoProxy and

What it exactly means?


Answer:

This might answer your question - it's an excerpt from mvn dependency:tree for a project that uses spring-aop:

[INFO] |  +- org.springframework:spring-aop:jar:3.2.3.RELEASE:compile
[INFO] |  |  \- aopalliance:aopalliance:jar:1.0:compile
[INFO] |  +- org.springframework:spring-aspects:jar:3.2.3.RELEASE:compile
[INFO] |  |  +- org.aspectj:aspectjweaver:jar:1.7.2:compile

As you can see, the Spring dependency transitively includes the AspectJ weaver.

That being said, the documentation states that

Spring 2.0 introduces a simpler and more powerful way of writing custom aspects using either a schema-based approach or the @AspectJ annotation style. Both of these styles offer fully typed advice and use of the AspectJ pointcut language, while still using Spring AOP for weaving.

Cheers,

Question:

I am trying to run aspectj-maven plugin with JDK8. But it is giving errors like "The type java.lang.CharSequence cannot be resolved. It is indirectly referenced from required .class files"

Any help on how to resolve, or if the aspectj-maven-plugin supports JDK8. I am using 1.6 version of aspectj--maven-plugin.


Answer:

I had to achieve the same and I drove crazy trying to figure out this, fortunately I could solve it and here I give you what I did:

To use aspectj-maven-plugin with Java 8 you need version aspectj-maven-plugin 1.7 (Note that aspectj-maven-plugin 1.6 works for Java 7).

So, the maven plugin configuration needs to be:

        <!-- AspectJ configuration -->
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.7-SNAPSHOT</version>
            <configuration>
                <complianceLevel>1.8</complianceLevel>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

By the way, the aspectJ jars needed are:

    <!-- Spring AOP + AspectJ -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>1.8.1</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.1</version>
    </dependency>

And the most important thing I've struggled was that you need to install the aspectj-maven-plugin 1.7 jar manually into your pom.xml since this jar aren't on maven repo yet.

You can get it from Haus Jira (look at the Attachment section):

https://jira.codehaus.org/browse/MASPECTJ-131

Btw, once you download it an copy it to your repo you need to create your own aspectj-maven-plugin-1.7-SNAPSHOT.pom file within the corresponding directory. You can copy it from version 1.6 BUT ensure you modify the following content:

 <version>1.7-SNAPSHOT</version>

 <properties>
    <aspectjVersion>1.8.1</aspectjVersion>
    <mavenVersion>2.2.1</mavenVersion>
    <changesPluginVersion>2.9</changesPluginVersion>
 </properties>

That's all here you go, hope to help.

Question:

I have several implementations of SomeInterface. The question is what is the pointcut for the method executeSomething in all implementation of SomeInterface.

public class SomeImplementation implements SomeInterface {

    public String executeSomething(String parameter) {
        // Do something
    }

}

public class AnotherImplementation implements SomeInterface {

    public String executeSomething(String parameter) {
        // Do something different way
    }

}

Answer:

Pointcuts for that method can be either method-execution or method-call pointcuts. The most specific pointcuts for your requirement would look like this:

execution(public String SomeInterface+.executeSomething(String))
call(public String SomeInterface+.executeSomething(String))

Some explanation on these pointcut types:

  • the type pattern used in both these pointcuts mean: all public methods that return String that are defined in SomeInterface or any subtype of it, being named executeSomething and accepting a single String argument. This is the most specific type pattern that can be defined for your case and it will match only implementations of the String SomeInterface.executeSomething(String) method.
  • execution type pointcuts match join points that correspond to when a particular method body is executed
  • call type pointcuts match join points that correspond to when a particular method is called (i.e. the join point is located at the caller side)

Execution type pointcuts are used more often, but call type pointcuts are very useful too in some cases.

See The AspectJ Language/Join Points and Pointcuts chapter in the AspectJ Programming Guide for further reference.

Question:

I have a collection of unmanaged classes that I are instantiated outside of Spring. I've been attempting to use Spring AOP with load time weaving to @Autowire a bean into these classes but have so far not had any luck.

I've been testing using Tomcat 8 and Spring Boot 1.2.0.

My @Configuration where I attempt to set up class looks like this:

@Configuration
@PropertySource("classpath:application.properties")
@EnableSpringConfigured
@EnableLoadTimeWeaving
public class Config

Inside Config I define the bean I want to @Auotwire into my unmanaged classes:

@Bean
public StateProvider stateProvider() {
    //setup bean
    return new DynamoStateProviderImpl( );
}

The unmanaged bean looks like this:

@Configurable(autowire = Autowire.BY_TYPE, dependencyCheck = true,   preConstruction = true)
public class StateOutput implements UnifiedOutput {

@Autowired
private StateProvider stateProvider;

And I have the following deps inside my pom

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-agent</artifactId>
        <version>2.5.6.SEC03</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
    </dependency>

    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>javax.el-api</artifactId>
        <version>3.0.0</version>
    </dependency>

So far, I have not been able to see anything injected into stateProvider or been able to pull any info from the logs. I've also attempted setter style injection using

@Autowired
public void setStateProvider(StateProvider stateProvider){
    this.stateProvider = stateProvider;
}

Thanks


Answer:

In order to instrument LTW you'll need to either use the javaagent or place spring-tomcat-weaver.jar in the \lib folder and set up TomcatInstrumentableClassLoader in context.xml.

javaagent example:

-javaagent:"${settings.localRepository}/org/springframework/spring-agent/2.5.6.SEC03/spring-agent-2.5.6.SEC03".jar

ClassLoader example:

<Context>
    <Loader loaderClass="org.springframework.instrument.classl oading.tomcat.TomcatInstrumentableClassLoader" />
</Context>

Question:

I am trying to understand how Aspect works. I come from a C/C++ background where magic never happens.

I understand that you can annotate some functions with @Aspect then write down the Aspect implementation and so on. But, how (and at what time) does the new code get generated?

Assuming I have no editor. I compile java classes using javacc command that will generate .class files. Now, assume that the java files are annotated using Aspect. Shouldn't I then compile the .class files again with Aspect somehow to generate another set of .class files?

If my understanding is correct, how is this dual compilation step done in maven? or spring? I found many tutorial that will tell you what to add here and there to get things working but no tutorial explains how these things are actually working.


Answer:

Yeah, it is easy to tell that you are a C++ guy. There is no such thing as javacc (if you are not talking about the Java Parser Generator of the same name) but the Java Compiler is called javac. ;-)

As Philipp Wendler already pointed out, Eclipse is not just an IDE, it is an organisation similar to Apache, and AspectJ has been adopted many years ago as one of its projects. This has also the advantage that AJDT (AspectJ Development Tools) for Eclipse IDE are sort of the best AspectJ support you can get for any IDE, sadly including my favourite IntelliJ IDEA which is superior to Eclipse IDE in almost all respects except its AspectJ support being rather mediocre.

So much for the minor topics. Now as for your main question, it is not really suited for StackOverflow because it is rather a forum question, not about a concrete programming problem requiring a solution. Anyway, I love AspectJ and will answer briefly:

AspectJ has its own compiler ajc which is basically an enhanced version of the Eclipse Java Compiler ejc, i.e. it can be used to compile normal Java files as well as aspects in native AspectJ syntax or in @AspectJ style annotation-based syntax. No matter which way you weave your aspects, e.g.

  1. build aspect + Java code with ajc from scratch (compile-time weaving),
  2. build only aspects with ajc and Java code with javac, ejc or any other Java compiler, then

    1. weave aspects into Java class files via ajc (post-compile or binary weaving) or
    2. weave aspects into Java class files at runtime during class-loading with a Java agent called the AspectJ Weaver (load-time weaving, LTW),

what AspectJ does is always pretty much the same: It modifies Java byte code by weaving aspect code into it. In case 1 you just get one set of class files directly from ajc. Case 2.1 creates additional, new class files. Case 2.2 just creates new byte code in memory directly in the JVM.

I hope this helps. Let us not make this a long discussion, okay? If you have follow-up questions, let us limit to a minimum, okay?

Question:

Often people ask AspectJ questions like this one, so I want to answer it in a place I can easily link to later.

I have this marker annotation:

package de.scrum_master.app;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Marker {}

Now I annotate an interface and/or methods like this:

package de.scrum_master.app;

@Marker
public interface MyInterface {
  void one();
  @Marker void two();
}

Here is a little driver application which also implements the interface:

package de.scrum_master.app;

public class Application implements MyInterface {
  @Override
  public void one() {}

  @Override
  public void two() {}

  public static void main(String[] args) {
    Application application = new Application();
    application.one();
    application.two();
  }
}

Now when I define this aspect, I expect that it gets triggered

  • for each constructor execution of an annotated class and
  • for each execution of an annotated method.
package de.scrum_master.aspect;

import de.scrum_master.app.Marker;

public aspect MarkerAnnotationInterceptor {
  after() : execution((@Marker *).new(..)) && !within(MarkerAnnotationInterceptor) {
    System.out.println(thisJoinPoint);
  }

  after() : execution(@Marker * *(..)) && !within(MarkerAnnotationInterceptor) {
    System.out.println(thisJoinPoint);
  }
}

Unfortunately the aspect prints nothing, just as if class Application and method two() did not have any @Marker annotation. Why does AspectJ not intercept them?


Answer:

The problem here is not AspectJ but the JVM. In Java, annotations on

  • interfaces,
  • methods or
  • other annotations

are never inherited by

  • implementing classes,
  • overriding methods or
  • classes using annotated annotations.

Annotation inheritance only works from classes to subclasses, but only if the annotation type used in the superclass bears the meta annotation @Inherited, see JDK JavaDoc.

AspectJ is a JVM language and thus works within the JVM's limitations. There is no general solution for this problem, but for specific interfaces or methods you wish to emulate annotation inheritance for, you can use a workaround like this:

package de.scrum_master.aspect;

import de.scrum_master.app.Marker;
import de.scrum_master.app.MyInterface;

/**
 * It is a known JVM limitation that annotations are never inherited from interface
 * to implementing class or from method to overriding method, see explanation in
 * <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Inherited.html">JDK API</a>.
 * <p>
 * Here is a little AspectJ trick which does it manually.
 *
 */
public aspect MarkerAnnotationInheritor {
  // Implementing classes should inherit marker annotation
  declare @type: MyInterface+ : @Marker;
  // Overriding methods 'two' should inherit marker annotation
  declare @method : void MyInterface+.two() : @Marker;
}

Please note: With this aspect in place, you can remove the (literal) annotations from the interface and from the annotated method because AspectJ's ITD (inter-type definition) mechanics adds them back to the interface plus to all implementing/overriding classes/methods.

Now the console log when running the Application says:

execution(de.scrum_master.app.Application())
execution(void de.scrum_master.app.Application.two())

By the way, you could also embed the aspect right into the interface so as to have everything in one place. Just be careful to rename MyInterface.java to MyInterface.aj in order to help the AspectJ compiler to recognise that it has to do some work here.

package de.scrum_master.app;

public interface MyInterface {
  void one();
  void two();

  public static aspect MarkerAnnotationInheritor {
    // Implementing classes should inherit marker annotation
    declare @type: MyInterface+ : @Marker;
    // Overriding methods 'two' should inherit marker annotation
    declare @method : void MyInterface+.two() : @Marker;
  }
}

Question:

I have an AspectJ trace routine set up to log method entry and exit conditions using the following pointcuts:

public aspect Trace {       
    pointcut anyMethodExecuted():       execution (* biz.ianw.lanchecker.*.*(..)) && !within(Trace) && !within( is(AnonymousType) );
    pointcut anyConstructorExecuted():  execution (biz.ianw.lanchecker.*.new(..)) && !within(Trace); 

In my sendEmail class I have a method which calls the setDebugOut method to redirect the debug output to a LogOutputStream:

final private static  Logger log = LoggerFactory.getLogger(MailMail.class);
...
LogOutputStream losStdOut = new LogOutputStream() {             
    @Override
    protected void processLine(String line, int level) {
        log.debug(line);
    }
};    

public void sendPlainHtmlMessage(...) {  
    Session session = javaMailSender.getSession();
    PrintStream printStreamLOS = new PrintStream(losStdOut);
    session.setDebugOut(printStreamLOS);
    ...

This works fine, except that the Trace class pointcut intercepts the call the the anonymous inner class, producing as output:

20:14:18.908 TRACE [biz.ianw.lanchecker.Trace] - Enters method: Logger biz.ianw.lanchecker.MailMail.access$0()
20:14:18.909 TRACE [biz.ianw.lanchecker.Trace] - Exits method: Logger biz.ianw.lanchecker.MailMail.access$0().
20:14:18.909 TRACE [biz.ianw.lanchecker.Trace] -   with return value: Logger[biz.ianw.lanchecker.MailMail]
20:14:18.909 DEBUG [biz.ianw.lanchecker.MailMail] - DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]

I added the rather overly broad

&& !within( is(AnonymousType) )

condition to the pointcut, as shown above, but it had no effect. In fact I'm having real difficulty finding is(AnonymousType) documented anywhere.

How can I write a pointcut that excludes this anonymous inner method, preferably without impacting any others?


Answer:

This answer is courtesy Andrew Clement (see http://dev.eclipse.org/mhonarc/lists/aspectj-users/msg14906.html, ff), reposted here with his permission:

The access$0 method has been added to MailMail because log is private in MailMail - it enables the log.debug(line) to access log from the anonymous class (presumably called MailMail$1).

Recognizing that, we can see that access$0 is not in the anonymous class, it is an accessor generated in the MailMail class, hence your additional pointcut fragment not working.

Couple of options:

Exclude it specifically:

pointcut anyMethodExecuted():       execution (* biz.ianw.lanchecker.*.*(..)) && !within(Trace) && !execution(* MailMail.access$0(..));

Exclude all synthetic accessors (it is considered synthetic because it is ‘generated’ by the compiler to support what you are doing):

pointcut anyMethodExecuted():       execution (* biz.ianw.lanchecker.*.*(..)) && !within(Trace) && !execution(synthetic * access$*(..));

Or you could exclude all synthetics perhaps:

pointcut anyMethodExecuted():       execution (!synthetic * biz.ianw.lanchecker.*.*(..)) && !within(Trace);

Question:

We're using AspectJ in our project and also Jacoco for test coverage report, currently we're facing an issue that due to AspectJ changed the byte code during compiling phase, which makes the code coverage report not correct. One example is due to AspectJ adds extra if-else statement, then the branch coverage shows something like 1/4 but actually there's no condition branch in the source code. Is there some good way to tell Jacoco to ignore all code generated by AspectJ?

Thanks a lot.


Answer:

I am copying here the answer I just wrote on the JaCoCo mailing list:

You have two options with AspectJ if you want to avoid it compiling from source:

  1. Use LTW with the weaving agent.
  2. Move your aspects into a separate Maven module. Compile your Java modules with the normal Maven Compiler Plugin and the aspect module with AspectJ Maven. Then create another module which just uses AspectJ Maven in order to do binary weaving on a Java module, using both previously created artifacts as dependencies. In this scenario you need to make sure that JaCoCo offline instrumentation is bound to a phase before binary weaving is done.

The easiest way out, though, would be to test your aspects in isolation and also the Java code without aspects and measure coverage there without any issues.

Question:

Spring manual says:

any join point (method execution only in Spring AOP) where the target object has an @Transactional annotation: @target(org.springframework.transaction.annotation .Transactional)

any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation: @within(org.springframework.transaction.annotation .Transactional)

But I not see any difference between them!

I tried to Google it:

One difference between the two is that @within() is matched statically, requiring the corresponding annotation type to have only the CLASS retention. Whereas, @target() is matched at runtime, requiring the same to have the RUNTIME retention. Other than that, within the context of Spring, here is no difference between the join points selected by two.

So I tried to add custom annotation with CLASS retention, but Spring throw an Exception (because annotation must have RUNTIME retention)


Answer:

You are noticing no difference because Spring AOP, while using AspectJ syntax, actually only emulates a limited subset of its functionality. Because Spring AOP is based on dynamic proxies, it only provides interception of public, non-static method execution. (When using CGLIB proxies, you can also intercept package-scoped and protected methods.) AspectJ however can also intercept method calls (not just executions), member field access (both static and non-static), constructor call/execution, static class initialisation and a few more.

So let us construct a very simple AspectJ sample:

Marker annotation:

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

Driver application:

package de.scrum_master.app;

@MyAnnotation
public class Application {
  private int nonStaticMember;
  private static int staticMember;

  public void doSomething() {
    System.out.println("Doing something");
    nonStaticMember = 11;
  }

  public void doSomethingElse() {
    System.out.println("Doing something else");
    staticMember = 22;
  }

  public static void main(String[] args) {
    Application application = new Application();
    application.doSomething();
    application.doSomethingElse();
  }
}

Aspect:

package de.scrum_master.aspect;

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

@Aspect
public class MyAspect {
  @Before("@within(de.scrum_master.app.MyAnnotation) && execution(public !static * *(..))")
  public void adviceAtWithin(JoinPoint thisJoinPoint) {
    System.out.println("[@within] " + thisJoinPoint);
  }

  @Before("@target(de.scrum_master.app.MyAnnotation) && execution(public !static * *(..))")
  public void adviceAtTarget(JoinPoint thisJoinPoint) {
    System.out.println("[@target] " + thisJoinPoint);
  }
}

Please note that I am emulating Spring AOP behaviour here by adding && execution(public !static * *(..)) to both pointcuts.

Console log:

[@within] execution(void de.scrum_master.app.Application.doSomething())
[@target] execution(void de.scrum_master.app.Application.doSomething())
Doing something
[@within] execution(void de.scrum_master.app.Application.doSomethingElse())
[@target] execution(void de.scrum_master.app.Application.doSomethingElse())
Doing something else

No surprise here. This is exactly what you would also see in Spring AOP. Now if you remove the && execution(public !static * *(..)) part from both pointcuts, in Spring AOP the output is still the same, but in AspectJ (e.g. also if you activate AspectJ LTW in Spring) it changes to:

[@within] staticinitialization(de.scrum_master.app.Application.<clinit>)
[@within] execution(void de.scrum_master.app.Application.main(String[]))
[@within] call(de.scrum_master.app.Application())
[@within] preinitialization(de.scrum_master.app.Application())
[@within] initialization(de.scrum_master.app.Application())
[@target] initialization(de.scrum_master.app.Application())
[@within] execution(de.scrum_master.app.Application())
[@target] execution(de.scrum_master.app.Application())
[@within] call(void de.scrum_master.app.Application.doSomething())
[@target] call(void de.scrum_master.app.Application.doSomething())
[@within] execution(void de.scrum_master.app.Application.doSomething())
[@target] execution(void de.scrum_master.app.Application.doSomething())
[@within] get(PrintStream java.lang.System.out)
[@within] call(void java.io.PrintStream.println(String))
Doing something
[@within] set(int de.scrum_master.app.Application.nonStaticMember)
[@target] set(int de.scrum_master.app.Application.nonStaticMember)
[@within] call(void de.scrum_master.app.Application.doSomethingElse())
[@target] call(void de.scrum_master.app.Application.doSomethingElse())
[@within] execution(void de.scrum_master.app.Application.doSomethingElse())
[@target] execution(void de.scrum_master.app.Application.doSomethingElse())
[@within] get(PrintStream java.lang.System.out)
[@within] call(void java.io.PrintStream.println(String))
Doing something else
[@within] set(int de.scrum_master.app.Application.staticMember)

When looking at this in detail you see that a lot more @within() joinpoints get intercepted, but also a few more @target() ones, e.g. the call() joinpoints mentioned before, but also set() for non-static fields and object initialization() happening before constructor execution.

When only looking at @target() we see this:

[@target] initialization(de.scrum_master.app.Application())
[@target] execution(de.scrum_master.app.Application())
[@target] call(void de.scrum_master.app.Application.doSomething())
[@target] execution(void de.scrum_master.app.Application.doSomething())
Doing something
[@target] set(int de.scrum_master.app.Application.nonStaticMember)
[@target] call(void de.scrum_master.app.Application.doSomethingElse())
[@target] execution(void de.scrum_master.app.Application.doSomethingElse())
Doing something else

For each of these aspect output lines we also see a corresponding @within() match. Now let's concentrate on what is not the same, filtering the output for differences:

[@within] staticinitialization(de.scrum_master.app.Application.<clinit>)
[@within] execution(void de.scrum_master.app.Application.main(String[]))
[@within] call(de.scrum_master.app.Application())
[@within] preinitialization(de.scrum_master.app.Application())
[@within] get(PrintStream java.lang.System.out)
[@within] call(void java.io.PrintStream.println(String))
Doing something
[@within] get(PrintStream java.lang.System.out)
[@within] call(void java.io.PrintStream.println(String))
Doing something else
[@within] set(int de.scrum_master.app.Application.staticMember)

Here you see, in oder of appearance

  • static class initialisation,
  • static method execution,
  • constructor call (not execution yet!),
  • constructed object pre-initialisation,
  • member variable access in another class (System.out),
  • calling a method from another class (PrintStream.println(String)),
  • setting a static class member.

What do all of those pointcuts have in common? There is no target object, because either we are talking about static methods or members, static class initialisation, object pre-initialisation (no this defined yet) or calling/accessing stuff from other classes not bearing the annotation we are targeting here.

So you see that in AspectJ there are significant differences between the two pointcuts, in Spring AOP they are just not noticeable because of its limitations.

My advice for you is to use @target() if your intention is to intercept non-static behaviour within a target object instance. It will make switching to AspectJ easier if you ever decide to activate the AspectJ mode in Spring or even port some code to a non-Spring, aspect-enabled application.

Question:

I would like to have something like this:

public void doSomething(@ReplaceFooBar String myString) {
    //...
}

ReplaceFooBar is my custom annotation which should take the value of myString and do a replaceAll of "foo" with "bar" on it before the method starts executing so that it executes with the new string value. So, if the method was invoked with the parameter "I'm at the foo." it should actually execute with "I'm at the bar."

I don't know how to make this work. I've been fiddling with this for some time now. Let's say I last ended up at this point:

@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReplaceFooBar {
}

And...

@Aspect
public aspect ReplaceFooBarAspect {
    @Before("@annotation(ReplaceFooBar)")
    public String replaceFooBar(String value) {
        if (value == null) {
            return null;
        }
        return value.replaceAll("foo", "bar");
    }
}

What am I doing wrong?

My code isn't compiling, I'm getting errors like these.

Error:(6, 0) ajc: Duplicate annotation @Aspect
Error:(7, 0) ajc: aspects cannot have @Aspect annotation
Error:(10, 0) ajc: This advice must return void
Error:(10, 0) ajc: formal unbound in pointcut

I don't know how these aspects work exactly, how to get this working the way I want it.


Answer:

To execute method with different argument you should use @Around advice and replace arguments manually in code.

For example:

@Around("execution(* *(.., @aspectjtest.ReplaceFooBar (*), ..))")
public Object replaceFooBar(ProceedingJoinPoint pjp) throws Throwable {
    //get original args
    Object[] args = pjp.getArgs();

    //get all annotations for arguments
    MethodSignature signature = (MethodSignature) pjp.getSignature();
    String methodName = signature.getMethod().getName();
    Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
    Annotation[][] annotations;
    try {
        annotations = pjp.getTarget().getClass().
                getMethod(methodName, parameterTypes).getParameterAnnotations();
    } catch (Exception e) {
        throw new SoftException(e);
    }

    //Find annotated argument
    for (int i = 0; i < args.length; i++) {
        for (Annotation annotation : annotations[i]) {
            if (annotation.annotationType() == ReplaceFooBar.class) {
                Object raw = args[i];
                if (raw instanceof String) {
                    // and replace it with a new value
                    args[i] = ((String) raw).replaceAll("foo", "bar");
                }
            }
        }
    }
    //execute original method with new args
    return pjp.proceed(args);
}

Question:

I'm using AspectJ to intercept java.net.Socket calls.

I've created very simple aspect

after(): call(* java.net.Socket.connect(..)) {
    System.out.println("Connect intercepted!");
}

and aop.xml

<aspectj>

    <aspects>
        <aspect name="com.iggroup.lightstreamer.nwtp.SocketExceptionLoggingAspect"/>
    </aspects>

    <weaver options="-Xlint:ignore -Xset:weaveJavaxPackages=true -Xset:weaveJavaPackages=true">
    </weaver>

</aspectj>

When the call stack is like this, then I can see the console output:

java.lang.Exception
    at com.iggroup.lightstreamer.nwtp.SocketExceptionLoggingAspect.ajc$after$com_iggroup_lightstreamer_nwtp_SocketExceptionLoggingAspect$2$6e16217c(SocketExceptionLoggingAspect.aj:39)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:337)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:55)
    at org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal(HttpComponentsClientHttpRequest.java:91)
    at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
    at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:596)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:475)
    at com.iggroup.lightstreamer.nwtp.users.SsoRestClientImpl.lambda$0(SsoRestClientImpl.java:68)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

But nothing is logged out when the call stack is like this:

Caused by: java.net.ConnectException: Connection refused: connect
                at java.net.DualStackPlainSocketImpl.connect0(Native Method) ~[na:1.8.0_65]
                at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79) ~[na:1.8.0_65]
                at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_65]
                at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_65]
                at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_65]
                at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) ~[na:1.8.0_65]
                at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_65]
                at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_65]
                at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:668) ~[na:1.8.0_65]
                at sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:173) ~[na:1.8.0_65]
                at sun.net.NetworkClient.doConnect(NetworkClient.java:180) ~[na:1.8.0_65]
                at sun.net.www.http.HttpClient.openServer(HttpClient.java:432) ~[na:1.8.0_65]
                at sun.net.www.http.HttpClient.openServer(HttpClient.java:527) ~[na:1.8.0_65]
                at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:781) ~[na:1.8.0_65]
                at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:647) ~[na:1.8.0_65]
                at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1536) ~[na:1.8.0_65]
                at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441) ~[na:1.8.0_65]
                at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254) ~[na:1.8.0_65]
                at com.lightstreamer.ls_client.HttpProvider.connectAndGetAnswer(HttpProvider.java:244) ~[lightstreamer-se-client-2.5.2-1110.jar:na]

I wonder if it is because the sun.net.* packages are not load-time-weaved due to some security manager restrictions.

Does anyone know how to get it work with sun.net.* packages?

Update 1

I confirm that I can intercept the ls_client.HttpProvider.connectAndGetAnswer call, but not the one above it (sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream).

Is sun.* possible to weave with AspectJ?


Answer:

I'm yet to see a successful setup for load-time weaving of JRE (bootstrap) classes. If you need this for debugging purposes I'd go with build time weaving of the JRE classes instead.

This short snippet will weave the JRE jars for you and put the weaved classes in a single output jar. It needs org.aspectj/aspectjtools as a dependency. It also skips the jars in ext subfolder of the JRE as those jars will contain some duplicate classes and creating a jar file containing duplicate files will lead to an error. I'm also skipping jfxswt.jar from newer JRE versions as it will fail because of missing classes.

String aspectFileName = "src/main/java/pckg/AspectName.aj";
String jreLibPath = "c:/Program Files/Java/jdk1.8.0_40/jre/lib";
String outputJar = "weavedjre.jar";

List<String> jars = new ArrayList<>();

File dir = new File(jreLibPath);
File[] files = dir.listFiles();
for (File file : files) {
    if (file.isFile() && file.getName().endsWith(".jar")
            && !file.getName().endsWith("jfxswt.jar")) {
        jars.add(file.getAbsolutePath());
    }
}

List<String> ajcArgs = new ArrayList<>(Arrays.asList("-showWeaveInfo"));
for (String jar : jars) {
    ajcArgs.add("-inpath");
    ajcArgs.add(jar);
}
ajcArgs.add(aspectFileName);
ajcArgs.add("-outjar");
ajcArgs.add(outputJar);

org.aspectj.tools.ajc.Main.main(ajcArgs.toArray(new String[] {}));

Then run your program with the following VM arguments to use the weaved JRE classes (prepended to your boot classpath):

-verbose:class -Xbootclasspath/p:path_to/weavedjre.jar

or in an Eclipse launch configuration:

-verbose:class -Xbootclasspath/p:${resource_loc:/project_name/weavedjre.jar}

I added the verbose logging of class loading VM argument too, so you can see which class is loaded from where.

Question:

What is the CodeSignature in aspectJ? I tried to find JavaDocs but didn't find anything useful. For Instance, thy is the following signature is a CodeSignature:

pointcut log() : execution(@Log * *(..));

before() : log() {
    String[] names = ((CodeSignature) thisJoinPoint.getSignature()).getParameterNames();
}

Is there a JoinPoint such that thisJoinPoint.getSignature() that is not a CodeSignature?


Answer:

CodeSignature represents a code block captured by a join point. It may be a method, constructor, initializer (static or non-static) or an advise. There are join points where the signature is not a CodeSignature. For example join points for field set and field get where the signature is a FieldSignature and join point for a catch clause has a CatchClauseSignature.

Signatures provide access to information on which join point is called upon.

Question:

I have two errors on an existing mvm project I am trying to build and not sure how to get these resolved.

First the main one:

[ERROR] Failed to execute goal org.codehaus.mojo:aspectj-maven-plugin:1.5:compile (default) on project ws: Compiler errors:
The type java.util.Comparator cannot be resolved. It is indirectly referenced from required .class files

This one is bugging me a bit, I mean this is from the main JRE so I am not sure what this error means. I am building this from the command line and not through Eclipse or other IDEs at this stage. Most answers on the web seem to be based on putting the JRE on the project build path within eclipse.

I have Java 1.8 installed, running on OSX. My Java Source+Target version is 1.7.

The second is a warning, which I am not too fussed but I would like to remove it if I can:

[WARNING] The POM for org.aspectj:aspectjweaver:jar:1.8.0.M1 is missing, no dependency information available

Now I believe this is coming from Spring-Aspects-4.0 which I have dependency on, I have set an explicit decency on the POM to 1.7.4 (stable).

Anyway I can remove this warning, or do I need to put a dependency on the 1.8.0.M1 on my POM which I do not want to do.


Answer:

Right so after much tinkering, it seems the issue was that the environment it was being built on, had a JDK 8 installed and the aspectjweaver version was not compatible with it.

Therefore two solutions:

  1. Install JDK7 and set that as the JAVA_HOME before building.

or

  1. Set source/target to 1.8, set aspectjweaver to 1.8.1 version and that works.

The error message wasn't clear but it's sorted now.

Question:

Note: this is a proof of concept implementation and not the final thing.

i have 3rd. party add ons and i want to limit their usage of sound, e.g. limit the duration etc. (not possible with security manager). To achieve this i thought about replacing the return of AudioSystem.getLine() with a wrapper. this is the test-aspect:

@Aspect
public class MixerAspect {
    @Around("execution(* javax.sound.sampled.AudioSystem.getLine(javax.sound.sampled.Line.Info))")
    public Object getLineAdvice(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("AspectJ");
        pjp.getArgs();
        Line ret = (Line) pjp.proceed();
        return ret;
    }
}

every add-on has its own class loader and they usually don't share objects, so this is what i have come up with:

@Override
public Class<?> loadClass(String className) throws ClassNotFoundException {
....
if (className.equals(AudioSystem.class.getName())) {
    .....
    byte[] array = buffer.toByteArray();
        try {
            if (mixed == null)
                mixed = weaver.defineClass(className, array, new CodeSource(mixerAspect, (CodeSigner[]) null));
            return mixed;
        } catch (IOException e) {
            throw new ClassNotFoundException("unable to define class", e);
        }

this is the initlialization-code of the WeavingURLClassloader:

weaver = new WeavingURLClassLoaderHelper(new URL[0], parent);
weaver.addURL(aspects[0]);

parent is the class loader with access to the Mixer aspect and aspects is an url-array which only element is one pointed to the directory where the MixerAspect is located in. my aop.xml:

<aspectj>
    <aspects>
        <aspect name="org.intellimate.izou.security.replaced.MixerAspect"/>
    </aspects>

    <weaver options="-Xset:weaveJavaxPackages=true -verbose -showWeaveInfo -debug">
        <!-- Weave types that are within the javax.* or org.aspectj.*
             packages. Also weave all types in the foo package that do
             not have the @NoWeave annotation. -->
        <include within="javax.*"/>
        <include within="org.intellimate.izou.security.replaced.*"/>
        <include within="javax.sound.sampled.AudioSystem"/>
    </weaver>
</aspectj>

this is the (relevant) log:

....(no relevant log)
TraceFactory.instance=org.aspectj.weaver.tools.Jdk14TraceFactory@53aad5d5
[WeavingURLClassLoaderHelper] info AspectJ Weaver Version 1.8.5 built on Thursday Jan 29, 2015 at 01:03:58 GMT
[WeavingURLClassLoaderHelper] info register classloader ro.fortsoft.pf4j.IzouPluginClassLoader$WeavingURLClassLoaderHelper
[WeavingURLClassLoaderHelper] info using configuration /Users/LeanderK/IdeaProjects/Izou/target/classes/META-INF/aop.xml
[WeavingURLClassLoaderHelper] info register aspect org.intellimate.izou.security.replaced.MixerAspect
[WeavingURLClassLoaderHelper] info AspectJ Weaver Version 1.8.5 built on Thursday Jan 29, 2015 at 01:03:58 GMT
[WeavingURLClassLoaderHelper] info register classloader ro.fortsoft.pf4j.IzouPluginClassLoader$WeavingURLClassLoaderHelper
[WeavingURLClassLoaderHelper] info using configuration /Users/LeanderK/IdeaProjects/Izou/target/classes/META-INF/aop.xml
[WeavingURLClassLoaderHelper] info register aspect org.intellimate.izou.security.replaced.MixerAspect
...(no relevant log)
[WeavingURLClassLoaderHelper] debug weaving 'javax.sound.sampled.AudioSystem'
[WeavingURLClassLoaderHelper] weaveinfo Join point 'method-execution(javax.sound.sampled.Line javax.sound.sampled.AudioSystem.getLine(javax.sound.sampled.Line$Info))' in Type 'javax.sound.sampled.AudioSystem' (AudioSystem.java:410) advised by around advice from 'org.intellimate.izou.security.replaced.MixerAspect' (MixerAspect.class(from MixerAspect.java))
[WeavingURLClassLoaderHelper] debug generating class 'javax.sound.sampled.AudioSystem$AjcClosure1'
2015-05-24 20:12:13,945 FATAL [Thread-5] org.intellimate.izou.threadpool.ThreadPoolManager (ThreadPoolManager.java:59) - unable to provide callback for: org.intellimate.izou.addon.AddOnManager$$Lambda$19/970865974@1f4f3b69
java.util.concurrent.CompletionException: java.lang.NoSuchMethodError: org.intellimate.izou.security.replaced.MixerAspect.aspectOf()Lorg/intellimate/izou/security/replaced/MixerAspect;
    at java.util.concurrent.CompletableFuture.internalComplete(CompletableFuture.java:205) [?:1.8.0_25]
    at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:459) [?:1.8.0_25]
    at java.util.concurrent.CompletableFuture$Async.run(CompletableFuture.java:428) [?:1.8.0_25]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_25]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_25]
    at org.intellimate.izou.threadpool.ThreadPoolManager$LoggingThreadFactory$1.run(ThreadPoolManager.java:73) [classes/:?]
Caused by: java.lang.NoSuchMethodError: org.intellimate.izou.security.replaced.MixerAspect.aspectOf()Lorg/intellimate/izou/security/replaced/MixerAspect;
    at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:410) ~[?:1.8.0_25]
    at leanderk.izou.playground.ExampleAddOn.prepare(ExampleAddOn.java:41) ~[?:?]
    at org.intellimate.izou.sdk.addon.AddOn.register(AddOn.java:41) ~[?:?]
    at org.intellimate.izou.addon.AddOnManager$$Lambda$19/970865974.run(Unknown Source) ~[?:?]
    at java.util.concurrent.CompletableFuture$AsyncRun.exec(CompletableFuture.java:454) ~[?:1.8.0_25]
    ... 4 more

it looks like it doesn't weave, but why? I don't know what else to try. I have the following dependencies:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.5</version>
 </dependency>
 <dependency>
    <groupId>aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.5.4</version>
 </dependency>

to further complicate things, the class loader is in another project with is a simple maven dependency to this project. Is there some aspectj-intitialization i am missing?


edit to clarify the answer: you also have to define the aspect through WeavingURLClassloader, this is my (example - its simplified) code, the same can be applied for every class you want to mix-in. In my case the class was already loaded through the system-classloader, so i had to excplicitly call define (be careful, the same classes loaded from different class loaders are not the same!)

private Class mixer = null;
......
@Override
public Class<?> loadClass(String className) throws ClassNotFoundException {
   .....
   else if (className.contains("MixerAspect")) {
        InputStream is = this.getResourceAsStream(className.replace('.', '/') + ".class");
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();

        int nRead;
        byte[] data = new byte[16384];

        try {
            while ((nRead = is.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }
        } catch (IOException e) {
            throw new ClassNotFoundException("unable to load class", e);
        }

        try {
            buffer.flush();
        } catch (IOException e) {
            throw new ClassNotFoundException("unable to load class", e);
        }
        byte[] array = buffer.toByteArray();
        URL mixerAspect = getResource("org/intellimate/izou/security/replaced/MixerAspect.class");
        try {
            if (mixer == null) {
                mixer = weaver.defineClass(className, array, new CodeSource(mixerAspect, (Certificate[]) null));
            }
            return mixer;
        } catch (IOException e) {
            throw new ClassNotFoundException("unable to define class", e);
        }
    }

Answer:

If using annotation style aspects and compiling with javac you need the aspect to be 'finished off' at loadtime with a pass through the weaver itself. If you don't then it can't generate the helper methods like aspectOf() that will be called from other woven types attempting to use the aspect. The NoSuchMethodError for aspectOf() tells me the aspect is not getting woven. The fact that aspectOf() is being called at all is telling me that the other types are being woven successfully. Couple of choices:

  • use ajc to compile your MixerAspect, this will add the extra methods at compile time

  • ensure your weaving process lets MixerAspect be woven. Ensure it is loaded with the other classes being woven rather than a parent loader? Or let the parent loader do weaving too?

Question:

I have the aspect:

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

    int around() : publicMethodExecuted() {
        //I need parameters values here
        //to write their to log

        int original_return_value = proceed();
        return original_return_value * 100;
    }
}

How to get parameters the method was called with? I need to write their to log file.

I'm most interested in a native AspectJ-way, not using reflection.


Answer:

Sorry If I misunderstood but this should bring the parameters

Object[] args = thisJoinPoint.getArgs();

Question:

I'm using AspectJ 1.8.8 compile-time weaving and I have a block like this

@SomeAnnotation(value="someValue")
public List doSomething(String someArg) {
    ...
}

where @SomeAnnotation is implemented with an "Around" advice.

Looking at the bytecode with JD-GUI, I see the following generated code (slightly formatted):

public class SomeClass {
  private static Annotation ajc$anno$5;

  ...

  @SomeAnnotation(value="someValue")
  public List doSomething(String someArg)
  {
    String str = someArg;
    JoinPoint localJoinPoint = Factory.makeJP(ajc$tjp_5, this, this, str);
    Object[] arrayOfObject = new Object[3];
    arrayOfObject[0] = this;
    arrayOfObject[1] = str;
    arrayOfObject[2] = localJoinPoint;
    Annotation tmp56_53 = ajc$anno$5;
    if (tmp56_53 == null) {
      tmp56_53;
    }
    return (List)new SomeClass.AjcClosure11(arrayOfObject).linkClosureAndJoinPoint(69648).around(tmp56_53, (SomeAnnotation)(ajc$anno$5 = SomeClass.class.getDeclaredMethod("doSomething", new Class[] { String.class }).getAnnotation(SomeAnnotation.class)));
  }
}

I was wondering why that condition (if (tmp56_53...)) even exists as it appears to be doing nothing (And is also syntactically incorrect Java? Maybe because this was generated by ajc?). I'm curious about this because it's causing "branch misses" in a coverage tool (JaCoCo).


Edit 1

Here is the raw Java machine code from javap:

       0: aload_1
       1: astore_2
       2: getstatic     #480                // Field ajc$tjp_10:Lorg/aspectj/lang/JoinPoint$StaticPart;
       5: aload_0
       6: aload_0
       7: aload_2
       8: invokestatic  #312                // Method org/aspectj/runtime/reflect/Factory.makeJP:(Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint;
      11: astore_3
      12: invokestatic  #339                // Method com/foo/SomeAspect.aspectOf:()Lcom/foo/SomeAspect;
      15: iconst_3
      16: anewarray     #2                  // class java/lang/Object
      19: astore        4
      21: aload         4
      23: iconst_0
      24: aload_0
      25: aastore
      26: aload         4
      28: iconst_1
      29: aload_2
      30: aastore
      31: aload         4
      33: iconst_2
      34: aload_3
      35: aastore
      36: new           #484                // class com/foo/SomeClass$AjcClosure21
      39: dup
      40: aload         4
      42: invokespecial #485                // Method com/foo/SomeClass$AjcClosure21."<init>":([Ljava/lang/Object;)V
      45: ldc_w         #327                // int 69648
      48: invokevirtual #333                // Method org/aspectj/runtime/internal/AroundClosure.linkClosureAndJoinPoint:(I)Lorg/aspectj/lang/ProceedingJoinPoint;
      51: getstatic     #488                // Field ajc$anno$10:Ljava/lang/annotation/Annotation;
      54: dup
      55: ifnonnull     86
      58: pop
      59: ldc           #75                 // class com/foo/SomeClass
      61: ldc_w         #489                // String someArg
      64: iconst_1
      65: anewarray     #348                // class java/lang/Class
      68: dup
      69: iconst_0
      70: ldc           #171                // class java/lang/String
      72: aastore
      73: invokevirtual #352                // Method java/lang/Class.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
      76: ldc_w         #341                // class com/foo/SomeAnnotation
      79: invokevirtual #358                // Method java/lang/reflect/Method.getAnnotation:(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;
      82: dup
      83: putstatic     #488                // Field ajc$anno$10:Ljava/lang/annotation/Annotation;
      86: nop
      87: checkcast     #341                // class com/foo/SomeAnnotation
      90: invokevirtual #362                // Method com/foo/SomeAspect.around:(Lorg/aspectj/lang/ProceedingJoinPoint;Lcom/foo/SomeAnnotation;)Ljava/lang/Object;
      93: pop
      94: return

Looks like ifnonnull could be conditional in question, but I am not familiar at all with JVM instructions, and I still don't know why AspectJ would generate logic like this.


Answer:

tl;dr: It's a normal lazy initialization, and jd is just confused.

Byte 16 is where it creates that new Object[3]:

16: anewarray     #2                  // class java/lang/Object

You can see after that in 19-35 that it's just immediately copying the local variables onto the stack (iconst for the index, aload for the reference) and then writing them to the array (aastore). The immediate next byte is 36, which is the new operator (just the allocation, then immediately followed by the invokespecial to run the constructor).

That brings us to byte 48, which calls linkClosureAndJoinPoint. You didn't include your constants table, but at 45 ldc_w #327 loads the constant value 69648, so that brings us up to the point of .around.

Now something interesting happens at byte 51. The single chained call that jd reconstructed is now interrupted. The bytecode loads the static annotation field ajc$anno$10 (not 5, as jd says) onto the stack. If that annotation field is not null (55), then execution jumps to 86 (a no-op, used as a "landing point" for the jump), which performs that cast check ((SomeAnnotation)) , then finally actually invokes the advice.

The code that's skipped over (58-82) says this, which you'll recognize from the decompilation:

SomeClass.class
    .getDeclaredMethod("doSomething", new Class[] { String.class })
    .getAnnotation(SomeAnnotation.class)

Byte 83 then stores the result into the static field, and execution proceeds from there.

In Java terms, this is exactly what's happening:

if (cachedAnnotation == null) {
    cachedAnnotation = getAnnotationOnMethodUsingReflection();
}

AspectJ's bytecode is very tight and clean here (likely hand-optimized because this is likely to be very hot code). Either because of that or because that logic interrupts the chained method call, jd is getting confused and splitting the null check and the assignment.

Question:

In the following code snippet I need to execute some logic whenever the property myList is accessed. Is it possible?

public class Test {
    public static List<String> myList = new ArrayList();

    public static void addData(){
        myList.add("foo");
        myList.add("bar");
    }
    public static void removeData(){
        if(myList.size() > 0){
            myList.remove(0);
        }
    }
    public static void displayData(){
        for (String data : myList) {
            System.out.println("data : "+data);
        }
    }

    public static void main(String[] args) {
        addData();
        displayData();
        removeData();
        displayData();
    }
}

Answer:

You can weave code Before/After/Around any access to your field using the following pointcuts :

@Aspect
public class TestAccessorsAspect {
    @Pointcut("get(java.util.List com.sample.Test.myList)")
    public void readMyList(){}

    @Pointcut("set(java.util.List com.sample.Test.myList)")
    public void writeMyList(){}
}

in .aj syntax, this might look like this :

public aspect TestAccessorsAspect {

    pointcut readMyList() : get(java.util.List com.sample.Test.myList);   

    pointcut writeMyList() : set(java.util.List com.sample.Test.myList);   
}

Whenever those field are accessed for reading (resp. writing), those pointcuts are going to be triggered.

Question:

I'm currently going through AspectJ's documentation, and I don't quite get their point on Pointcut composition. In particular, I don't understand what cFlow(P && Q) does, when advice with that pointcut would get executed.

A PowerPoint presentation (for a course at the university of Utrecht) I found explains

cflow is the collection of join points flowing from the argument pointcut. This means that cflow(P) && cflow(Q) is the intersection of the two collections, while cflow(P && Q) means that you first combine the pointcuts P and Q, and all the join points flowing from that are in this collection.

They go on to list all join points for cFlow(P) && cFlow(Q) (pointcut flowPAndflowQ() : cflow(execution(* Example.P(..))) && cflow(execution(* Example.Q(..))) && within(Example);), and to me it looks like an intersection of all the control flow points of the individual statements - P ∩ Q, if you will (just like they said):

Flow from P - execution(void Example.P()) Flow from P - call(void Example.Q()) Flow from P - execution(void Example.Q()) Flow from Q - execution(void Example.Q()) Flow from P && flow from Q - execution(void Example.Q())

(Their example is like the one in the AspectJ docs, except for the lacking println() statement.)

What I (still) don't understand, is what cFlow(P && Q) would do.

Does it mean "get all join points that are in P, then add all join points that are in Q, then match on anything that flows from any of them"? If so, I don't get the println() statement for the AspectJ example: System.out.println("should not occur"); Surely, if I add all flow points in P and Q (i.e. P + Q), that should be the superset (union) to P ∩ Q, P ∪ Q?

Or does it mean "get all join points in P that are also in Q", i.e. all flow points within X() below?

public void P() { X(); }
public void Q() { X(); }
public void X() { /* all that is in the body of X() */ }

Or can it just never occour, as AspectJ's example states? (Why?)

I'd really appreciate if someone could shed some light. :)


Answer:

Does it mean "get all join points that are in P, then add all join points that are in Q, then match on anything that flows from any of them"?

No, it means get all join points that are in P and in Q so it's intersection.

Or does it mean "get all join points in P that are also in Q", i.e. all flow points within X() below?

Yes for "get all join points in P that are also in Q" and no for the remaining part. The reason is pointcut P defines a single join point: execution(void Example.P()), and pointcut Q defines a single join point: execution(void Example.Q()). Because these join points are different the intersection for them is an empty set. cflow taken from an empty set is an empty set too. That's why in AspectJ documentation this pointcut is marked with "should not occur".

Hope this helps!

This is a misleading quote from the Power Point presentation:

cflow(P && Q) means that you first combine the pointcuts P and Q, and all the join points flowing from that are in this collection

The word "combine" should be replaced with "intersect".

I created a simple example on Github that replicates the example from the PowerPoint presentation: https://github.com/medvedev1088/aspectj-cflow-composition-example

public class Example {
    public void P() {
        Q();
    }

    public void Q() {
    }

    public static void main(String[] args) {
        new Example().P();
    }
}

If you run it the output should be like this:

pointcut: P                    join point: execution(Example.P())
pointcut: flowP                join point: execution(Example.P())
pointcut: flowP                join point: call(Example.Q())
pointcut: Q                    join point: execution(Example.Q())
pointcut: flowP                join point: execution(Example.Q())
pointcut: flowQ                join point: execution(Example.Q())
pointcut: flowPAndflowQ        join point: execution(Example.Q())

What this shows is that there are only 3 join points:

A: execution(Example.P())
B: call(Example.Q())
C: execution(Example.Q())

Pointcuts:

pointcut P includes only A
pointcut Q includes only C
pointcut flowP includes A, B and C
pointcut flowQ includes only C
pointcut flowPAndflowQ includes only C

We can see now that P && Q is an empty set while flowP && flowQ includes C.

I also included additional pointcut: cflow(P() && publicMethods()) (the advice for this pointcut is commented out in the code). publicMethods() is execution(public * *(..)). Unlike cflow(P() && Q()) it doesn't result in empty set.

Question:

I am using Spring Boot to develop a REST API and I would like to log the URL of the resources being retrieved by the clients using Spring Aspect. My class for the Aspect have this code:

@Component
@Aspect
public class Logs {

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void allResources() {}

    @Before("allResources()")
    public void apiRequestLog(JoinPoint jp) {    
        LogManager.getLogger(jp.getSignature().getDeclaringTypeName()).info("------------------------- o -------------------------");
        String log = jp.getSignature().getName() + " >>>";
        for (Object arg : jp.getArgs()) {
            log += "\n   ARG: " + arg;
        }
        LogManager.getLogger(jp.getSignature().getDeclaringTypeName()).info(log);

    }
}

I dont know how to pass the RequestMapping object as parameter for the advice, and get the path of the URL.


Answer:

You can let Spring inject the client's request into your aspect:

@Component
@Aspect
public class Logs {
   @Autowired(required = false)
   private HttpServletRequest request;
...

The original URL called by the client can then be retrieved from that in the before-method via:

request.getRequestURL();

Question:

I am writing an aspect logger to write a log whenever any member variable in a given class is accessed.

If I write a specific pointcut for a single variable like below, I am able to get the value of the field.

@Pointcut("get(* abc.ThreadPoolService.drMaxTh)")
public void drFields() {}

@AfterReturning(pointcut="drFields()", returning="drMaxTh")  
public void afterAccessingdrFields(int drMaxTh) {
    LOGGER.info("Accessed the field drMaxTh " + drMaxTh);
}

But my class has a dozen+ variables, and I don't intend on writing specific pointcuts for each of them. So, I want to write something like..

@Pointcut("get(* abc.ThreadPoolService.*)")
public void drFields() {}

@AfterReturning(pointcut="drFields()", returning= **????** )  
public void afterAccessingdrFields(what should come here???) {
    LOGGER.info("Accessed the field drMaxTh " + <and here???>);
}

But unable to understand how to capture the name and value of the field that is being accessed, in case of a wildcard field access specifier.

Thanx to anyone helping me out on this.


Answer:

It is actually very simple, and sheltem was right, you can just use Object in the returning type declaration. Here is a little demo showing that it even works for both static and non-static members, as long as they are not declared final:

Driver application:

package de.scrum_master.app;

public class Application {
    public static final double PI = Math.PI;
    static String producer = "Scrum-Master.de";

    private int id = 11;
    private String author = "Alexander Kriegisch";
    private final String COUNTRY = "Germany";

    public static void main(String[] args) {
        Object dummy;
        Application application = new Application();

        // Access static fields
        dummy = PI;
        dummy = producer;
        // Access non-static fields
        dummy = application.author;
        dummy = application.id;
        dummy = application.COUNTRY;
    }
}

Aspect:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class FieldAccessLogger {
    @Pointcut("get(* de.scrum_master.app.Application.*)")
    public void fieldAccess() {}

    @AfterReturning(pointcut = "fieldAccess()", returning = "field")
    public void afterFieldAccess(Object field, JoinPoint thisJoinPoint) {
        System.out.println(thisJoinPoint.toLongString());
        System.out.println("  " + thisJoinPoint.getSignature().getName());
        System.out.println("  " + field);
    }
}

Console output:

get(static java.lang.String de.scrum_master.app.Application.producer)
  producer
  Scrum-Master.de
get(private java.lang.String de.scrum_master.app.Application.author)
  author
  Alexander Kriegisch
get(private int de.scrum_master.app.Application.id)
  id
  11

As you can see, PI and COUNTRY are not intercepted because they are (final) constants.

Question:

I have an aspect that handles all methods that have a custom annotation.

The annotation has an enum parameter and I have to get the value in the aspect:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Monitored {
    MonitorSystem monitorSystem();
}

My case is very similar to that question and the accepted answer works for Spring beans that do not implement an interface.

The aspect:

@Aspect
@Component
public class MonitorAspect {

    @Around("@annotation(com.company.project.monitor.aspect.Monitored)")
    public Object monitor(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        MonitorSystem monitorSystem = signature.getMethod().getAnnotation(Monitored.class).monitorSystem();
        ...
    }
}

But if the Spring bean that is annotated with @Monitored (only the implementation class is annotated) implements an interface - pjp.getSignature() returns the signature of the interface and it does not have an annotation.

This is OK:

@Component
public class SomeBean {
   @Monitored(monitorSystem=MonitorSystem.ABC) 
   public String someMethod(String name){}
}

This does not work - pjp.getSignature() gets the signature of the interface.

@Component
public class SomeBeanImpl implements SomeBeanInterface {
   @Monitored(monitorSystem=MonitorSystem.ABC) 
   public String someMethod(String name){}
}

Is there a way to get the signature of the implementation method from ProceedingJoinPoint?


Answer:

Managed to do it with:

@Aspect
@Component
public class MonitorAspect {

    @Around("@annotation(com.company.project.monitor.aspect.Monitored)")
    public Object monitor(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = pjp.getTarget()
           .getClass()
           .getMethod(signature.getMethod().getName(),     
                      signature.getMethod().getParameterTypes());
        Monitored monitored = method.getAnnotation(Monitored.class);
        ...
    }
}

Question:

I have a Java 8 Maven project that defines a custom annotation and an aspect. When running test code in that project itself, it is applying the aspect to the annotated classes. I am then packaging and installing project.

I then bring in that dependency into a new project (non-Spring). The new project is then not having the aspect applied to it's classes, though it does bring in the new annotation.

How do I have a single JAR to define an annotation and aspect and have it applied to all of my projects with Maven?


Answer:

You need to specify your aspect project dependency as an aspect library in your aspectj-maven-plugin configuration in your pom.xml. Let's suppose your aspect module has the groupid:artifactid groupid:aspect-module. Your pom.xml should look similar to this:

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
    </dependency>
    <dependency>
        <groupId>groupid</groupId>
        <artifactId>aspect-module</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <executions>
                <execution>
                    <id>default-compile</id>
                    <phase>none</phase>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.9</version>
            <configuration>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>groupid</groupId>
                        <artifactId>aspect-module</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Note that I'm switching off the maven-compiler-plugin because they tend do overwrite each other's output with the aspectj-maven-plugin, and the AspectJ compiler should be able to compile normal java files and weave them in the same step anyway, so using the maven-compiler-plugin is redundant. If you are using Eclipse + AJDT, this maven configuration will much better reflect what happens in your IDE while you're developing.

Question:

In my case, I am using the following advice:

  @Around(value = "@annotation(MyAnnotation)  && args(MyArgs)")

and it works fine once the MyAnnotation is added to the method and MyArgs will also retrieved.

  @MyAnnotation(type = MyType.CREATE)
  public void add(MyArgs) { 
  ...
  }

But in this post, it says:

The errors that can and will occur

Using only annotations creates another problem that we don’t need to think about while using patterns; It will make our advice run twice(or more), because the annotation pointcut don’t specify if it should be run during execution or initialization.

To my understanding, it seems right once the join point reached and the condition is met, the advice should run (then my advice above will run twice - the call and the exeuction). And I should use the following advice to avoid it.

  @Around(value = "@annotation(MyAnnotation)  && execution(* *(..)) && args(MyArgs)")

But I debugged my code, it only runs once without adding execution(* *(..)).

Is this right? Or it's not the way in which advice runs?

Updated 2018-04-16

@Nandor is right, I was using Spring AOP instead of AspectJ. I started a maven demo clearly demonstating his point. Thank you, Nandor.


Answer:

If you were using AspectJ, your advice would be triggered twice, because the pointcut expression

@annotation(MyAnnotation)

matches both method execution and method call join points. See call vs execution in the AspectJ programming guide. Since your pointcut expression is not restricted to either call or execution join points, it will match both. If you were actually using AspectJ in your project, your around advice would be triggered for both and you would face the issue you were warned about in the post you are referring to.

The fact that using this pointcut expression doesn't result in the around advice executing twice means that you are in fact not using AspectJ and you're using Spring AOP instead, which only supports method execution pointcuts (see Spring AOP capabilities and goals)

Spring AOP currently supports only method execution join points (advising the execution of methods on Spring beans).

and only for public methods, because of the proxy based nature of Spring AOP (besided many other limitations).

If you want to create pointcut expressions that are compatible with both Spring AOP and AspectJ, always constrain the pointcut to method execution by adding the corresponding pointcut expression, for example:

@annotation(MyAnnotation) && execution(public * *(..))

Question:

I'm trying to figure out a way to inject a bean into an aspect.

I mean

public class Greeter {
    public String greet(String name) {....}
}

...

public aspect GreeterAspect {
    @Inject
    private Greeter greeter

    ...
}

Executing that as a JUnit test with Arquillian + Wildfly 8.2.1 (managed and remote) I get these lines of log:

WELD-000119: Not generating any bean definitions from x.y.z.Greeter because of underlying class loading error: Type org.aspectj.runtime.internal.AroundClosure from [Module "deployment.test.war:main" from Service Module Loader] not found.
WELD-000119: Not generating any bean definitions from x.y.z.GreeterAspect because of underlying class loading error: Type org.aspectj.lang.NoAspectBoundException from [Module "deployment.test.war:main" from Service Module Loader] not found.

and soon after I get the error

WELD-001474: Class x.y.z.Greeter is on the classpath, but was ignored because a class it references was not found: org.aspectj.runtime.internal.AroundClosure from [Module "deployment.test.war:main" from Service Module Loader].

If I get it right, it complains that aspectjrt.jar is not in the classpath, though I've checked and I got it in the dependencies (using Maven to build). Was in provided scope, tried to switch to compile but nothing changed.

Can anyone help me solve the issue?

EDIT: Solved the initial problm, now NullPointerException

Solved the initial issue by adding the aspectjrt.jar to Arquillian deployment as suggested by simas_ch.

Though, when executing, I receive a NullPointerException

public class Greeter {
    public String greet(String name) {....}
}

...

public aspect GreeterAspect {
    @Inject
    private Greeter greeter;

    private pointcut pc() : execution(* x.y.z.SomeClass.someMethod(..));

    String around() : pc() {
        log.debug("Aspect is about to say something...");
        String result = greeter.greet("Stefano");
        log.debug("Aspect said: " + result);
        return proceed();
    }
}

I can see the first log line (Aspect is about to say something...) and then I get the NullPointerException, clearly the Greeter bean has not been injected.

What am I doing wrong? Or is it possible at all to inject beans into aspects?


Answer:

Thanks to the help of the community, I managed to come out with a solution for both the problems. Leaving track here.

PART ONE - aspectjrt.jar in deployment

First, added Shrinkwrap to my dependencies:

<dependency>
    <groupId>org.jboss.shrinkwrap.resolver</groupId>
    <artifactId>shrinkwrap-resolver-api-maven</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.jboss.shrinkwrap.resolver</groupId>
    <artifactId>shrinkwrap-resolver-impl-maven</artifactId>
          <scope>test</scope>
</dependency>
<dependency>
       <groupId>org.jboss.shrinkwrap.resolver</groupId>
       <artifactId>shrinkwrap-resolver-impl-maven-archive</artifactId>
      <scope>test</scope>
</dependency>

<version> is not needed: Arquillian's BOM - already included - will take care of that.

Then add aspectj to deployment classpath:

@RunWith(Arquillian.class)
public class ArquillianTest {
    private static final String[] DEPENDENCIES = {
        "org.aspectj:aspectjrt:1.8.7"
    };

    @Deployment
    public static JavaArchive createEnvironement() {
        JavaArchive lib = ShrinkWrap.create(JavaArchive.class, "libs.jar");
        for (String dependency : DEPENDENCIES) {
            lib.merge(Maven.resolver().resolve(dependency).withTransitivity().asSingle(JavaArchive.class));
        }

        JavaArchive jar = ShrinkWrap.create(JavaArchive.class)
            // create you deployment here
            .as(JavaArchive.class);

        JavaArchive toBeDeployed = jar.merge(lib);

        return toBeDeployed;
    }

    // other stuff, like tests

}

PART TWO: Injecting a bean into an aspect

After further inquiries I think simas_ch was correct in saying that CDI does not inject beans into aspects.

Came out with a workaround: adding an @Injected member into a bean via the aspect.

public interface Advised {
    String buildGreeting(String name);
}

public class AdvisedImpl implements Advised {
    String buildGreeting(String name) {
        return "ADVISED";
    }
}

public class Greeter {
    public String greet(String name) {
        return "Hello, " + name + ".";
    }
}

...

public aspect GreeterAspect {
    @Inject
    private Greeter Advised.greeter; // adding the member to the interface / class. No need for getters / setters

    private pointcut pc() : execution(* x.y.z.Advised.buildGreeting(String));

    String around(Advised adv, String name) : pc() && target(adv) && args(name) {
        log.debug("Aspect is about to say something...");
        String result = proceed(adv, name) + " - " + adv.greeter.greet(name);
        log.debug("Aspect said: '" + result + "'");
        return result;
    }
}

Given the test

@Test
public void test() {
    assertThat(advised, not(is(nullValue())));
    assertThat(advised.buildGreeting("Stefano"), equalToIgnoringCase("advised - hello, stefano."));
}

it succeeds.

Question:

I am investigating AspectJ and its many uses and have discovered mixins.

I can find many examples employing pure AspectJ .aj aspects however I need to use only @AspectJ annotations.

What I am trying to achieve is the following:-

I have a class that I cannot amend, it has a private class variable that I need to interrogate after a particular class method has completed execution. This class does not have getter or setter methods associated with this private class variable.

public final class CannotAmend {

    private Uri privateUri;

    public final void methodOne(){}

    public final void methodTwo(){}

    public final void methodThree(){

        privateUri = "something";   

    }
}

I require an aspect/mixin that can capture @After methodThree() and allow me to see the value set in privateUri.

Is this possible to achieve?

With @AspectJ annotations?

Where can I discover documentation/tutorial/examples of how to achieve this?


Answer:

Within an aspect you can access the private field using the reflection API.

In the aspect you need two things:

  • A pointcut to define methods on which the aspect matches.
  • And a method annotated with @After containing logic that's executed after a method matched by the pointcut returns.

@Aspect
public class MyAspect {

    @Pointcut("execution(* CannotAmend.methodThree(..))")
    public void methodThreePointcut(){
    }

    @After("methodThreePointcut()")
    public void afterMethod(JoinPoint joinPoint) throws NoSuchFieldException, IllegalAccessException {
        Object instance = joinPoint.getThis();

        Field privateUriField = instance.getClass().getDeclaredField("privateUri");
        privateUriField.setAccessible(true);

        String privateUri = (String) privateUriField.get(instance);
        System.out.println(privateUri); // prints "something"
    }
}

On a side note, using String constants to access a private field is not a clean solution. If sometime in the future the name of the variable changes or if it's removed, the aspect will break.

Question:

I am trying to use Aspect Oriented Programming to execute a simple Fibonacci function and trace all calls to any method apart from the ones in Java and also display the nesting level of them.

Java Code:

package tracing;

public class Test {

    static int fib(int n) {
        if (n<=1)
            return n;
        else
            return fib(n-1) + fib(n-2);
    }

    static void report(int n,int r) {
        System.out.println("fib("+n+")="+r);
    }

    public static void main(String[] a) {
        report(4,fib(4));
    }
}

AspectJ Code:

package tracing;

public aspect Trace {
    String prefix = "";

    Object around(): call(* *(..)) && !within(java..*) && !within(FigureEditor..*) {
        System.out.println(prefix+thisJoinPoint.getSignature());
        prefix = ">" + prefix;
        Object result = proceed();
        prefix = prefix.substring(1);
        return result;
    }
}

Note: && !within(FigureEditor..*) is used only to avoid the functions in a class of a different package.


Console Output - Errors:

Exception in thread "main" java.lang.StackOverflowError     at
org.aspectj.runtime.internal.AroundClosure.<init>(AroundClosure.java:34)
    at tracing.Trace$AjcClosure1.<init>(Trace.aj:1)     at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)   at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)   at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)   at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)   at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)   at
tracing.Trace.ajc$around$tracing_Trace$1$ef88057b(Trace.aj:7)

Update: The output I want is similar to below:

void Test.main(String [])
>void Test.report(int, int)<br>
>>int Test.fib(int)<br>
>>>int Test.fib(int)<br>
>>>>int Test.fib(int)<br>
>>>>>int Test.fib(int)<br>
>>>>>int Test.fib(int)<br>
>>>>int Test.fib(int)<br>
>>>int Test.fib(int)<br>
>>>>int Test.fib(int)<br>
>>>>int Test.fib(int)<br>
>> void Test.write(String) fib(4)=3

Answer:

I'm not sure if you're using Eclipse or some other IDE to develop your AspectJ code, but if you do, you might notice that there are AspectJ markers shown by the IDE in the method body of your around() advice itself, which means they themselves (the method calls inside your around() advice) get woven by your aspect, as shown in the following image:

That means, in order to avoid the infinite recursion occuring in your around() advice, where the advice is getting called repeatedly from inside itself, you need to exclude the control flow of the advice from getting advised. You can exclude all code inside the control flow of any advice easily by including the following pointcut expression: !cflow(adviceexecution()) so your aspect code would look like this (reformatted a little bit):

public aspect Trace {

    String prefix = "";

    Object around(): call(* *(..)) 
        && !within(java..*) 
        && !within(FigureEditor..*) 
        && !cflow(adviceexecution()) {

        System.out.println(prefix+thisJoinPoint.getSignature());
        prefix = ">" + prefix;
        Object result = proceed();
        prefix = prefix.substring(1);

        return result;
    }
}

From the AspectJ documentation on pointcut expressions:

cflow(Pointcut): Picks out each join point in the control flow of any join point P picked out by Pointcut, including P itself.

adviceexecution(): Picks out all advice execution join points.

EDIT: adding Aspect code to reflect the updated question

Your update to your original question clarifies your intention with your aspect. I've updated the aspect code to reflect these changes. The resulting aspect would look like this:

public aspect Trace {

    String prefix = "";

    Object around(): call(* *(..)) 
        && !within(java..*)
        && !if(thisJoinPoint.getTarget()!=null && thisJoinPoint.getTarget().getClass().getName().startsWith("java"))
        && !within(FigureEditor..*) 
        && !within(Trace) {

        System.out.println(prefix+thisJoinPoint.getSignature());
        prefix = ">" + prefix;
        Object result = proceed();
        prefix = prefix.substring(1);

        return result;
    }
}

I replaced the exclusion of the control flows of all advice execution code with the exclusion of only the Trace aspect, and included a runtime test to exclude all calls to code in the java package.

Question:

I've got an @Aspect annotated class that is calling ProceedingJoinPoint#proceed(). This method throws Throwable and thus the class looks something like this:

@Aspect
@Component
public class MyClass{

    @Around("@annotation(myAnnotation)")
    public Object myMethod(final ProceedingJoinPoint joinPoint) throws Throwable {
        //some code here
        try {
            return joinPoint.proceed();
        } finally {
            //some more code here
        }
    }
}

Is it ok for myMehtod to throw a Throwable in this scenario where I have to call another method that throws Throwable? Should I avoid throwing Throwable and somehow convert it to Exception or Error?

In either case I'd like to know why as well. Thank you.


Answer:

No, it is not okay to throw Throwable. Errors and unchecked exceptions are not supposed to be caught; Errors are serious or fatal system problems, while unchecked exceptions (usually) expose programmer mistakes. Declaring a signature with throws Throwable forces callers to catch, and allows them to suppress, things which shouldn't be caught or suppressed.

If at all possible, you should fix the ProceedingJoinPoint.proceed() method's signature, but if you don't have control over that class, your own code should wrap it in a more reasonable exception.

How to wrap it depends on what you expect of callers of your code. If any Throwable is likely to be a condition that no one can possibly do anything to correct or address, you might as well wrap it in an unchecked RuntimeException:

try {
    return joinPoint.proceed();
} catch (Throwable t) {
    throw new RuntimeException(t);
} finally {
    //some more code here
}

If you want to make sure callers handle all Throwables gracefully, you should create your own application-specific exception class:

try {
    return joinPoint.proceed();
} catch (Throwable t) {
    throw new JoinPointException(t);
} finally {
    //some more code here
}

The exception class is simply:

public class JoinPointException
extends Exception {
    private static final long serialVersionUID = 1;

    public JoinPointException(Throwable cause) {
        super(cause);
    }

    public JoinPointException(String message,
                              Throwable cause) {
        super(message, cause);
    }
}

Question:

I'm trying to understand the difference between execution and call in AOP as simply as possible. From what I gather, execution() will add a join point in the executing code, so HelloWorldSayer.sayHello() in this case, but if the pointcut was call(), then the join point will be HelloWorldSayer.main(). Is this correct?

public class HelloWorldSayer {
    public static void main (String[] args) {
        sayHello();
    }

    public static void sayHello() {
        System.out.println("Hello");
    }
}

public aspect World {
    public hello():
        execution(static void HelloWorldSayer.sayHello());

    after() hello() {
        System.out.println("Bye");
    }
}

Answer:

If we look at the HelloWorldSayer class again, there are 4 join point shadows (2 execution pointcuts and 2 call pointcuts).

In other words, public static void main (String[] args) and public static void sayHello() refer to the execution pointcut. (HelloWorldSayer.)sayHello(); and System.out.println("Hello"); refer to the call pointcut.

If you change the declared pointcut as follows, the pointcut selects sayHello();

public pointcut hello():
    call(static void HelloWorldSayer.sayHello());

On the other hand, you change the declared pointcut as follows, the pointcut selects the sayHello method declaration public static void sayHello().

public pointcut hello():
    execution(static void HelloWorldSayer.sayHello());

At last, please read this answer to get better understanding about call() and execution(): https://stackoverflow.com/a/18149106/904745

Question:

I am trying to execute a set code in my advice but can't able to weave the code inside the function which has the @SecuredAPI annotation and calls the setQuery() function.

Previously I tried the following pointcut and it worked very well

call(* org.elasticsearch.action.search.SearchRequestBuilder.setQuery(org.elasticsearch.index.query.QueryBuilder)) && args(queryBuilder)

But need to also include the annotated condition in this. Please help me with that.

My poincut and advice looks like this

@Around(value = "@annotation(SecuredAPI)  && call(* org.elasticsearch.action.search.SearchRequestBuilder.setQuery(org.elasticsearch.index.query.QueryBuilder)) && args(queryBuilder)" )
public Object decorateQuery(ProceedingJoinPoint proceedingJoinPoint, QueryBuilder queryBuilder) throws Throwable {
  // ...
}

And my function looks like this

@SecuredAPI
public List<Integer> getAllIds() {
  // ...
  SearchResponse response = conn
    .getESClient().prepareSearch(ElasticSearchConstants.ATTRIBUTE_INDEX)
    .setSearchType(SearchType.DEFAULT)
    //.setQuery(QueryBuilders.queryStringQuery(searchQuery))
    .setQuery(qb)
    .setFrom(0).setSize(10000).setExplain(true).get();
}

Please help me to find a way to may it work for following condition


Answer:

Okay, while editing your question (the code formatting was a bit chaotic) I read it again and you said that call() actually works for you. So you are not using Spring AOP because call() is not supported there. You must be using AspectJ, probably via LTW (load-time weaving) or maybe via CTW (compile-time weaving). It does not make a difference for the answer.

The problem is that @annotation(SecuredAPI) would actually work inside an execution() pointcut defined on your annotated method, but the method you call from there is not annotated, so the advice does not get triggered for call(). It only would if the target method setQuery(..) was annotated, but it is not. Consequently, @annotation() is not the right pointcut for your purpose.

What you want to express is: "a call to setQuery(..) from within code annotated by @SecuredAPI". This is done as follows (AspectJ example without Spring, please adjust class and package names to your needs):

package de.scrum_master.app;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD })
public @interface SecuredAPI {}
package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    Application application = new Application();
    application.doSomething();
    application.doSomethingElse();
  }

  @SecuredAPI
  public void doSomething() {
    System.out.println("Doing something before setting query");
    setQuery("my first query");
    System.out.println("Doing something after setting query");
  }

  public void doSomethingElse() {
    System.out.println("Doing something else before setting query");
    setQuery("my second query");
    System.out.println("Doing something else after setting query");
  }

  public void setQuery(String query) {
    System.out.println("Setting query to: " + query);
  }
}
package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class SecuredAPIAspect {
  @Around("@withincode(de.scrum_master.app.SecuredAPI) && call(* setQuery(..))")
  public Object myAdvice(ProceedingJoinPoint thisJoinPoint) throws Throwable {
    System.out.println(thisJoinPoint);
    return thisJoinPoint.proceed();
  }
}

See? @withincode() is your friend in this case. The console log looks as follows:

Doing something before setting query
call(void de.scrum_master.app.Application.setQuery(String))
Setting query to: my first query
Doing something after setting query
Doing something else before setting query
Setting query to: my second query
Doing something else after setting query

Besides, you also need to use a fully-qualified class name for the annotation such as de.scrum_master.app.SecuredAPI, not just SecuredAPI, unless the annotation happens to be in the same package as your aspect.

Question:

Background

Logging a project using aspects such that all methods, classes, and constructors that are marked with the @Log annotation have information written to a log file.

Problem

Methods appear to be called recursively one-level deep, but the code does not show any such recursive relationship.

Actual

Logged results:

2018-09-25 12:17:29,155 |↷|   EmailNotificationServiceBean#createPayload([SECURE])
2018-09-25 12:17:29,155 |↷|     EmailNotificationServiceBean#createPayload([{service.notification.smtp.authentication.password=password, mail.smtp.port=25, service.notification.smtp.authentication.username=dev@localhost, mail.mime.allowutf8=true, mail.smtp.auth=false, mail.smtp.starttls.enable=false, mail.smtp.timeout=10000, mail.smtp.host=localhost}])
2018-09-25 12:17:29,193 |↷|       EmailPayloadImpl#<init>([{service.notification.smtp.authentication.password=password, mail.smtp.port=25, service.notification.smtp.authentication.username=dev@localhost, mail.mime.allowutf8=true, mail.smtp.auth=false, mail.smtp.starttls.enable=false, mail.smtp.timeout=10000, mail.smtp.host=localhost}])
2018-09-25 12:17:29,193 |↷|         EmailPayloadImpl#validate([SECURE])
2018-09-25 12:17:29,194 |↷|           EmailPayloadImpl#validate([{service.notification.smtp.authentication.password=password, mail.smtp.port=25, service.notification.smtp.authentication.username=dev@localhost, mail.mime.allowutf8=true, mail.smtp.auth=false, mail.smtp.starttls.enable=false, mail.smtp.timeout=10000, mail.smtp.host=localhost}, SMTP connection and credentials])
2018-09-25 12:17:29,195 |↷|         EmailPayloadImpl#setMailServerSettings([SECURE])
2018-09-25 12:17:29,196 |↷|           EmailPayloadImpl#setMailServerSettings([{service.notification.smtp.authentication.password=password, mail.smtp.port=25, service.notification.smtp.authentication.username=dev@localhost, mail.mime.allowutf8=true, mail.smtp.auth=false, mail.smtp.starttls.enable=false, mail.smtp.timeout=10000, mail.smtp.host=localhost}])
Expected

Expected logged results:

2018-09-25 12:17:29,155 |↷|   EmailNotificationServiceBean#createPayload([SECURE])
2018-09-25 12:17:29,193 |↷|     EmailPayloadImpl#<init>([SECURE])
2018-09-25 12:17:29,193 |↷|       EmailPayloadImpl#validate([SECURE])
2018-09-25 12:17:29,195 |↷|       EmailPayloadImpl#setMailServerSettings([SECURE])
Code

The logging aspect:

@Aspect
public class LogAspect {
    @Pointcut("execution(public @Log( secure = true ) *.new(..))")
    public void loggedSecureConstructor() { }

    @Pointcut("execution(@Log( secure = true ) * *.*(..))")
    public void loggedSecureMethod() { }

    @Pointcut("execution(public @Log( secure = false ) *.new(..))")
    public void loggedConstructor() { }

    @Pointcut("execution(@Log( secure = false ) * *.*(..))")
    public void loggedMethod() { }

    @Pointcut("execution(* (@Log *) .*(..))")
    public void loggedClass() { }

    @Around("loggedSecureMethod() || loggedSecureConstructor()")
    public Object logSecure(final ProceedingJoinPoint joinPoint) throws Throwable {
        return log(joinPoint, true);
    }

    @Around("loggedMethod() || loggedConstructor() || loggedClass()")
    public Object log(final ProceedingJoinPoint joinPoint) throws Throwable {
        return log(joinPoint, false);
    }

    private Object log(final ProceedingJoinPoint joinPoint, boolean secure) throws Throwable {
        final Signature signature = joinPoint.getSignature();
        final Logger log = getLogger(signature);

        final String className = getSimpleClassName(signature);
        final String memberName = signature.getName();
        final Object[] args = joinPoint.getArgs();
        final CharSequence indent = getIndentation();
        final String params = secure ? "[SECURE]" : Arrays.deepToString(args);

        log.trace("\u21B7| {}{}#{}({})", indent, className, memberName, params);

        try {
            increaseIndent();

            return joinPoint.proceed(args);
        } catch (final Throwable t) {
            final SourceLocation source = joinPoint.getSourceLocation();
            log.warn("\u2717| {}[EXCEPTION {}] {}", indent, source, t.getMessage());
            throw t;
        } finally {
            decreaseIndent();
            log.trace("\u21B6| {}{}#{}", indent, className, memberName);
        }
    }

The Log interface definition:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR})
public @interface Log {
    boolean secure() default false;
}

The decompiled service bean:

@Log
public class EmailNotificationServiceBean
implements EmailNotificationService {

    @Log(secure = true)
    @Override
    public EmailPayload createPayload(Map<String, Object> settings) throws NotificationServiceException {
        Map<String, Object> map = settings;
        JoinPoint joinPoint = Factory.makeJP((JoinPoint.StaticPart)ajc$tjp_2, (Object)this, (Object)this, map);
        Object[] arrobject = new Object[]{this, map, joinPoint};
        return (EmailPayload)LogAspect.aspectOf().logSecure(new EmailNotificationServiceBean$AjcClosure7(arrobject).linkClosureAndJoinPoint(69648));
    }

The payload implementation:

@Log
public class EmailPayloadImpl extends AbstractPayload implements EmailPayload {

    @Log(secure = true)
    public EmailPayloadImpl(final Map<String, Object> settings)
                    throws NotificationServiceException {
        validate(settings, "SMTP connection and credentials");
        setMailServerSettings(settings);
    }

    @Log(secure = true)
    private void validate(final Map<String, Object> map, final String message)
                    throws NotificationServiceException {
        if (map == null || map.isEmpty()) {
            throwException(message);
        }
    }

    @Log(secure = true)
    private void setMailServerSettings(final Map<String, Object> settings) {
        this.mailServerSettings = settings;
    }
Question

What is causing:

  • the secure = true constructor annotation attribute to be ignored; and
  • the validate and setMailServerSettings methods to be called and logged twice (once securely and once not)?

I suspect the issues are related.


Answer:

Solution:

To fix duplication issue need to adjust loggedClass() pointcut definition:

@Pointcut("execution(* (@Log *) .*(..)) && !@annotation(Log)")
public void loggedClass() { }

Please also find a link to Proof of concept in the Additional information section.


Explanation:

Issue related to join points (defined by @Pointcut annotation), their patterns cross each other - and this is the reason of duplication in the logs.

In our case all @Pointcuts named descriptive enough, e.g.:

  • loggedClass() covers all methods in the classes annotated by @Log.
  • loggedSecureMethod() covers all methods annotated by @Log(secure = true). Others remain are similar to this one, so let's ignore them for explanation.

So in case when EmailPayloadImpl is annotated with @Log and EmailPayloadImpl.validate() is annotated with @Log(secure = true) - we will have 2 active join points: one secure and one non-secure. And this will cause adding 2 log entries.


Assuming that we want to introduce priority in the annotations, i.e. method-level annotation should overwrite class-level one - the simplest way will be just to avoid crossing join point patterns.

So we will need to have 3 groups for methods:

  1. Methods annotated with @Log(secure = true) = loggedSecureMethod()
  2. Methods annotated with @Log = loggedMethod()
  3. Methods without @Log annotation, but within a class annotated with @Log, which is:

    @Pointcut("execution(* (@Log *) .*(..)) && !@annotation(Log)")
    public void loggedClass() { }
    

Additional information:
  1. In case it will be needed to handle also @Log(secure = true) on the class level - need to add additional join point similar to loggedClass() of course.
  2. Added Proof of concept >> in the GitHub

Question:

Say I have this method:

public void exampleMethod(String myString, Integer myInteger, Object myObject){}

If I have an Aspect @Around that, and I call ProceedingJoinPoint.getArgs() will it always return an array sorted in the order of the signature? Like this?

  public void aspectMethod(final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    Object[] args = proceedingJoinPoint.getArgs();

    args[0]; // String myString?
    args[1]; // Integer myInteger?
    args[2]; // Object myObject?
  }

It does seem to be deterministic, at least for the 10 or so times I've run through this scenario. I can't find anything in the javadocs to say either way.


Answer:

It's always ordered. Knowing that you can even create a map where keys are parameter names and values are parameter values. The order is always same

    String[] keys = ((MethodSignature) jp.getSignature()).getParameterNames();
    Object[] values = jp.getArgs();

    Map<String, Object> params = new HashMap<>();
    IntStream.range(0, keys.length).boxed().forEach(i -> params.put(keys[i], values[i]));

Question:

I have a generic method that accepts any type as its parameter. For example, I would like a pointcut that matches the calls made to the method only with 'String' type as its parameter. Ultimately the requirement is to limit the scope which the advices get executed for to 'String' parameters.

Here is my generic class and method:

public class Param<T> {
    public T execute(T s){
        return s;
    }
}

Main class: My app makes calls to the method with both Boolean and String as parameters.

public static void main(String[] args) {
    Param<String> sp = new Param<String>();
    String rs = sp.execute("myString"); //want a joint point

    Param<Boolean> bp = new Param<Boolean>();
    Boolean rb = bp.execute(true); //dont want a joint point
}

Below pointcuts are valid for both String and Boolean parameters (work for any type actually). But I would like a pointcut to intercept method calls only when parameter is of type String.

@Pointcut("call(* com.amazon.auiqa.aspectj.generics.Param.execute(**))")
void param(){}

@Pointcut("execution(Object com.amazon.auiqa.aspectj.generics.Param.execute(Object))")
void param(){}

Below ones did not work for me:

 @Pointcut("execution(String com.amazon.auiqa.aspectj.generics.Param.execute(String))")
 @Pointcut("call(String com.amazon.auiqa.aspectj.generics.Param.execute(String))")

I was wondering if it is possible to achieve what I want to achieve here. I would like to do the same thing with method return types.


Answer:

You cannot do that with AspectJ, nor with any other bytecode manipulation library as generic type information is actually erased from the compiled bytecode (as of Java 9), so your generic method becomes public Object execute(Object s), since the type argument T is unbounded. See Type Erasure at the Java Documentation for further info.

While the original method signature is preserved in the form of metadata, the compiler can check whether type bounds are respected or not while compiling against generic code, but this will not help you in any way to determine what generic type argument an instance of that class was instantiated with, because that information is simply not present at all.

Question:

I'm trying to set up AspectJ for Metrics in a simple java project. I have added the required dependencies in pom.xml. When i do mvn compile, I get the following warnings. It says, the advice is not applied. Where am i going wrong

[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[WARNING] advice defined in io.astefanutti.metrics.aspectj.TimedAspect has not been applied [Xlint:adviceDidNotMatch]
    /root/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.1.0/metrics-aspectj-1.1.0.jar!io/astefanutti/metrics/aspectj/TimedAspect.class:26

[WARNING] advice defined in io.astefanutti.metrics.aspectj.ExceptionMeteredAspect has not been applied [Xlint:adviceDidNotMatch]
    /root/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.1.0/metrics-aspectj-1.1.0.jar!io/astefanutti/metrics/aspectj/ExceptionMeteredAspect.class:26

[WARNING] advice defined in io.astefanutti.metrics.aspectj.MeteredAspect has not been applied [Xlint:adviceDidNotMatch]
    /root/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.1.0/metrics-aspectj-1.1.0.jar!io/astefanutti/metrics/aspectj/MeteredAspect.class:26

[WARNING] advice defined in io.astefanutti.metrics.aspectj.ExceptionMeteredStaticAspect has not been applied [Xlint:adviceDidNotMatch]
    /root/.m2/repository/io/astefanutti/metrics/aspectj/metrics-aspectj/1.1.0/metrics-aspectj-1.1.0.jar!io/astefanutti/metrics/aspectj/ExceptionMeteredStaticAspect.class:26

This my pom.xml

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.dropwizard.metrics</groupId>
      <artifactId>metrics-core</artifactId>
      <version>3.1.0</version>
    </dependency>
    <dependency>
      <groupId>io.dropwizard.metrics</groupId>
      <artifactId>metrics-graphite</artifactId>
      <version>3.1.2</version>
    </dependency>
    <dependency>
      <groupId>io.dropwizard.metrics</groupId>
      <artifactId>metrics-annotation</artifactId>
      <version>3.1.2</version>
    </dependency>
    <dependency>
      <groupId>io.astefanutti.metrics.aspectj</groupId>
      <artifactId>metrics-aspectj</artifactId>
      <version>1.1.0</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.8.7</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjtools</artifactId>
      <version>1.6.2</version>
    </dependency>
    <dependency>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>aspectj-maven-plugin</artifactId>
      <version>1.8</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.8</version>
        <configuration>
          <complianceLevel>1.6</complianceLevel>
          <source>1.6</source>
          <target>1.6</target>
          <aspectLibraries>
            <aspectLibrary>
              <groupId>io.astefanutti.metrics.aspectj</groupId>
              <artifactId>metrics-aspectj</artifactId>
            </aspectLibrary>
          </aspectLibraries>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <filters>
                <filter>
                  <artifact>*:*</artifact>
                  <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                  </excludes>
                </filter>
              </filters>
              <transformers>
                <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                  <mainClass>dropwizard.App</mainClass>
                </transformer>
              </transformers>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

Here is my code:

package dropwizard;

import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.MetricFilter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries;
import com.codahale.metrics.annotation.Metered;
import com.codahale.metrics.annotation.Timed;
import com.codahale.metrics.graphite.Graphite;
import com.codahale.metrics.graphite.GraphiteReporter;
import io.astefanutti.metrics.aspectj.Metrics;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

/**
 * Hello world!
 *
 */
@Metrics(registry = "graphiteregistry2")
public class App 
{
    static final MetricRegistry registry = new MetricRegistry();
    public static void main(String args[]) {
        startReport();
        test();
        wait5Seconds();
    }

    static void startReport() {

        final Graphite graphite = new Graphite(new InetSocketAddress("127.0.0.1", 2003));

        final GraphiteReporter reporter = GraphiteReporter.forRegistry(registry)
                .prefixedWith("test8.example.com")
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .filter(MetricFilter.ALL)
                .build(graphite);
        reporter.start(1, TimeUnit.SECONDS);

        ConsoleReporter reporter1 = ConsoleReporter.forRegistry(registry)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build();
        reporter1.start(3, TimeUnit.SECONDS);

        SharedMetricRegistries.add("graphiteregistry2", registry);

    }

    static void wait5Seconds() {
        try {
            Thread.sleep(5*1000);
        }
        catch(InterruptedException e) {}
    }

    @Timed(name = "test8method")
    @Metered(name = "methodmeter")
    static void test() {

        //Timer.Context time = responses.timer("test8.update").time();
        System.out.println("inside test");
        try {

            for(int i=0;i<10000;i++){}

        }
        finally {
            //time.stop();
        }
    }

}

Answer:

The warnings only mean that in the tool library some aspects are defined the pointcuts of which do not fire and which thus have not been applied. Looking at your code, you really do not use those or use them in places where they should not be applied, so the warnings just describe the situation. In detail:

  • @Metrics: is applied, no warning.
  • @Timed: is not applied because used on static method, thus a warning. If you look at the aspect source code you see that the pointcut only targets non-static methods: execution(@Timed !static * (@Metrics Profiled+).*(..))
  • @Metered: is not applied because used on static method, thus a warning. If you look at the aspect source code you see that the pointcut only targets non-static methods: execution(@Metered !static * (@Metrics Profiled+).*(..))

Remove the static from your test() method and see what happens when you recompile.

Question:

I have 2 classes

class Fragment1{
   createView(SomeObject p1, AnoterObject p2)
}

@AutoLayout(String annotationParam)
class Fragment2 extends Fragment1{
}

How i can do @Around createView on Fragment2.createView call and get annotationParam? Thanks

ADD: If i add method stub into Fragment2, it is start be possible to use next annotation @Around("createMethod(inflater, group, savedState) && @within(autoInflate)"), but it is a very ugly solution

SOLUTION: Thanks to @kriegaex i found solution:

@Around("execution(* com.github.a_kokulyuk.kotakt.ui.BaseFragment+.*(*, *, *)) && args(inflater, parent, savedState) && @this(an)")
    public Object doLayout(ProceedingJoinPoint jo, LayoutInflater inflater, ViewGroup parent, Bundle savedState, AutoLayout an) throws Throwable {
        return inflater.inflate(an.value(), parent, false);
    }

Answer:

Given this annotation:

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

Let us assume we have three classes:

  • a parent class without annotation,
  • a plain child class without annotation and
  • an annotated child class:
package de.scrum_master.app;

public class Parent {
    public void doSomething() {}
}
package de.scrum_master.app;

public class PlainChild extends Parent {
    int doSomethingElse() { return 11; }
}
package de.scrum_master.app;

@MyAnnotation
public class AnnotatedChild extends Parent {
    String doSomethingSpecial(int number) { return ""; }
}

Here is a little driver application instantiating all three classes, calling all available methods on them, inherited or not, with different signatures and return types:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        new Parent().doSomething();
        new PlainChild().doSomething();
        new PlainChild().doSomethingElse();
        new AnnotatedChild().doSomething();
        new AnnotatedChild().doSomethingSpecial(123);
    }
}

Finally, here is the aspect doing what was asked in the question: It intercepts all method executions in Parent or any of its subclasses (thus the +), but only if the class of the current instance this bears @MyAnnotation:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MyAspect {
    @Around(
        "execution(* de.scrum_master.app.Parent+.*(..)) && " +
        "@this(de.scrum_master.app.MyAnnotation)"
    )
    public Object myAdvice(ProceedingJoinPoint thisJoinPoint) {
        System.out.println(thisJoinPoint);
        System.out.println("  " + thisJoinPoint.getThis());
        return thisJoinPoint.proceed();
    }
}

The console log:

execution(void de.scrum_master.app.Parent.doSomething())
  de.scrum_master.app.AnnotatedChild@681a9515
execution(String de.scrum_master.app.AnnotatedChild.doSomethingSpecial(int))
  de.scrum_master.app.AnnotatedChild@13221655

As you can see, doSomething() is called three times, but only intercepted once. You can also see from the printed getThis() object, that really the right execution is intercepted.

Question:

Dear all I am curently using Spring AOP (v4) and AspectJ with load-time-weaver.

I am looking currently for a way to add a dirty flag mechanism into my beans. Therefore I I though of using AOP to call a method before a setter of my beans get called. This I achieved already, but how can I access the old field value beforeit get modified? Or is there a way to get the field name so I can call the getter before the setter get called?

Can anybody provide me here some example how the pointcut/advice has to look like to get it a passed as arguments?

@Aspect
public class MyAspect {

  @Before("execution(* foo.*.set*(..))") 
  public void beforeSetterCalled(JoinPoint joinPoint){
    System.out.println("beforeSetter");
  }
}

Unfortunately it seems that Spring AOP does not support the "set()" field-pointcut construct, is this correct? OR exists someway to use this?

Thank you for any help.


Answer:

I would recommend to use full AspectJ in combination with a set() pointcut in order to get an efficient solution. But if you do not mind having a slow, ugly solution involving reflection you can also do something like this:

package de.scrum_master.app;

public class Person {
    private int id;
    private String firstName;
    private String lastName;

    public Person(int id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public int getId() { return id; }
    public String getFirstName() { return firstName; }
    public String getLastName() { return lastName; }

    public void setId(int id) { this.id = id; }
    public void setFirstName(String firstName) { this.firstName = firstName; }
    public void setLastName(String lastName) { this.lastName = lastName; }

    @Override
    public String toString() { return "Person [" + id + ", " + firstName + " " + lastName + "]"; }

    public static void main(String[] args) {
        Person albert = new Person(1, "Albert", "Camus");
        Person audrey = new Person(2, "Audrey", "Hepburn");
        System.out.println(albert);
        System.out.println(audrey);
        System.out.println();
        albert.setId(8);
        albert.setLastName("Einstein");
        audrey.setId(9);
        audrey.setLastName("Tautou");
        System.out.println();
        System.out.println(albert);
        System.out.println(audrey);
    }
}
package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.SoftException;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class SetterInterceptor {
    @Before("execution(* set*(*)) && target(instance) && args(newValue)")
    public void beforeSetterCalled(JoinPoint thisJoinPoint, Object instance, Object newValue) {
        String methodName = thisJoinPoint.getSignature().getName();
        try {
            System.out.println(
                methodName.substring(3) + ": " +
                instance
                    .getClass()
                    .getMethod(methodName.replaceFirst("set", "get"))
                    .invoke(instance) +
                " -> " + newValue
            );
        } catch (Exception e) {
            throw new SoftException(e);
        }
    }
}

Console log:

Person [1, Albert Camus]
Person [2, Audrey Hepburn]

Id: 1 -> 8
LastName: Camus -> Einstein
Id: 2 -> 9
LastName: Hepburn -> Tautou

Person [8, Albert Einstein]
Person [9, Audrey Tautou]

Question:

Please see the updates below.


I have a Spring Boot application where I accept TCP/IP connections:

   public MyClass implements InitializingBean {
   @Override
    public void afterPropertiesSet() throws Exception {

        try (ServerSocket serverSocket = new ServerSocket(port)) {

            while (true) {

                Socket socket = serverSocket.accept();                   
                new ServerThread(socket).start();
            } 
        }
    }

    ...

    private class ServerThread extends Thread {
            @Override
            public void run() {
                try (InputStream input = socket.getInputStream();
                     OutputStream output = socket.getOutputStream()) {

                     // Read line from input and call a method from service:
                     service.myMethod(lineConvertedToMyObject);

                } catch {
                    ...
                }
            }
    }

}

Now this works fine, as it is. But when I introduce AspectJ to myMethod:

@Aspect
@Component
public class MyServiceAspect {

    private static final Logger logger = LoggerFactory.getLogger(MyServiceAspect.class);

    @Around(value = "execution(* com.package.to.MyService.myMethod(..))")
    public MyObject rules(ProceedingJoinPoint joinPoint) throws Throwable {

        long startTime = System.currentTimeMillis();

        MyObject obj = (MyObject) joinPoint.proceed();

        logger.debug("Took {} milliseconds", System.currentTimeMillis() - startTime);

        return obj;
    }
}

service.myMethod is not called and the thread is blocked. What am I missing?

Update:

So here's the deal: MyService, MyServiceImpl and MyServiceAspect are all in the same package. Moving MyServiceAspect into another package made it work.

Does this ring a bell for anyone? Happy to award the bounty to anyone explaining this behavior. Thanks!

Update 2:

Yet another solution: Adding @DependsOn(value = {"myServiceAspect"}) on top of MyServiceImpl again resolves the issue, still wondering why though.


Answer:

Actual problem

As it was described by Alexander Paderin >> in his answer to the related question >> infinite loop in the afterPropertiesSet() was the thread blocker, since control wasn't return back to Spring in this case.

1. Working example with your samples (not actual after question edit)

Code samples you've provided do not contain issues directly, AspectJ declaration is fine.

First of all, please let me share working example: spring-aspectj-sockets. It is based on Spring 5.1.0 and AspectJ 1.9.1 (currently latest versions) and uses your samples, works independent of the location/package of MyServiceAspect.


2. Issue explanation
2.1. Intro

The most possible thread blocker in your samples is a call to ServerSocket.accept(), javadocs for this method says:

Listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made.

There are 2 correct ways of handling accept():

  1. To initialize connection first, e.g.:

    serverSocket = new ServerSocket(18080);
    clientSocket = new Socket("127.0.0.1", 18080); // initializing connection
    Socket socket = serverSocket.accept(); // then calling accept()
    
  2. Set up timeout to wait for acceptance:

    serverSocket = new ServerSocket(18080);
    serverSocket.setSoTimeout(5000); // 5 seconds timeout
    Socket socket = serverSocket.accept(); // then calling accept()
    

    NOTE: If within 5 seconds there will be no connections, accept() will throw exception, but will not block the thread

2.2. Assumption

I assume that you are using 1-st approach and somewhere you have a line which initializes the connection, i.e. clientSocket = new Socket("127.0.0.1", 18080);.

But it is called (e.g. if static declarations are used):

  • After serverSocket.accept() in case MyServiceAspect is located in the same package and
  • Before - in case MyServiceAspect is located in some other place

3. Debugging

I'm not sure if this is needed, have doubts because of bounty's description, let me cover this quickly just in case.

You can debug your application using Remote Debugging - it will cover aspects, child threads, services, etc. - you will only need to:

  1. Run Java with specific arguments like it is described in this question >>
  2. And connect to the specified debug port using IDE (steps for Eclipse are described in the same question)

Question:

Im working with some AspectJ code and i want to catch all the executions for none private pointcuts.

@Pointcut("execution(public * *(..))")//Public
public void publicMethod(){};
@Pointcut("execution(protected * *(..))"//Protected
public void protectedMethod(){}

@Pointcut("@annotation(mypackage.name.annotationName")
public void annotationPointcut(){}

@Around("annotationPointcut() && (protectedMethod() || publicMethod())")
public Object test(){ System.out.println("Should not print private"); }

I read about using ! (not) but could not get it to work. Something like

@Pointcut("!execution(private * *(..))"

But without getting it to work.

I could not find a modifier name for default class modifier in the aspectJ, have I missed it or do i need to try and solve it by using ! not sign in some sort of way?

Regards a new dev that are learning aspectJ


Answer:

Try this to catch all non private methods.

@Pointcut("execution(!private * *(..))")

Question:

My requirement is to profile the elastic search java api get method to find the execution timings.I have written a Spring AOP aspect to do this

@Aspect
@Component
public class PerformanceAspect {

  private final Logger LOGGER = LoggerFactory
        .getLogger(PerformanceAspect.class);

  @Pointcut("execution(*  org.elasticsearch.action..ActionRequestBuilder.get(..))")
  public void getESMethod() {}


  @Around("getESMethod()")
  public void profile(ProceedingJoinPoint pjp) {
    long start = System.currentTimeMillis();
    LOGGER.info("Calling the get method..");
    try {
        pjp.proceed();
        LOGGER.info("Method execution completed");
        long elapsedTime = System.currentTimeMillis() - start;
        LOGGER.info("Method execution time "+elapsedTime);
    } catch (Throwable e) {
        e.printStackTrace();
    }

  }

}

ActionRequestBuilder is in elasticsearch.jar which is loaded by maven. I am using the spring boot with maven. But looks like this aspect is not getting executed at all. Is it because this ActionRequestBuilder is in another JAR file ? If I change the pointcut to any other methods in the project it's working fine. How can I resolve this issue ?


Answer:

Spring AOP only works on Spring Beans, i.e. classes instantiated and maintained by Spring. This seems to be a non-spring core ElasticSearch class. You need to move at least one level up and find out what Spring glue code calls this class, rewriting the pointcut to point at the Spring glue code.

But I'm not even sure that will work, as Spring Data uses its own proxy magic, so I'm not sure you can apply AOP proxies to those. The safest bet would be to point the pointcut at your code that calls ElasticSearch

Question:

I am trying to build a custom performance measuring library, which an user can use to measure the performance of any method in an application. My goal is to achieve this thing without changing the existing Java code of the user's application.

The library will use a MethodInterceptor implementation as an advice to measure the performance. The only input from the user will be a pointcut expression of his/her choice, nothing else. And using the provided pointcut expression, my library will be able to intercept the matching method call to measure the performance.

In a nutshell user will only configure like below in spring xml:

<bean id="configBean" class="com.something.PointCutConfigBean">
    <property name="patterns">
        <list>
            <value>"execution(* com.company.CustomerDao.addCustomer(..))"</value>
        </list>
    </property>
</bean>

My question is how can I achieve this in my library? How do I implement the PointCutConfigBean class? I can use spring 2 and aspectj.

I know, same thing can be achieved if the user just write a normal <aop:config and use my advice. But I am just looking for something cooler if at all possible.


Answer:

That's a good question !

Why don't you create an annotation, for tagging method or fields if you need, and write an aspect who can get annotations . Class.getAnnotations(), and if the your annotation is present, you run your code ?

Question:

To add a field to some specific class with aspectj we do

package com.test;

public class MyClass {
    private String myField;
}

public aspect MyAspect
{
    private String MyClass.myHiddenField;
}

How do we add a field to a class that is annotated with some custom annotation?

example usage : if class is annotated with @CustomLoggable add a Logger field and some methods.

or

if method has the @ReadLocked annotation then class will have a ReentrantReadWriteLock field and the appropriate logic injected, etc.


Answer:

Actually you cannot make inter-type declarations (ITD) on annotation types, i.e. you need to know concrete class names in order to declare static or non-static members or methods directly.

The usual workaround is:

  • Create an interface with all the methods you need.
  • Provide implementations for each interface method.
  • Make each annotated type implement the interface via ITD.

Now if you also want to add a static member such as a logger to all annotated types, again if you do not know the exact class names you need to use a workaround:

  • Create an aspect holding the desired member(s). Let's call it LoggerHolder in this example.
  • Make sure that one aspect instance per target class is created instead of the default singleton aspect instance. This is done via pertypewithin.
  • In order to avoid runtime exceptions you must not initialise the members directly via Logger logger = ... but need to do it lazily, waiting until after the target type's static initialisation phase is finished.
  • You also need to provide an accessor method like LoggerHolder.getLogger() in the aspect and call it whenever necessary.
  • In order to hide all the ugly aspect stuff from the end user I recommend to add yet another accessor method LoggableAspect.getLogger() (same method name for convenience) to the ITD interface mentioned above and provide a method implementation extracting the member reference from the aspect instance via LoggerHolder.aspectOf(this.getClass()).getLogger().

Attention: I am using two concepts at once here, mixing them in one application because you asked for both static members and non-static methods added to annotated classes:

  • Helper interface + implementation added to your core code via ITD
  • Holder aspect declaring member(s) and associated with target classes via pertypewithin in order to emulate static members

Now here is some sample code:

Annotation:

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface CustomLoggable {}

Two classes, one bearing the annotation and one not bearing it:

package de.scrum_master.app;

public class OrdinaryClass {
    public void doSomething() {
        System.out.println("Logging some action directly to console");
    }
}
package de.scrum_master.app;

import java.util.logging.Level;

@CustomLoggable
public class AnnotatedClass {
    public void doSomething() {
        getLogger().log(Level.INFO, "Logging some action via ITD logger");
        getLogger().log(Level.INFO, someOtherMethod(11));
    }
}

As you can see, the second class uses two methods which have not been declared directly within the class: getLogger() and someOtherMethod(int). Both of them will be declared via ITD further below, the former providing access to the pseudo-static member and the latter being just another method you want declared on each annotated class.

Aspect holding an instance of the pseudo-static member:

package de.scrum_master.aspect;

import java.util.logging.Logger;
import de.scrum_master.app.CustomLoggable;

public aspect LoggerHolder
    pertypewithin(@CustomLoggable *)
{
    private Logger logger;

    after() : staticinitialization(*) {
        logger = Logger.getLogger(getWithinTypeName());
    }

    public Logger getLogger() {
        return logger;
    }
}

As I said earlier, please note the usage of pertypewithin and staticinitialization. Another convenient thing is to use the aspect's getWithinTypeName() method in order to get the target class name for naming the logger.

Aspect declaring an interface + implementation and applying it to all target types:

package de.scrum_master.aspect;

import java.util.logging.Logger;
import de.scrum_master.app.CustomLoggable;

public aspect LoggableAspect {
    public static interface Loggable {
        Logger getLogger();
        String someOtherMethod(int number);
    }

    declare parents : (@CustomLoggable *) implements Loggable;

    public Logger Loggable.getLogger() {
        return LoggerHolder.aspectOf(this.getClass()).getLogger();
    }

    public String Loggable.someOtherMethod(int number) {
        return ((Integer) number).toString();
    }
}

For simplicity, I just declared the interface as a static nested type within the aspect. You can also declare the interface separately, but here you see it in its context which for me is preferable.

The key thing here is the declare parents statement making each target class implement the interface. The two method implementations at the end show how to provide "normal" method implementations as well as how to access the logger from the holder aspect via aspectOf.

Driver class with entry point:

Last, but not least, we want to run the code and see if it does what we want.

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        new OrdinaryClass().doSomething();
        new AnnotatedClass().doSomething();
    }
}

Console output:

Logging some action directly to console
Mrz 15, 2015 11:46:12 AM de.scrum_master.app.AnnotatedClass doSomething
Information: Logging some action via ITD logger
Mrz 15, 2015 11:46:12 AM de.scrum_master.app.AnnotatedClass doSomething
Information: 11

Voilà! Logging works, the Logger has a nice name de.scrum_master.app.AnnotatedClass and calling the two interface methods works as expected.

Alternative approach:

Since AspectJ 1.8.2 annotation processing is supported, see also this blog post. I.e. you could use APT in order to generate one aspect per annotated type and introduce static members and additional methods directly without any tricks such as per-type instantiation, accessor methods members within holder aspect instances and interfaces. This comes at the cost of an additional build step, but I think it would be a very neat and straightforward way to solve your problem. Let me know if you have any difficulty understanding the examples and need more help.

Question:

Is there a (pref portable) way to check if The JVM has been stated with a particular -javaagent?

In particular I'm interested to know if the aspectj load time weaver has loaded or not. (I'm trying to provide a helpful error msg in the case of incorrect startup).


Answer:

The following code shows

  • a way to determine any -javaagent:... JVM arguments,
  • a way to check if the AspectJ weaving agent entry point class (the one mentioned in the manifest entry Premain-Class: of aspectjweaver.jar) is loaded.

The former just proves that the argument was given on the command line, not that the agent was actually found and started.

The latter just proves that the weaver is available on the classpath, not that it was actually started as an agent. The combination of both should give you pretty much confidence that the agent is actually active.

package de.scrum_master.app;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.List;

public class Application {
    public static void main(String[] args) {
        RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
        List<String> arguments = runtimeMxBean.getInputArguments();
        for (String argument : arguments) {
            if (argument.startsWith("-javaagent:"))
                System.out.println(argument);
        }
        try {
            Class.forName("org.aspectj.weaver.loadtime.Agent");
        } catch (ClassNotFoundException e) {
            System.err.println("WARNING: AspectJ weaving agent not loaded");
        }
    }
}

You also might find the question Starting a Java agent after program start and some of its answers helpful.


Update:

Okay, here is a combination of my own solution and yours, but one which actually works even if the weaver is unavailable, which is important because this is what you want to check in the first place:

public static boolean isAspectJAgentLoaded() {
    try {
        Class<?> agentClass = Class.forName("org.aspectj.weaver.loadtime.Agent");
        Method method = agentClass.getMethod("getInstrumentation");
        method.invoke(null);
    } catch (Exception e) {
        //System.out.println(e);
        return false;
    }
    return true;
}

Update 2:

After some discussion with the OP bacar I have decided to offer a solution which does not use reflection but catches NoClassDefError instead:

public static boolean isAspectJAgentLoaded() {
    try {
        org.aspectj.weaver.loadtime.Agent.getInstrumentation();
    } catch (NoClassDefFoundError | UnsupportedOperationException e) {
        System.out.println(e);
        return false;
    }
    return true;
}

Now both main error types

  • weaving agent is available on the classpath, but instrumentation has not been initiated because aspectjweaver.jar was not started as a Java agent,
  • agent aspectjweaver.jar is not on the classpath at all and class org.aspectj.weaver.loadtime.Agent is thus unavailable

are handled gracefully by returning false after warning messages (in this simple examples just the exceptions which say clearly what is wrong) have been printed on the console.

Possible console outputs for the two cases are:

  • java.lang.UnsupportedOperationException: Java 5 was not started with preMain -javaagent for AspectJ
  • java.lang.NoClassDefFoundError: org/aspectj/weaver/loadtime/Agent

Question:

I need to define a point cut which triggers the execution on all methods of a spring service annotated with a custom annotation. The annotation I would like to define the point cut on will be on an other annotation.

@Y
public @interface X {
}

and then the service would be annotated as following

@X
public Service1 {
} 

I tried with the following point cut definition but it only works when @Y is on the service itself, meaning that it doesn't see that the annotation is on @X

@Around("@within(com.mypackage.Y)")

Answer:

I had this exact need in an application. I found this answer, but wasn't satisfied this couldn't be done.

After a bit more searching, I found this cheat sheet for AspectJ/Spring pointcut expressions. The solution in the cheat sheet didn't work exactly as advertised, but I was able to make it work for what I needed.

@Pointcut("within(@(@Annotation *) *)")
public void classAnnotatedWithNestedAnnotationOneLevelDeep() { }

I combined this expression with a @within expression for just the @Annotation to get what I wanted to work.

For method execution:

@Pointcut("execution(@(@com.someorg.SomeAnnotation *) * *(..))")
public void methodAnnotatedWithNestedAnnotationOneLevelDeep() { }

I combined this expression with a @annotation expression for just the @Annotation to get what I wanted to work for methods.

Question:

I'm facing a strange behaviour using AspectJ for a pointcut using my custom annotation.

The pointcut I use is:

@AfterThrowing(pointcut="@annotation(com.core.meta.NotifyOnFailure)", throwing="ex")

The problem I have is that my aspect is executed twice but if I modify the pointcut to:

@AfterThrowing(pointcut="execution(* sendAndReceive(..))", throwing="ex")

It runs once as expected.

The only method I have that raises the aspect is this:

    @NotifyOnFailure // I want to use this annotation to raise the aspect once
    public  String sendAndReceive(String serviceUrl)
    {
         String responseXml = "...";
         try
         {
             throw new Exception("test...");
         }
         catch(Exception x)
         {
            ExternalExecutionException ex = new ExternalApiExecutionException("Service failed");
            throw ex; 
         }
         finally
         {
             ...
         }          

        return responseXml;
    }

Any idea about why my aspect is executed twice when using my custom annotation and only once when I use execution pointcut?


Answer:

Make sure you also restrict the pointcut to execution. Otherwise it will only be restricted to the annotation and thus be used for both call and execution (if AspectJ can advise the call of your method, which it can since it is in your own code). A good comparison between both is here: https://stackoverflow.com/a/18149106/2191746

Your pointcut would then look like this:

@AfterThrowing(pointcut="execution(* *(..)) && @annotation(com.core.meta.NotifyOnFailure)", throwing="ex")

No guarantee on the syntax, as I don't have an aspectJ compiler at hand.

Question:

We're implemented "before" advice using custom annotations so as to only execute certain methods if the (uninteresting to this problem) business logic applies.

We're seeing the aspect called twice for each invocation of the method.

Debugging into it I see Cglib2AopProxy$CglibMethodInvocation.proceed has an array called: interceptorsAndDynamicMethodMatchers. This array lists our PointCut ("RequiresX") twice.

Here is the join point:

@Before(@annotation(requiresX)")
public Object process(ProceedingJoinPoint joinPoint, RequiresACL requiresX) throws Throwable
{
    Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
    log.info(" method:" + method.getName());

    // do business logic of the aspect…

    log.info(" joinPoint.proceed with call to " + method.getName());
 }

and here is our custom annotation

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.Method)
public @interface RequiresX {
}

and here is a method we can to intercept:

@RequiresX()
public String someMethod() {    
    ....
}

This seems pretty vanilla but clearly I've done something wrong. Any suggestions on how to only execute the advice once per call would be greatly appreciated.


Answer:

you should print Pointcut and see the problem like:

@Before(@annotation(requiresX)")
public Object process(ProceedingJoinPoint joinPoint, RequiresACL requiresX) throws Throwable
{

    log.info(" pointcut:" + joinPoint.getKind());
    // do business logic of the aspect…


 }

it will print the problem like:

pointcut:method-call 
pointcut:method-execution

So, you should change Pointcut as:

@Before(@annotation(RequiresX) && execution(@RequiresX * *.*(..)))

Question:

I'm getting some weird errors which seem to eb the result of a missing library, though I can't figure out where it's missing from as all the guides I've seen don't seem to be including anything I'm missing. I've included the AspectJ jars and I'm compiling with ajc through IntelliJ.

Error:ajc: can't determine annotations of missing type javax.cache.annotation.CacheRemove
when weaving type com.webbilly.dao.hibernate.GenericDAO
when weaving classes 
when weaving 
when batch building BuildConfig[null] #Files=10 AopXmls=#0
 [Xlint:cantFindType]

Here it specifies javax.cache.annotation.CacheRemove, but there are other files as well that are missing that I attempted to band-aid with a package from java2s, but it's still missing this one.


Answer:

Include this dependency in your pom file if you are using maven OR download jar from here http://mvnrepository.com/artifact/javax.cache/cache-api/1.0.0 and include it in project.

Question:

I'm working on an aspectj aspect which needs to know where it's invoked from. At the moment I'm using

new Throwable().getStackTrace();

to access this information but each aspect is taking several hundred microseconds to run.

I've looked at the SecurityManager but that only seems to be able to get me the class name.

Are there any other alternatives I've missed?

Update

JMH Benchmark results referred to in my comment on @apangin's answer:

Benchmark                       Mode  Cnt      Score    Error  Units
MyBenchmark.javalangaccess13i   avgt  100   2025.865 ±  8.133  ns/op
MyBenchmark.javalangaccess2i    avgt  100   2648.598 ± 24.369  ns/op  
MyBenchmark.throwable1          avgt  100  12706.978 ± 84.651  ns/op

Benchmark code:

@Benchmark
public StackTraceElement[] throwable1() {
    return new Throwable().getStackTrace();
}

@SuppressWarnings("restriction")
@Benchmark
public static StackTraceElement javalangaccess2i() {
    Exception e = new Exception();
    return sun.misc.SharedSecrets.getJavaLangAccess().getStackTraceElement(e, 2);
}

@SuppressWarnings("restriction")
@Benchmark
public static StackTraceElement javalangaccess13i() {
    Exception e = new Exception();
    return sun.misc.SharedSecrets.getJavaLangAccess().getStackTraceElement(e, 13);
}

Tests run under Windows 10, JDK 1.8.0_112 on a Dell XPS13 9343 (i5-5200U @ 2.2GHz)


Answer:

Unfortunately, Throwable.getStackTrace() seems to be the only viable option to get the caller frame in pure Java 8.

However, there is a JDK-specific trick to access just one selected stack frame. It uses non-standard sun.misc.SharedSecrets API.

public static StackTraceElement getCaller() {
    Exception e = new Exception();
    return sun.misc.SharedSecrets.getJavaLangAccess().getStackTraceElement(e, 2);
}

Here 2 is the index of the required frame.

This works fine until the latest JDK 8, but private API will not be accessible in JDK 9. A good news is that Java 9 will have new standard Stack-Walking API. Here is how to do the same in Java 9.

public static StackWalker.StackFrame getCaller() {
    return StackWalker.getInstance(Collections.emptySet(), 3)
            .walk(s -> s.skip(2).findFirst())
            .orElse(null);
}

The alternative option, that works well for both older and newer versions of Java, is JVMTI GetStackTrace function. It requires linking native code though.

Question:

I have an aspect usable with an annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DumpToFile {

}

And the join point:

@Aspect
@Component
public class DumpToFileAspect {

  @Around("@annotation(DumpToFile)")
  public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {

    ...
    // I likte to read out a parameter from the annotation...
    Object proceed = joinPoint.proceed();

    ...

    return proceed;
  }
}

I can use the aspect successfully on a method with @DumpToFile; however, I would like to pass a parameter to the annotation and retrieve it's value inside my aspect. Eg. @DumpToFile(fileName="mydump"). Can anybody show me how to do that?


Answer:

You should be able to pass the annotation interface to the interceptor method. I haven't tried myself though.

Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DumpToFile {

      String fileName() default "default value";

}

In DumpToFileAspect -

@Aspect
@Component
public class DumpToFileAspect {

  @Around("@annotation(dtf)")
  public Object logExecutionTime(ProceedingJoinPoint joinPoint, DumpToFile dtf) throws Throwable {

    ...
    // I likte to read out a parameter from the annotation...

    System.out.println(dtf.fileName); // will print "fileName"

    Object proceed = joinPoint.proceed();

    ...

    return proceed;
  }
}

Question:

I am looking to create around advice on methods with a specific return type. I'm curious if something like that is possible. I have this method for example:

@Around("execution(* com.mytest.example.*Resource.*(..))")
public Object restCallMade(ProceedingJoinPoint pjp) {
    Response response = null;

    try {
        response = (Response) pjp.proceed();

        // Do other stuff
    } catch (Throwable e) {

    }

    return response;
}

However, if possible I would like that this advice only gets called if the return type of the method is Response. Is that possible?


Answer:

Just use the (fully qualified) type name instead of the joker * in the pointcut's method signature:

@Around("execution(org.foo.Response com.mytest.example.*Resource.*(..))")
public Response restCallMade(ProceedingJoinPoint pjp) {
    Response response = null;
    try {
        response = (Response) pjp.proceed();
        // Do other stuff
    } catch (Throwable t) {}
    return response;
}

Question:

I need to pass @interface instance variable value to pointcut and the method but wasn't able to find anything on google.

here is what I have so far:

pointcut:

pointcut auditField(Object t, Object value): set(@ge.shemo.anotations.CaptureChanges * * ) && args(value) && target(t);

before (Object target, Object newValue, FieldChangeName fieldName): 
        auditField(target, newValue,fieldName) {
    FieldSignature sig = (FieldSignature) thisJoinPoint.getSignature();
    Field field = sig.getField();
    field.setAccessible(true);
    Object oldValue;
    try {
        oldValue = field.get(target);
    } catch (IllegalAccessException e) {
        throw new RuntimeException("Failed to create audit Action", e);
    }
    System.out.println("changed from " + oldValue + " to " + newValue);
}

and interface:

@Retention(RUNTIME)
@Target(value = FIELD)
public @interface CaptureChanges {
    MethodType fieldType();
}

UPDATED

public enum MethodType {
    NAME(FieldChangeType.STRING),
    ID(FieldChangeType.STRING),
    FIRST_NAME(FieldChangeType.STRING),
    LAST_NAME(FieldChangeType.STRING);

    private FieldChangeType type;

    private FieldChangeName(FieldChangeType type) {
        this.type = type;
    }

    public FieldChangeType getType() {
        return this.type;
    }
}
public enum FieldChangeType {
    ENUM, STRING
}

I want to get the value of 'FieldChangeMethod method' from @interface CaptureChanges and use it in before() function.

How can I do this?


Answer:

While it's unclear to me what you're trying to achieve with the MethodType and FieldChangeType classes, here's a way to access the value of the @CaptureChanges annotation when a field value is about to change:

pointcut auditField(Object t, Object value, CaptureChanges captureChanges): 
    set(* *) && @annotation(captureChanges) && args(value) && target(t);

before (Object target, Object newValue, CaptureChanges captureChanges): 
        auditField(target, newValue, captureChanges) {

    FieldSignature sig = (FieldSignature) thisJoinPoint.getSignature();
    Field field = sig.getField();
    field.setAccessible(true);
    Object oldValue;
    try {
        oldValue = field.get(target);
    } catch (IllegalAccessException e) {
        throw new RuntimeException("Failed to create audit Action", e);
    }
    System.out.println("changed from " + oldValue + " to " + newValue 
            + ", fieldType=" + captureChanges.fieldType()
            + ", fieldChangeType=" + captureChanges.fieldType().getType());
}

Question:

I want to write an aspect on a method pointcut, and in the aspect I want to call another method using the object on which pointcut method is called.

Something like this:

@Pointcut("@annotation(com.mypackage.Notify(getC))")
public void notifyPointCut() {
}

@AfterReturning(value = "notifyPointCut(getC)", argNames = "joinPoint") 
public void notifyChange (JoinPoint joinPoint) {
  Object targetObject  = joinPoint.getTarget();
  C cField = targetObject.invokeMethod("getC");
  notifier.sendUpdate(cField);
}

I want to get the object on which joinPoint method is called and make another method call on that object (method name that is passed in the annotation)

My use case is to get some fields of the object, these fields are created or updated by joinPoint method. Once joinPoint method returns, I want to get those fields in the aspect and send a notification on the field value.

I am not sure if I am complicating aspect usage too much as I could not find such a usage anywhere on searching.


Answer:

I figured out how to invoke the method. I need to get the method and invoke it, then I do not need to do casting for the class.

Object targetObject  = joinPoint.getTarget();
Method m = targetObject.getMethod("getC");
m.invoke(targetObject);

Question:

It is my first approaching to AOP. I've a spring-boot application with one Aspect, a Logger. Searching i reach to the conclusion that the @Around method executes before, and after the method (I'm calling it just in one method), is this right? And in the middle of my @Around method y have a joinPoint.proceed(). If I'm not wrong, the JoinPoint is the object i must use to obtain information of the method where the aspect is getting called but i can't understand what is the proceed actually doing!

This is my code:

@Around(value = "execution(* *(..)) && @annotation(Loggable)", argNames = "ProceedingJoinPoint, Loggable")
public Object logAround(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable {

    String methodArguments = loggable.printMethodArguments() ? Arrays.toString(joinPoint.getArgs()) : "[]";

    long start = System.currentTimeMillis();
    Object returnObject = joinPoint.proceed(); // continue on the
                                                // intercepted method
    long elapsedTime = System.currentTimeMillis() - start;

    String returnValue = loggable.printReturn() && returnObject != null ? returnObject.toString() : "[]";

    LOG.info("Logging method: {}.{} Method arguments: {}. Method return value: {}. Method execution time: {}",
            joinPoint.getTarget().getClass().getName(), joinPoint.getSignature().getName(), methodArguments,
            returnValue, elapsedTime);
    return returnObject;
}

Answer:

As you said, when you're using @Around it's just like you can do whatever you want before the method, then invoke the method, then you can do whatever you want after the method called.

//Read file, Log , .... (Before method calling)
//Invoke the method (joinPoint.proceed)
//Write to the file, complete log, .... (After method calling)

The invoking phase done by joinPoint.proceed().


Log Example

1- Log before calling method

2- Call or invoke the method you set pointcut on it (proceed)

3- Save the log into the database or write it to the file or send it ,...

Authorization Example

In this sample, using @Around, you can authorize users and determine that they can use the method or not?

So you need to do authorization process before the method invocation, if authorization is true then invoke method if not throws an exception or you can log.

1- Authorize user before calling method

2- If Authorization was true then invoke method (joinPoint.proceed();)


In summary, joinPoint.proceed(); means that you are calling the set method, or invoking it.

Question:

I have a Spring boot code with Aspectj. This code has written with basic MVC architecture. Then I just try to test it with MockMVC. But when I try to test it, Aspectj doesn't interrupted. Is there a special configuration about Aspectj?

Controller:

@GetMapping("user/{userId}/todo-list")
public ResponseEntity<?> getWaitingItems(@RequestUser CurrentUser currentUser){
    ...handle it with service method.
}

Aspect:

@Pointcut("execution(* *(.., @RequestUser (*), ..))")
void annotatedMethod()
{
}

@Before("annotatedMethod() && @annotation(requestUser)")
public void adviseAnnotatedMethods(JoinPoint joinPoint, RequestUser requestUser)
{
    ...
}

Test:

@WebMvcTest(value = {Controller.class, Aspect.class})
@ActiveProfiles("test")
@ContextConfiguration(classes = {Controller.class, Aspect.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class ControllerTest
{
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @Autowired
    private Controller controller;

    @MockBean
    private Service service;

    @Before
    public void setUp()
    {
        mockMvc = MockMvcBuilders
                .webAppContextSetup(webApplicationContext)
                .build();
    }

    @Test
    public void getWaitingItems() throws Exception
    {
        mockMvc.perform(get("/user/{userId}/todo-list", 1L))
                .andExpect(status().isOk());
    }
}

Answer:

Spring @WebMvcTest will only instantiate web layer and it will not load complete application context

However, in this test, Spring Boot instantiates only the web layer rather than the whole context.

In order to test Aspectj you need to load whole application context using @SpringBootTest annotation

The @SpringBootTest annotation tells Spring Boot to look for a main configuration class (one with @SpringBootApplication, for instance) and use that to start a Spring application context

So annotate the test using @SpringBootTest annotation

@SpringBootTest
@ActiveProfiles("test")
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
public class ControllerTest {

   @Autowired
   private MockMvc mockMvc;

   @Autowired
   private WebApplicationContext webApplicationContext;

   @Autowired
   private Controller controller;

   @Before
   public void setUp() {
    mockMvc = MockMvcBuilders
            .webAppContextSetup(webApplicationContext)
            .build();
      }

    @Test
    public void getWaitingItems() throws Exception  {
    mockMvc.perform(get("/user/{userId}/todo-list", 1L))
            .andExpect(status().isOk());
         }
    }

Question:

I have annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Retry {

    int DEFAULT_RETRIES = 2;

    int times() default DEFAULT_RETRIES;
}

Which is used either on class level:

@Retry(times = 5)
public class PersonServiceClass {

//...

    public void deletePerson(long id) {
        //...
    }
}

Or method level (another class, not PersonServiceClass):

@Retry
public void deletePerson(long id) {
    //...
}

The aspect is caught by such class:

@Aspect
@Component
public class RetryInterceptor {

    @Around("@within(retry) || @annotation(retry)")
    public Object around(ProceedingJoinPoint proceedingJoinPoint, Retry retry) throws Throwable {
        System.out.println("around - " + retry);
        System.out.println("joinpoint - " + proceedingJoinPoint);
        return aroundHandler(proceedingJoinPoint, retry);
    }

And aspect is correctly caught on method or class level, but there is something wrong with binding Retry annotation.

When @Around is as following: @Around("@within(retry) || @annotation(retry)") then:

  1. When caught on method level than retry is binded
  2. When caught on class level than retry is null.

When @Around is as following @Around("@annotation(retry) || @within(retry)") then:

  1. When caught on method level than retry is null.
  2. When caught on class level than retryis binded.

Spring Boot Parent Version - 2.1.1.RELEASE


Answer:

...now you challenged me:) and i could reproduce the issue!

Pragmatically I (would) solve(d) it like that:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class ExampleAspect {

  @Around("@within(retry)")
  public Object typeAspect(ProceedingJoinPoint joinPoint, Retry retry) throws Throwable {
    return commonAspect(joinPoint, retry);
  }

  @Around("@annotation(retry)")
  public Object methodAspect(ProceedingJoinPoint joinPoint, Retry retry) throws Throwable {
    return commonAspect(joinPoint, retry);
  }

  private Object commonAspect(ProceedingJoinPoint joinPoint, Retry retry) throws Throwable {
    System.out.println("Retry is :" + (retry == null ? "null" : retry.value()));
    // ... do your (common) stuff here
    return proceed;
  }

}

..welcome! :-)

And since you already have a (common) aroundHandler() method, it comes down to "introducing 2 public facades/PCDs for it".

Additional hint: Rename times() (if its the only/main property of that annotation) to: value()! ..then you can do "just" @Retry(100).

Question:

Probably a duplicate question of experts.hybris

We are using promotion module(deprecated one). OOTB if you have a product restriction and you have mix cart(having allowed and restricted products) then promotion(Say: order threshold promotion) will apply(calculate) on whole cart total. Ideally, restricted products price should be excluded from cart total to trigger promotion and this is what I want to achieve.

To do so I'm trying to override getOrderSubtotalAfterDiscounts using Spring AOP and its also getting called. But there, I need to get current promotion class instance (OrderPromotion) to call evaluateRestrictions of PromotionsManager. But it always getting null using (OrderPromotion) pjp.getTarget()

Aspects:

package com.myproject.aop;

@Aspect
public class AbstractOrderAOP
{

    private static final Logger LOG = Logger.getLogger(AbstractOrderAOP.class);


    @Pointcut("execution(public * *..OrderThresholdDiscountPercentagePromotion.evaluate(..)) && target(orderPromotion)")
    public void evaluatePointcut(OrderPromotion orderPromotion)
    {
        //
    }

    @Pointcut("execution(protected * de.hybris.platform.promotions.jalo.OrderPromotion.getOrderSubtotalAfterDiscounts(..)) && args(ctx, order)")
    public void subtotalPointcut(SessionContext ctx, AbstractOrder order)
    {
        //
    }

    @SuppressWarnings("boxing")
    @Around("evaluatePointcut(orderPromotion) && cflow(subtotalPointcut(ctx, order))")
    public Object getOrderSubtotalAfterDiscounts(ProceedingJoinPoint pjp, OrderPromotion orderPromotion, SessionContext ctx,
            AbstractOrder order)
    {
        LOG.info("here you go ....");
        return 0l;
    }
}

aop.xml

<aspectj>
    <weaver options="-Xset:weaveJavaxPackages=true">
        <include within="de.hybris.platform.promotions.jalo.OrderPromotion"/>
        <include within="de.hybris.platform.b2bacceleratorservices.jalo.promotions.OrderThresholdDiscountPercentagePromotion"/>
        <include within="com.myproject.extended.interceptor.*"/>
    </weaver>
    <aspects>
        <aspect name="com.myproject.aop.AbstractOrderAOP"/>
    </aspects>
</aspectj>

Any help or suggestions would be appreciated!!


Answer:

Your aspect does not import de.hybris.platform.promotions.jalo.OrderPromotion and is not in the same package. So I really wonder why it should even compile with the cast to OrderPromotion you are trying to use.

If you do have the import in your aspect and just erased it before copying it into your SO question, I see no reason why pjp.getTarget() should yield null, with one exception: If the method is static, then of course it would not have a target object to be called upon because there is not object instance. In this case your aspect cannot work and you need to intercept another pointcut.

As Hybris does not seem to have any public JavaDoc on the web and I have never used it and thus no access to it, I cannot say for sure, I have to speculate.


Update: Okay, I am back from my trip and have a little time to answer. Basically the idea is to get

  • the target from the calling instance method and
  • the arguments from the static method.

In order to achieve that you use the cflow() pointcut by which you can express that the static method's execution should be captured if it is in the control flow (i.e. directly or indirectly called by) the instance method which gets you the target object. You should

  • pull out the two method executions into two separate pointcuts,
  • then use args() and target() in order to bind the captured values directly to pointcut parameters
  • and then combine the pointcuts and all parameters in your advice method:
@Aspect
public class AbstractOrderAOP {

  // (...)

  @Pointcut(
    "execution(public * *..OrderThresholdDiscountPercentagePromotion.evaluate(..)) && " +
    "target(orderPromotion)"
  )
  public void evaluatePointcut(OrderPromotion orderPromotion) {}

  @Pointcut(
    "execution(protected * *..OrderPromotion.getOrderSubtotalAfterDiscounts(..)) && " +
    "args(ctx, order)"
  )
  public void subtotalPointcut(SessionContext ctx, AbstractOrder order) {}

  @Around("cflow(evaluatePointcut(orderPromotion)) && subtotalPointcut(ctx, order)")
  public Object getOrderSubtotalAfterDiscounts(
    ProceedingJoinPoint pjp,
    OrderPromotion orderPromotion,
    SessionContext ctx,
    AbstractOrder order
  ) {

    LOG.info("############ AbstractOrderAOP is being evaluated ############");
    try {
      final Object output = pjp.proceed();
    } catch (Throwable e) {
      e.printStackTrace();
    }

    ArrayList products = new ArrayList();

    // (...)

    return 0l;
  }

  // (...)
}

See? No more ugly getTarget() or getArgs()[0], but perfectly typesafe parameter binding.

BTW, you do not need to abbreviate the package names to *.. like I did. I just wanted to make it a bit more readable for you and other people around here.

This works and I have tested that it does by replicating all your dozen or so classed as dummies (too much code to post here).

Question:

I'm having some issues with AspectJ implementation! I want to make a log method for methods with the @MyAnnotation annotation.

MyAnnotation.java :

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation{ }

MyAspect.java :

@Aspect
public class MyAspect {
    private static Logger logger = Logger.getLogger(MyAspect.class.getName());

    @Pointcut("@annotation(com.utils.aop.annotations.MyAnnotation)")
    public void logMyAspect() {
    }
    @Before("logMyAspect()")
    public void logMethod(JoinPoint jp) {
        String methodName = jp.getSignature().getName();
        logger.info("Executing method: " + methodName);
    }
}

I'm using my @MyAnnotation before some of the service method of my project:

    @RolesAllowed({ "DEV", "GUI", "API" })
    @POST
    @Path("/getList")
    @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
    @MyAnnotation
    public Response getList(@Context final ContainerRequestContext requestContext,  
            FilterAndSortObject filterAndSortObject, 
            @QueryParam("offset") final int offset,
            @QueryParam("limit") final int limit)
    {
             ...
    }

I've also seen that I should use @EnableAspectJAutoProxy in my configuration class :

@Configuration
@EnableAspectJAutoProxy
public class ServletContextClass implements ServletContextListener {
    final static Logger logger = Logger.getLogger(ServletContextClass.class);
    @Override
    public void contextInitialized(final ServletContextEvent sce) {
    ...
    }
...
}

However it doesn't seem to work. It doesn't log anything! I used a breakpoint in the logMethod(JoinPoint jp) as well checking the result, without any success!

Does anyone have any idea why this doesn't work?


Answer:

You don't have to separate the pointcut and the handler method; in fact, I'm sure this is what causes your issue. The following aspect should work just fine:

@Aspect
public class MyAspect {
    private static Logger logger = Logger.getLogger(MyAspect.class.getName());
    @Before("@annotation(com.utils.aop.annotations.MyAnnotation)")
    public void logMyAspect(JoinPoint jp) {
        String methodName = jp.getSignature().getName();
        logger.info("Executing method: " + methodName);
    }
}

You can also inspect your annotation values, in case it takes parameters:

@Before("@annotation(a)")
public void logMyAspect(JoinPoint jp, MyAnnotation a) {
    // conditional logging based on annotation contents
}

Question:

I have a Spring project managed by Maven. Instead of using execution pointcut designator like the following:

@Before("execution(* my.app.TestUtil.myStaticClass(..))")
public void logBeforeTestUtil(JoinPoint joinPoint) {
    System.out.println("*** hijacked : " + joinPoint.getSignature().getName());
}

I want to use call pointcut designator like:

@Before("call(* my.app.TestUtil.myStaticClass(..))")
public void logBeforeTestUtil(JoinPoint joinPoint) {
    System.out.println("*** hijacked : " + joinPoint.getSignature().getName());
}

However, my IDE (IntelliJ) tells me call pointcut designator isn't supported by Spring, even after I removed spring-aop in the pom.xml.

I'd like to mention the example above with execution pointcut designator is working and Spring AOP does not supports all AspectJ pointcut designators.

This answer shows how to use Load Time Weaving without using Spring. I am wondering if we can use Spring + AspectJ without Spring AOP. If so, how to do it?

EDIT: add pom.xml and context configuration files

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>my.app</groupId>
    <artifactId>myapp</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <spring.version>4.3.4.RELEASE</spring.version>
        <jackson.version>2.7.3</jackson.version>
        <aspectj.version>1.8.4</aspectj.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <aspectj.version>1.8.4</aspectj.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--<dependency>-->
            <!--<groupId>org.springframework</groupId>-->
            <!--<artifactId>spring-aop</artifactId>-->
            <!--<version>${spring.version}</version>-->
        <!--</dependency>-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-instrument</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
</project>

application-context.xml

package my.app;

import org.springframework.context.annotation.*;

@Configuration
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
public class AppConfig {
}

META-INF/aop.xml

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
    <weaver>
        <include within="my.app.utils.*"/>
        <include within="my.app.aspect.*"/>
    </weaver>
    <aspects>
        <aspect name="my.app.aspect.LoggingAspect" />
    </aspects>
</aspectj>

Answer:

For execution the called code must be advised. For call the calling code must be advised. Is the calling code within the scope of my.app.utils.* or my.app.aspect.*? Those are the only packages you configured your weaver to include. If the caller is from org.springframework... or other parts of your application, it will not be advised.

Converted to answer from previous comment.

Question:

I'm trying to understand AspectJ. I want to try to count all object initializations (which are initialized from the classes I've specified, not some Java-internal ones) in a project and I'm really not sure how to do this.

Let's say I have classes called A and B, where A has subclasses Aa and Ab, B has the subclasses Ba and Bb, and Bb has the subclass Bba. I'd like my aspect to track every single initialization of the objects created with those classes as a base, but I don't really understand how to properly do this (even though this should be somewhat simple). So far, I have something similar to this:

public aspect AspectCounter {
        private int objects = 0;

        pointcut countObjects() : initialization(A.new(..)) || initialization(B.new(..));

        pointcut printObjects() : call(* Test.printCounter(..));

        after() : countObjects() {
            objects++;
        }

        after() : printObjects() {
            System.out.println(objects);
        }
}

Which does, at least, print the right amount of A's and B's I've created (I didn't go with B*.new(..) since it would, the way I understand it, track any initialization of Bba three times which I don't want in this case). The way it works right now is that I have a Test class which, well, does test stuff, and after I'm done with the testing, I'm just calling an empty printCounter method that doesn't really do anything. It seems to work and does actually give me the right number of objects, but I'm sure there's a better way to do this. I really don't like having an empty method.


Answer:

You cannot do this with initialization, preinitialization or execution pointcuts on *.new(..) because of the order in which they are executed. They are not nested as you might think but executed rather sequentially due to the way the JVM works. I have explained this in detail here including sample code and log output. So you are only left with the option to use a call pointcut. Here is an example:

package de.scrum_master.app;

public class A {}
package de.scrum_master.app;

public class Aa extends A {}
package de.scrum_master.app;

public class Ab extends A {}
package de.scrum_master.app;

public class B {}
package de.scrum_master.app;

public class Ba extends B {}
package de.scrum_master.app;

public class Bb extends B {}
package de.scrum_master.app;

public class Bba extends Bb {}

Driver application:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        new A();
        new Aa();
        new Ab();
        new B();
        new Ba();
        new Bb();
        new Bba();
    }
}

Aspect:

package de.scrum_master.aspect;

import de.scrum_master.app.A;
import de.scrum_master.app.B;

public aspect InstanceCreationCounter {
    private static int count;

    after() : call(A+.new(..)) || call(B+.new(..)) {
        System.out.printf("%4d %s%n", ++count, thisJoinPoint);
    }
}

Console log:

   1 call(de.scrum_master.app.A())
   2 call(de.scrum_master.app.Aa())
   3 call(de.scrum_master.app.Ab())
   4 call(de.scrum_master.app.B())
   5 call(de.scrum_master.app.Ba())
   6 call(de.scrum_master.app.Bb())
   7 call(de.scrum_master.app.Bba())

I guess this is what you want.

Caveat: You need to have control over all the calling code and weave the aspect into it in order for this to work.

Question:

The method below should be invoked when my system throws an exception, but it isn't. It only works when I remove the 'throwing' from the annotation and the 'Exception' as parameter:

Doesn't work:

@AfterThrowing(pointcut="execution(public * br.com.ogfi.*.controller.*.*(..))", throwing="e")
public void afterThrowing(Exception e) {
    System.out.println("Test");
}

Works:

@AfterThrowing(pointcut="execution(public * br.com.ogfi.*.controller.*.*(..))")
public void afterThrowing() {
    System.out.println("Test");
}

Does anyone knows what i'm doing wrong?

This is the entire class:

package br.com.ogfi.portalbackoffice.aspect;

import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AfterThrowAdvice {


    @AfterThrowing(pointcut="execution(public * br.com.ogfi.*.controller.*.*(..))", throwing="e")
    public void afterThrowing(Exception e) {
        System.out.println("Boo! We want our money back!");
        //ex.printStackTrace();
        //System.out.println("Boo! We want our money back!");

    }

}

Answer:

Finaly i've found the reason it wasn't working:

The java project i'm working with has his own exception called SystemException, the same name of javax.transaction.SystemException and i haven't realized it wasn't from javax.

The SystemException from my project extends Throwable and when I tried to use Exception as parameter, my method wasn't called because wasn't the same thing.

Question:

I'm new to AOP with AspectJ and I need to write the following simple aspect:

I have the @EndDay:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface EndDay { }

annotation and I need to intercept all non-reflective assignation to all non-static fields of the type Date annotated with @EndDate annotation and then assign the value of the end of the day specified in the assigned Date object (e.g we're assigngn 2011-11-11 10:00:00, it's intercepted and assigned 2011-11-11 23:59:59 instead). What I have tried:

public aspect EndDay {
    before(): set(@DayEnd private Date *) {
        Date d = (Date) thisJoinPoint.getTarget();
        DateUtils.setDayEnd(d); //It an utility class modifying the date
    };
}

It didn't work properly. How can I fix that?


Answer:

To change the value being assigned to a field we need to use the around advice, instead of before or after. The around advice specifies that we will perform some operations instead of ones being performed normally. Now, as the documentation says:

All set join points are treated as having one argument, the value the field is being set to, so at a set join point, that value can be accessed with an args pointcut.

That means we should have declared our advice for the conjucntion of the set(@DayEnd private Date *) and args(original). The first one picks out all the private fields assignments, but the second one specifying the value being assigned. Now, in order to assign the moified value we finally need to call proceed(_modified_argument).

The working aspect looks as follows:

public aspect DayBoundaries {

   void around(Date original): set(@DayEnd private Date *) && args(original){
        Calendar c = Calendar.getInstance();
        c.setTime(original);
        c.set(Calendar.HOUR_OF_DAY, 23);
        c.set(Calendar.MINUTE, 59);
        c.set(Calendar.SECOND, 59);
        c.set(Calendar.MILLISECOND, 999);
        proceed(c.getTime());
    };
}

Question:

The source code for the project I work on is managed within eclipse but the .class and .war files we actually use and ship are built using ant via a build.xml file. The code works in a Spring environment and uses AspectJ to do some compile-time weaving. We've been working with AspectJ 1.6 and Java 1.6 for several years, but we are now in the process of trying to move to using Java 1.8 (a jboss environment which we've been installing within has been using Java 1.6 but is being moved to 1.8; plus we are also working to decouple our application from the other application so we can run standalone inside a jetty container where we provide Java 1.8), but there seems to be a problem between the use of AspectJ and Java 1.8. I've found a number of posts which seem to be related to the issue we're seeing, though I've not found any of them to provide a simple solution that seems to match our particular build situation (those that do have potential solutions at all always refer to something like maven or other things which we are not using).

Here's the error output we see when trying to compile using Open JDK 8 from Zulu (8u31 for Windows):

 [iajc] C:\GitRepos\NSE_decouple\client\src\com\hp\nonstop\nse\test\cli\sort\PhysicalTargetListByName.java:5 [error] Comparator cannot be resolved to a type
 [iajc] public class PhysicalTargetListByName implements Comparator<String>
 [iajc]                                                  ^^^^^^^^^
 [iajc] C:\GitRepos\NSE_decouple\client\src\com\hp\nonstop\nse\test\cli\sort\PhysicalTargetListByName.java:5 [error] The type java.util.Comparator cannot be resolved. It is indirectly referenced from required .class files
 [iajc] public class PhysicalTargetListByName implements Comparator<String>

The particular code in question referenced in this error (I suspect other code would be failing as well, but this failure seems to stop the compile) is:

public class PhysicalTargetListByName implements Comparator<String>
{
<code not included; the declaration itself seems to be the failure point>
}

In case the problem was related to using aspectj1.6, I installed the latest version of AspectJ as well, which is AspectJ 1.8.5, but that made no difference.

Things build OK within eclipse itself, but we get the errors when trying to build using ant, with JAVA_HOME set to "c:\Program Files\Zulu\zulu-8" and IAJC_HOME set to "c:\aspectj1.8" before doing "ant build" at the command line. Within the build.xml file, we have the following step inside a build target task to perform the iajc compile:

 <iajc destdir="${build.dir}" failonerror="true" 
     showWeaveInfo="${showWeaveInfo.isEnabled}" source="1.6" target="1.6"  
     debug="true"  fork="true"  maxmem="256m">
    <src path="${instsrc.dir}" />
    <exclude name="**/junit/*"/>
    <exclude name="**/install/*"/>
    <classpath refid="master-classpath"/>
    <aspectPath refid="aspectPath"/>
 </iajc>

I've also tried this with both source and target set to "1.8" as well but that makes no difference either.

The build.xml file also contains:

<path id="aspectPath">
   <pathelement location="${lib.dir}/spring-aspects.jar"/>
</path>

and

<path id="master-classpath">
    <fileset dir="${lib.dir}">
        <include name="*.jar"/>
    </fileset>
    <fileset dir="${jetty.dir}/lib">
        <include name="servlet-api-3.0.jar"/>
        <include name="jetty-servlet-8.1.16.v20140903.jar"/>
        <include name="jetty-util-8.1.16.v20140903.jar"/>
    </fileset>
    <fileset dir="${jetty.dir}/lib/jsp">
        <include name="javax.servlet.jsp-2.2.0.v201112011158.jar"/>
    </fileset>
    <pathelement location="${clover.jar}"/>
    <pathelement path="${build.dir}"/>
</path>

An experiment where I replaced the <iajc> task with a <javac> task instead allowed the build to work without the error (though the code produced would not have been woven) so it does appear that the error is related to the mixture of AspectJ with java 1.8 (another experiment shows that we can build without the error when using Open JDK 7 and AspectJ).

And help pointing to what we might need to do to get AspectJ to work with Java 1.8 builds would be greatly appreciated!


Answer:

After some poking around, and a little bit of serendipity, I finally managed to find what was keeping the fixes I'd tried up to that point from solving the problem.

It came down to the existence of a copy of aspectjtools.jar within my %ANT_HOME%\lib folder. This JAR had been placed there many, many (many!) years ago. It happened to be the AspectJ 1.6 version of the JAR and its existance there caused ant to use that version even though our build.xml file had been modified at some point to specify the path to AspectJ so an existence of the JAR under the ant lib was not needed to determine the version to use(and which I'd recently changed to point at AspectJ 1.8 instead, though the presense of the file made my change to build.xml ignored). Even though I thought I was now using AJ 1.8 with Java 1.8, I was not, so all the fundamental problems of incompatibility between older AJ and Java 1.8 remained.

Once I removed that JAR from the ant lib folder, my ant builds worked as expected without errors!

So the fix was to remove a file which wasn't needed, but which hadn't caused a noticeable problem up to that point, since we'd been using AJ 1.6 for many years previously. The update to the newer version didn't really take effect because of the stray file's existence. No file ==> build.xml config takes effect ==> compile works!

Question:

I tryed to do aspectj-based security for controllers, but when i try to use my annotation - it's does not work. but when i try to annotate deeper service methods - all works perfectly.

Controller Class

@Controller
public class HomeController {

    @Autowired
    private AccountService accountService;

    @Loggable
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String index(Principal principal, HttpSession session) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (!(authentication instanceof AnonymousAuthenticationToken)) {
            String email = authentication.getName();
            Account acc = accountService.findByEmail(email);
            session.setAttribute("user", acc);
        }
        return principal != null ? accountService.findByEmail(principal.getName()).getRole().equalsIgnoreCase("ROLE_ADMIN") ? "/home/adminSignedIn" : "home/homeSignedIn" : "home/homeNotSignedIn";
    }

Annotation

@Target(value = {ElementType.METHOD, ElementType.TYPE})
 @Retention(value=RUNTIME)
// @Documented
//@Documented
@Component
public @interface Loggable {

}

Aspect class

@Aspect
@Component
public class Logger {

Logger logger = LoggerFactory.getLogger("test");

    @Around("@annotation(com.proj.server.aspect.log.Loggable)")
    public Object traceMethod(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        String methodName = signature.getDeclaringTypeName() + "#" + method.getName();
        logger.info("START : " + methodName);
        Object o = pjp.proceed();
        logger.info("END : " );
        return o;
    }
}

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>com.proj.web</groupId>
    <artifactId>proj</artifactId>
    <packaging>war</packaging>
    <version>version</version>
    <name>proj</name>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>${project.build.sourceEncoding}</project.reporting.outputEncoding>
        <java-version>1.7</java-version>
        <org.aspectj-version>1.7.4</org.aspectj-version>
        <org.slf4j-version>1.7.5</org.slf4j-version>
        <ch.qos.logback-version>1.0.13</ch.qos.logback-version>
        <org.thymeleaf-version>2.1.3.RELEASE</org.thymeleaf-version>
        <org.thymeleaf.extras.springsecurity3-version>2.1.1.RELEASE</org.thymeleaf.extras.springsecurity3-version>
    </properties>
    <repositories>
        <repository>
            <id>java.net2</id>
            <name>Repository hosting the jee6 artifacts</name>
            <url>http://download.java.net/maven/2</url>
        </repository>
        <repository>
            <id>sonatype-oss-repository</id>
            <url>https://oss.sonatype.org/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>repository.spring.milestone</id>
            <name>Spring Milestone Repository</name>
            <url>http://repo.spring.io/milestone</url>
        </repository>
    </repositories>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-framework-bom</artifactId>
                <version>4.0.3.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-bom</artifactId>
                <version>4.0.0.M2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!-- Spring -->
        <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
        </dependency>
        <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <version>3.1</version>
        </dependency>
        <dependency>
                <groupId>aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>1.5.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>

            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>
        <!-- Security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
        </dependency>
        <!-- View -->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>${org.thymeleaf-version}</version>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring4</artifactId>
            <version>${org.thymeleaf-version}</version>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity3</artifactId>
            <version>${org.thymeleaf.extras.springsecurity3-version}</version>
        </dependency>
        <!-- Persistence -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.1-901-1.jdbc4</version>
        </dependency>
        <!-- Spring Data -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.4.1.RELEASE</version>
        </dependency>
        <!-- javax.validation (JSR-303) -->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.0.0.GA</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.3.0.Final</version>
        </dependency>
        <!-- AspectJ -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${org.aspectj-version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.4</version>
        </dependency>
        <!-- Logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${org.slf4j-version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>${org.slf4j-version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${ch.qos.logback-version}</version>
        </dependency>
        <!-- @Inject -->
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
        <!-- Servlet -->
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-servlet_3.0_spec</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- JSON -->
        <dependency>
            <groupId>org.codehaus.jackson</groupId>
            <artifactId>jackson-mapper-asl</artifactId>
            <version>1.9.9</version>
        </dependency>
        <!-- Utilities -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>14.0.1</version>
        </dependency>
        <!-- Test -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
            <version>1.7.0</version>
            <scope>test</scope>
        </dependency>

    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>${java-version}</source>
                    <target>${java-version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <warName>test-version</warName>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.17</version>
                <configuration>
                    <excludes>
                        <exclude>${systest.package}</exclude>
                        <exclude>**/*$*</exclude>
                        <exclude>**/*Test*.java</exclude>
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>deploy</id>
                        <phase>deploy</phase>
                        <goals>
                            <goal>sources</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.5</version>
                <configuration>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>test-all</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <version>2.17</version>
                        <configuration>
                            <includes>
                                <include>**/WebSuite*</include>

                            </includes>
                            <excludes>
                                <exclude>${systest.package}</exclude>
                                <exclude>**/*$*</exclude>
                                <exclude>**/*Test*.java</exclude>
                            </excludes>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

</project>

@EnableAspectJAutoProxy(proxyTargetClass = true)

in appconfig.class


Answer:

here is problem with different contexts. i have @EnableAspectJAutoProxy(proxyTargetClass = true) in appconfig.class . all get work after i add something like that in security and mvc contexts.

Question:

I'm beggining my journey with Spring, trying to use AspectJ in Spring 3.2. Im following book Spring in Action. Author uses AspectJ by importing aspectJ packages this way:

import org.aspectj.lang.annotation.Aspect

However using that leaves me with

package org.aspectj.lang.annotation does not exist

I tried importing aspectj.jar (version 1.8.4) to my libraries in NetBeans, without any effect. I have the jar just bellow dozen of SPRING FRAMEWORK 3.2.3 RELEASE xxxxxx's. It still does not find the package. What could cause this issue? Here's the beggining of my beans.xml

    <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
" xmlns:util="http://www.springframework.org/schema/util">

    <context:component-scan base-package="heyspring">

    </context:component-scan>

    <aop:aspectj-autoproxy>

Answer:

I suggest you move to Maven

Even if you want to work without Maven, read the following note carefully.

Note: even in Maven Central Repository you are able to download the jars required according with my dependencies shared below

Be totally sure you have the following in your pom.xml or equivalent jars files:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${springframework.version}</version>
</dependency>

The following is mandatory

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${aspectj.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${aspectj.version}</version>
</dependency>

Of course you must set or configure each version, for Spring and AOP.

I have these three dependencies and work fine in my projects.

Question:

I have a marker interface which has several implementations. My intention is to add an aspect for all public methods defined in any class implementing that marker interface. I defined my aspect as follows:

@Around("within(x.y.z.MyInterface+) && execution(public * *(..))")

The problem is that this also catches inner classes, for example consider this method in one of the classes implementing that interface:

public void foo() {
  doSomething(new Request() {
    @Override
    public void do() {
      System.out.println("Hi");
    }
  });
}

For some reason, the aspect also catches that "do()" method, even though it is does not inherit from MyInterface.

How should I fix my aspect definition?


Answer:

Instead of "within" use the "this" pointcut:

@Around("this(x.y.z.MyInterface+) && execution(public * *(..))")

Basically "this" matches joinpoints where this, the current object reference at the time, is an instance of MyInterface. Anonymous classes not implementing your interface will no longer match.

JavaWorld has a nice article on it: http://www.javaworld.com/article/2074048/core-java/i-want-my-aop---part-2.html?page=2

Question:

I tried pointcut expression for a specific package like com.abc.def.controller, com.abc.def.service.serviceImpl, etc in @Around advice as:

@Around("execution(* com.abc.def.controller..*.*(..))")
@Around("execution(* com.abc.def.service.*Impl.*(..))")

I also need to match methods in different packages like com.abc.xyz.controller, com.abc.xyz.service.serviceImpl and tried many pointcut expressions but didn't worked.

Any help will be appreciated. :)


Answer:

How about this?

@Around("execution(* com.abc..controller..*(..))")
@Around("execution(* com.abc..service.*Impl.*(..))")

You can also match both at once like this:

@Around(
    "execution(* com.abc..controller..*(..)) || " + 
    "execution(* com.abc..service.*Impl.*(..))"
)

Other variants are possible, depending on what exactly you want to achieve. Feel free to ask related follow-up questions.

Question:

I am trying to play with AspectJ and run time weaving. I have created an aspect

  @Aspect(value = "TraceAspect")
public class TraceAspect {
   @Around("execution(* *(..))")
   public Object around(ProceedingJoinPoint invocation) throws Throwable{

     System.out.println(String.format("Invocing %s", invocation.getSignature().getName()));
     try {
      Object ret = invocation.proceed();
      System.out.println(String.format("Done Invocing %s", invocation.getSignature().getName()));
      return ret;
     } catch (Throwable throwable) {
       throw throwable;

     }

   }
}

and my aop.xml file is

<aspectj>
<aspects>
    <aspect name="TraceAscpect"></aspect>
</aspects>
<weaver options="-debug -showWeaveInfo"/>

however when I run the program I get exception -

 java.lang.RuntimeException: Cannot register non aspect: TraceAscpect , TraceAscpect

What did I forget to add?


Answer:

Looks like you have spelt the name of your aspect wrong in your XML definition, it should be TraceAspect and you've put TraceAscpect.

Question:

Recently upgraded a large project from Java 11 to 13. I am using AspectJ for logging purposes and I am now getting this error on startup :

AspectJ Internal Error: unable to add stackmap attributes. Unsupported class file major version 57

Looks clear as day that Java 13 is not supported and looking at the AspectJ site they mention Java 12 support added in version 1.9.3 but as of the latest one, 1.9.4, still no mention of Java 13 support.

Any idea if there is a way around this or if the project will be updated again soon? The last release was in May...

UPDATE

As requested, here are my dependency declarations :

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-instrument</artifactId>
    </dependency>

And here are my Java Agent declarations :

-javaagent:lib/aspectjweaver-1.9.4.jar -javaagent:lib/spring-instrument-5.2.0.RELEASE.jar

Thanks


Answer:

AspectJ 1.9.5 just dropped with official Java 13 support. Spring Boot 2.2.1 still has the 1.9.4 dependency (will probably be updated in 2.2.2) so for now you have to specify an override version in the POM.xml file :

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version><!--$NO-MVN-MAN-VER$-->
</dependency>

Question:

I'm using AspectJ and I trying to Pointcut on @Component annotation.

@Pointcut("@annotation(org.springframework.stereotype.Component)")
   public void bean() {
}

@Before("bean()")
public void beforeBeanCreation(JoinPoint jp) {
    System.out.println("Works!");
}

My configuration looks like below:

@Configuration
@ComponentScan({"com.app.pl"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
@EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED)
public class AppConfiguration{

}

Everything works when I want to pointcut on annotation with ElementType.METHOD, or on a bean with specific name. But Pointcut on annotation with ElementType.TYPE dosen't work. I speculate that is a problem related with annotations that they are readed earlier then AspectJ proxy stand up.

Any idea how to solve this?


Answer:

Probably you are not using AspectJ but Spring AOP. So there are a few things to consider:

  • Usually Spring AOP aspects work on @Components anyway, not on non-Spring stuff. For that you would really need AspectJ. So in a way your Spring AOP aspects look for that annotation anyway.
  • Spring AOP aspects should be @Components too, but are excluded from aspect weaving automatically. In AspectJ you would need special precautions to exclude one aspect weaving another one bearing the same annotation as normal application code. You would need to consider that in situations where you combine Spring AOP with full AspectJ.

Now as for your AOP question, you cannot intercept joinpoints in an annotated class via @annotation() pointcut, as you already noticed. You need to use @within() instead, e.g.:

@within(org.springframework.stereotype.Component)

Please note that this will intercept all joinpoints in annotated classes, i.e. in the case of Spring AOP all method executions. It will not intercept bean creation, if as your log message suggests that is your goal.

Question:

Here is an example of how you can define an aspect using annotations:

@Aspect
public class BlaBla() {
    @Pointcut(...)
    ...

    @Before(...)
    ...

    @After(...)
    ...
}

This is the only way that I found through research. However I want class BlaBla to not be polluted with annotations and pointcut methods. I want it to remain a POJO. If I were to use xml spring configuration, I could do it easily:

<bean id="blaBla" class="BlaBla">...</bean>

<aop:config>
    <aop:aspect ref="blaBla">
        <aop:pointcut .../>
        <aop:before .../>
        <aop:after .../>
    </aop:aspect>
</aop:config>

However, I am not using xml configuration, but a Java configuration instead. Basically question is, how can I say to spring that class BlaBla is an aspect without changing BlaBla class itself, but instead to define it inside a java class annotated with @Configuration spring annotation.


Answer:

You need to make another class BlaBlaAopConfig or something like that which will be your configuration class.

Java config is not different from xml, you need to define it and you should do it seperate from your code. Only difference you get, while using java config over xml is better (or worse depending on personal preferences) clarity. But you never want to mix aop and pojo code in one class.

You will define in @Pointcut your target class BlaBla

Question:

I am working on a logging aspect which need to intercept all the classes and methods annotated with a custom annotation.

Below is custom annotation class which can be annotated on class and methods:

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Loggable {
    LogLevel value();
}

I am using these pointcut expressions to intercept methods and classes with annotation @Loggable, which is working for all the simple classes but does not work for classses which extend or implement.

//Works for annotation @Loggable on class level
@Pointcut("execution(* *(..)) &&  within(@com.logger.Loggable *)")
public void classAnnotationLogger() {
}

//Working for methods annotated with @Loggable
@Before(value = "@annotation(loggable)", argNames = "jp, loggable")
public void logBeforeAdvice(JoinPoint jp, Loggable loggable) {
  ..
  ..
}

Below is code for super class

@Component
@Loggable(LogLevel.INFO)
public abstract class Processor{
  public void process(){
      readProcess();
  }

  public abstract void readProcess();
}

Below is code for subclass

@Service
@Loggable(LogLevel.INFO)
public class MyServiceProcessor extends Processor {

  @Override
  public void readProcess(){
    ...
    ...
  }
}

In the application readProcess() is called by doing

Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();

Even though I have @Loggable on Processor and MyServiceProcessor, when readProcess is called the advice is not being invoked.

But advice is invoked for process() and not readProcess.

How do I write the pointcut expression which also intercepts the call to any subclass methods, when annotation @Logabble is applied on any class or method?


Answer:

Well, first of all this

@Pointcut("execution(* *(..)) &&  within(@com.logger.Loggable *)")
public void classAnnotationLogger() {}

is just a pointcut and not an advice, so it does not do anything unless you also have an advice actually using this pointcut. You have not posted such an advice, so I can only speculate.

Secondly, you have not provided any sample code which would be triggered by

@Before(value = "@annotation(loggable)", argNames = "jp, loggable")
public void logBeforeAdvice(JoinPoint jp, Loggable loggable) {}

at all, i.e. no annotated method. Your sample code only shows annotated classes.

As for the @Loggable annotation on the subclass, it should not be necessary because its base class already carries the same annotation and the annotation is @Inherited. This works for annotations on classes, but not for annotations on methods or interfaces, see my other answer for an explanation and a possible workaround.

This example of yours should actually work, I cannot see a reason why it would not:

Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();

But this internal call to readProcess() (equivalent to this.readProcess()) will not work:

public void process() {
    readProcess();
}

This is because Spring AOP is a proxy-based "AOP lite" framework relying on JDK dynamic proxies (for interfaces) or CGLIB proxies (for classes). But calls to this.someMethod() are not routed through proxies of any type so they cannot be intercepted by Spring aspects. This is documented behaviour. If you want to overcome this limitation and apply aspects to internal method calls as well, please use full-blown AspectJ as documented here.

Question:

I am interested in how to use Feign client in AOP. For example:

API:

public interface LoanClient {
    @RequestLine("GET /loans/{loanId}")
    @MeteredRemoteCall("loans")
    Loan getLoan(@Param("loanId") Long loanId);
}

Config:

@Aspect
@Component // Spring Component annotation
public class MetricAspect {

    @Around(value = "@annotation(annotation)", argNames = "joinPoint, annotation")
    public Object meterRemoteCall(ProceedingJoinPoint joinPoint, 
                        MeteredRemoteCall annotation) throws Throwable {
    // do something
  }
}

But I do not know how to "intercept" the api method call. Where did I go wrong?

UPDATE:

My Spring class annotation:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MeteredRemoteCall {

    String serviceName();
}

Answer:

Your situation is somewhat complex because you have several problems:

  • You use Spring AOP, an "AOP lite" framework based on dynamic proxies (JDK proxies for interfaces, CGLIB proxies for classes). It only works for Spring beans/components, but from what I see your LoanClient is not a Spring @Component.
  • Even if it was a Spring component, Feign creates its own JDK dynamic proxies via reflection. They are outside the control of Spring. Probably there is a way to wire them into Spring manually, either programmatically or via XML configuration. But there I cannot help you because I do not use Spring.
  • Spring AOP only supports a subset of AspectJ pointcuts. Specifically, it does not support call() but only execution(). I.e. it only weaves into the place where a method is executed, not the place where it is called.
  • But the execution takes place in a method implementing an interface and annotations on interface methods such as your @MeteredRemoteCall are never inherited by their implementing classes. In fact, method annotations are never inherited in Java, only class-level annotations from class (not interface!) to respective subclass. I.e. even if your annotation class had an @Inherited meta annotation, it would not help for @Target({ElementType.METHOD}), only for @Target({ElementType.TYPE}). Update: Because I have answered this question several times before, I have just documented the problem and also a workaround in Emulate annotation inheritance for interfaces and methods with AspectJ.

So what can you do? The best option would be to use full AspectJ via LTW (load-time weaving) from within your Spring application. This enables you to use a call() pointcut instead of execution() which is implicitly used by Spring AOP. If you use @annotation() pointcuts on methods in AspectJ, it will match both calls and executions, as I will show you in a stand-alone example (no Spring, but the effect is the same as AspectJ with LTW in Spring):

Marker annotation:

package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MeteredRemoteCall {}

Feign client:

This sample client grabs full StackOverflow question pages (HTML source code) as strings.

package de.scrum_master.app;

import feign.Param;
import feign.RequestLine;

public interface StackOverflowClient {
    @RequestLine("GET /questions/{questionId}")
    @MeteredRemoteCall
    String getQuestionPage(@Param("questionId") Long questionId);
}

Driver application:

This application uses the Feign client interface in three different ways for demonstration purposes:

  1. Without Feign, manual instantiation via anonymous subclass
  2. Like #1, but this time with an extra marker annotation added to the implementing method
  3. Canonical usage via Feign
package de.scrum_master.app;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import feign.Feign;
import feign.codec.StringDecoder;

public class Application {
    public static void main(String[] args) {
        StackOverflowClient soClient;
        long questionId = 41856687L;

        soClient = new StackOverflowClient() {
            @Override
            public String getQuestionPage(Long loanId) {
                return "StackOverflowClient without Feign";
            }
        };
        System.out.println("  " + soClient.getQuestionPage(questionId));

        soClient = new StackOverflowClient() {
            @Override
            @MeteredRemoteCall
            public String getQuestionPage(Long loanId) {
                return "StackOverflowClient without Feign + extra annotation";
            }
        };
        System.out.println("  " + soClient.getQuestionPage(questionId));

        // Create StackOverflowClient via Feign
        String baseUrl = "http://stackoverflow.com";
        soClient = Feign
            .builder()
            .decoder(new StringDecoder())
            .target(StackOverflowClient.class, baseUrl);
        Matcher titleMatcher = Pattern
            .compile("<title>([^<]+)</title>", Pattern.CASE_INSENSITIVE)
            .matcher(soClient.getQuestionPage(questionId));
        titleMatcher.find();
        System.out.println("  " + titleMatcher.group(1));
    }
}

Console log without aspect:

  StackOverflowClient without Feign
  StackOverflowClient without Feign + extra annotation
  java - How to use AOP with Feign calls - Stack Overflow

As you can see, in case #3 it just prints the question title of this very StackOverflow question. ;-) I am using the regex matcher in order to extract it from the HTML code because I did not want to print the full web page.

Aspect:

This is basically your aspect with additional joinpoint logging.

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import de.scrum_master.app.MeteredRemoteCall;

@Aspect
public class MetricAspect {
    @Around(value = "@annotation(annotation)", argNames = "joinPoint, annotation")
    public Object meterRemoteCall(ProceedingJoinPoint joinPoint, MeteredRemoteCall annotation)
        throws Throwable
    {
        System.out.println(joinPoint);
        return joinPoint.proceed();
    }
}

Console log with aspect:

call(String de.scrum_master.app.StackOverflowClient.getQuestionPage(Long))
  StackOverflowClient without Feign
call(String de.scrum_master.app.StackOverflowClient.getQuestionPage(Long))
execution(String de.scrum_master.app.Application.2.getQuestionPage(Long))
  StackOverflowClient without Feign + extra annotation
call(String de.scrum_master.app.StackOverflowClient.getQuestionPage(Long))
  java - How to use AOP with Feign calls - Stack Overflow

As you can see, the following joinpoints get intercepted for each of the three cases:

  1. Only call() because even with manual instantiation the implementing class does not have the interface method's annotation. So execution() cannot be matched.
  2. Both call() and execution() because we manually added the marker annotation to the implementing class.
  3. Only call() because the dynamic proxy created by Feign does not have the interface method's annotation. So execution() cannot be matched.

I hope this helps you understand what happened and why.

Bottom line: Use full AspectJ in order to let your pointcut match against call() joinpoints. Then your problem is solved.

Question:

With javascript if we want to make sure that our code runs in all browser versions we can use Babel. Is there something like this for Java, where we could write our code in Java 9, but it will run in a Java 6 runtime?

For example can Kotlin target multiple JVM runtime versions?


Answer:

I was hoping for something like Kotlin to target multiple JVM runtimes - I guess we just have to dream for now.

You can compile Kotlin code to JDK6, JDK7, JDK8, JDK9 or any JDK above JDK6. This is what meant by supporting Java 1.6 level byte code. All features of Kotlin will stay the same, except for libraries, which can require different JDK versions.

The byte code generated by Kotlin will generally stay the same independent of the target JVM version. An exception is if you set a compiler option jvmTarget = "1.8", then the compiler may (or may not) use some features of JDK8 as an optimization.

IMHO this question got all the minuses because of how unexpected it is. Tools like Babel are unique to JavaScript because in all other languages they are called compilers. Since JS decided it could do without a compiler, I has such problems with deployments. There are (very limited) back porting tools for Java, but they are just plugins to the compiler. Kotlin doesn't have any, because its development is independent of JDK and it has to support all previous JDK versions above 1.6.

To sum it up, if you use Kotlin for JVM or JS development, your dream have come true - you can use any version of Kotlin, with any JVM library, probably any JS library above ES5.1, and get consistent runtime representation.

Question:

I have a class aspectJ in my maven project whitch hepls me to show the Begin and the End of any called method in my project. I try now to exclude all getters and setters. I try modify this annotation: @Around("execution(public * *(..)) by @Around("execution(public * *(..) && !within(* set*(..))")

But it doesn't whork and it gives me that in the consol:

 [ERROR] Failed to execute goal org.codehaus.mojo:aspectj-maven-plugin:1.7:compile (default) on project spb-lceb: AJC compiler errors:
 [ERROR] error at @Around("execution(public * *(..) && !within(* set*(..))")
 Syntax error on token "execution(public * *(..) && !within(* set*(..))", ")" expected

Any idea


Answer:

The accepted solution is clearly wrong because within(* set*(..)) will not even compile. This pointcut type needs a type signature, not a method signature. Furthermore, it only tries to take care of setters, not getters as asked by the OP.

The correct solution is:

@Around("execution(public * *(..)) && !execution(* set*(..)) && !execution(* get*(..))")

By accepting the wrong solution the OP even irritated someone else trying the same here. This is why after such a long time I am writing this answer.

Question:

Is there a way to get source files as a result of AspectJ compilation? So instead of getting bytecode, ajc works as a preprocessor that generates Java sources that can be compiled with javac?


Answer:

Since version 1.2 AspectJ has been a bytecode transformer, not a source transformer. For any recent version you cannot get sources directly out of AspectJ. You could use a decompiler/disassembler to go from the compiled bytecode back to sources but those sources may not look pretty.

You don't have to compile your aspects with the rest of your application code if that is your concern (i.e. that you want to build your app with javac)? You can compile your application with javac and then apply the aspects directly to the bytecode that javac produced in a binary weaving step.

Question:

@Component("taskCreateListener")
public class TaskCreateListener implements FlowableEventListener { 

@LogMethod
    @DetermineCaseTypeOfWork
    @Override
    public void onEvent(FlowableEvent event) {

///Do stuff that results in variables I want to pass to aspect
//For example, get ids and details and set to variables that I want to pass to insertThing() method once onEvent(FlowableEvent event) is finished executing
//ex:
//String procInstId = "abc1234";
//String type = "case1";
}

I need the onEvent to fully complete and then get local variables set in onEvent(FlowableEvent event) passed into my aspect insertThing() method:

@Aspect
@Component
public class DetermineCaseTypeOfWork {

@Transactional
@After(@annotation(path goes here))
public void insertThing() {
    //Do something here with the variables passed in from doSomething method
//if(procInstId.equals("abc1234") && type.equals("case1")) {
//do something
} else if(//other id and type) {
//do something else
} else {
//do something else
}
}

I can't modify the onEvent(FlowableEvent event) method to return something and the onEvent(FlowableEvent event) method has to fully complete first, so how would I go about passing parameters into insertThing()?


Answer:

According your question, there is no possibility to change signature of the onEvent() method, which should be handled by an aspect. You could try to create a ThreadLocal based container class which is initialized in aspect before calling onEvent() and assessed after finishing onEvent(). But that approach requires you to be able to edit onEvent() code (but do not requires change its returning type). Here are some details:

public class VariableContextHolder {

/**
 * ThreadLocal with map storing variables
 */
private final ThreadLocal<Map<String, Object>> threadlocal = new ThreadLocal<>();

private static VariableContextHolder instance;

private VariableContextHolder () {

}

public final static VariableContextHolder getInstance() {
    if (instance == null) {
        instance = new VariableContextHolder ();
    }
    return instance;
}

public Map<String, Object>get() {
    return threadlocal.get();
}

public void set(Map<String, Object>map) {
    threadlocal.set(map);
}

public void clear() {
    threadlocal.remove();
}
}

Aspect class:

@Aspect()
public class DetermineCaseTypeOfWork {

@Transactional
@Around(@annotation("path goes here"))
public void insertThing(ProceedingJoinPoint joinPoint) throws Throwable {

// save initialized map to threadlocal    
VariableContextHolder.getInstance().set(new HashMap<>());

// method onEvent() will be called
joinPoint.proceed();

// retrieve map from threadlocal
Map<String, Object> variablesMap = VariableContextHolder.getInstance().get();

// get variables by names and handle them
String procInstId = variablesMap.get("procInstId");

// clear threadlocal after using it
VariableContextHolder.getInstance().clear();
}

}

Changes needed to be done in onEvent() method:

public void onEvent(FlowableEvent event) {

    // retrieve map from threadlocal
    Map<String, Object> variablesMap = VariableContextHolder.getInstance().get();
    String procInstId = "abc1234";
    String type = "case1";
    // save variables to map
    variablesMap.put("procInstId", procInstId);
    variablesMap.put("type", type);
}

Question:

I am using AspectJ with annotation and trying to find how to disable all AspectJ's advices to stop advicing method from user's input (e.g. Boolean tracked = false).

Here is my code for main class.

package testMaven;


public class MainApp {

    public static void main(String[] args) {
        testing test = new testing();
        test.aa(1000);
        test.setDd(3);
    }

}

Here is the Aspect annotated class.

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

@Aspect
public class aspecter {

    public aspecter(){

    }

    boolean tracked = false;

    @Before("execution(*  testMaven.testing.aa(..)) && if(tracked)")
    public void testBefore(){
        System.out.println("yooi");
    }

    @Before("execution(*  testMaven.testing.setDd(..)) && if(tracked) ")
    public void testBefore2(){
        System.out.println("yooi2");
    }
}

if(tracked) will give an error of "Syntax error on token "execution(* testMaven.testing.aa(..)) && if(tracked) ", "in annotation style, if(...) pointcuts cannot contain code. Use if() and put the code in the annotated method" expected".

Is there anyway that I could specify the if() method based on my specification?

Thanks


Answer:

If using annotation style you have to do things a little differently, as the documentation describes ( https://eclipse.org/aspectj/doc/released/adk15notebook/ataspectj-pcadvice.html ). In your case your aspect needs to be something like this:

static boolean tracked = false;

@Pointcut("if()")
public static boolean tracked() {
  return tracked;
}

@Before("execution(*  testMaven.testing.aa(..)) && tracked()")
public void testBefore(){
    System.out.println("yooi");
}

@Before("execution(*  testMaven.testing.setDd(..)) && tracked() ")
public void testBefore2(){
    System.out.println("yooi2");
}

Notice the code that would normally go into the if(...) clause in a code style aspect is now in a method body, which is tagged with @Pointcut using if(). I did have to make the field static. You could probably modify the code in the tracked() method to use Aspects.aspectOf() to keep it non static.

Question:

I'm writing an aspect to log Request and Response of each API call in a controller. I want to be able to use this annotation on a class, hence used @Target(ElementType.TYPE)

Previously I had added @Target(ElementType.Method) and I was using this annotation on methods and it was working fine. Now I want to change it to @Target(ElementType.TYPE)

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ReLogger {}
@Aspect
@Component
public class ReLoggerAspect {
    public static final Logger log = LoggerFactory.getLogger("ReLoggerAspect");

    @PostConstruct
    private void postConstruct() {
        log.info("ReLoggerAspect Created");
    }

    @Around("@annotation(ReLogger)")
    private Object reqLoggingAspect(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("Request {}",jointPoint.getArgs()[0);
    }
}

Using @ReLoggerAspect on a class

@RestController
@RequestMapping(value = "....", produces = { "application/json" })
@ReLogger
public class Samplecontroller {
    /** Some logic here**/.....
}

It doesn't print the Request when an API SampleController is invoked


Answer:

Your premise that @annotation would match type annotations is wrong, see (Spring AOP manual](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-pointcuts-designators):

  • @within: Limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP).

  • @annotation: Limits matching to join points where the subject of the join point (the method being executed in Spring AOP) has the given annotation.

Thus, you ought to use @within(fully.qualified.AnnotationType).

Question:

I'm new to Spring. I am trying to use Spring AOP annotation like the following code.

@Aspect
public class A {
    @Pointcut("execution(* Operation.*(..))")
    public void b(){} 

    @Before("b()") 
    public void c(JoinPoint jp)
    {
        System.out.println("a");
    }
}

In my referenced libraries, I put all the spring jar (aop, core, aspects , beans, context, instrument, jdbc,jms,web, webmvc, etc)

I found another jar aspectj-1.9.3.jar and added it to my libraries in my eclipse. However, I can't import org.aspectj.lang.* (which I need). My Eclipse doesn't seem to locate it.

Did I find the right jar? (so the problem is something else?) Or do I need another jar? I am trying to do it without using Maven.


Answer:

org.aspectj.lang.joinpoint is part of the aspectj tool library. 

Add this to the Maven :

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjtools</artifactId>
    <version>1.8.9</version>
</dependency>

Question:

I have a scenario where my method to be intercepted is in the parent class and is not overridden in the pointcut class. Here is the sample classes:

public abstract class A{
@RequestMapping(value = "/data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
public String getData(@RequestBody String request) throws Exception {
    return "dummy";
}
}

@RestController
public class B extends A {
}

My Aspect is defined as:

@Aspect
@Component
public class RestCallLogger {
    @Pointcut("within(com.test..*) && within(@org.springframework.web.bind.annotation.RestController *)")
    public void restControllers() {
    }

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public void requestMappingAnnotations() {
    }

    @Around("restControllers() && requestMappingAnnotations()")
    public Object onExecute(ProceedingJoinPoint jp) throws Throwable {
        Object result = null;
        try {
            result = jp.proceed();
        } catch (Exception ex) {
            throw ex;
        }
        return result;
    }
}

But its not working. If I mark class A with Annotation @RestController and make it concrete, then it works. The question is how can I create a "pointcut for method in parent abstract class"? PS: I can not change the hierarchy of the code as its the existing code.


Answer:

For me this works. Here is an MCVE:

package de.scrum_master.app;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

public abstract class A {
  @RequestMapping(value = "/data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
  public String getData(@RequestBody String request) throws Exception {
    return request;
  }
}
package de.scrum_master.app;

import org.springframework.web.bind.annotation.RestController;

@RestController
public class B extends A {}
package de.scrum_master.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ComponentScan(basePackages = { "de.scrum_master" })
public class Application2 {
  public static void main(String[] args) throws Exception {
    ApplicationContext appContext = new AnnotationConfigApplicationContext(Application2.class);
    B b = (B) appContext.getBean("b");
    System.out.println(b.getData("bbb"));
    A a = (A) appContext.getBean("b");
    System.out.println(a.getData("aaa"));
  }
}
package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class RestCallLogger {
  @Pointcut("within(de.scrum_master..*) && @target(org.springframework.web.bind.annotation.RestController)")
  public void restControllers() {}

  @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
  public void requestMappingAnnotations() {
  }

  @Around("requestMappingAnnotations()")
  public Object onExecute(ProceedingJoinPoint jp) throws Throwable {
    System.out.println(jp);
    Object result = null;
    try {
      result = jp.proceed();
    } catch (Exception ex) {
      throw ex;
    }
    return result;
  }
}

The console log says:

execution(String de.scrum_master.app.A.getData(String))
bbb
execution(String de.scrum_master.app.A.getData(String))
aaa

What is different in your case?

Question:

I'm trying to define a pointcut around a method annotated with a custom annotation. The annotation has one parameter that I would like to include a check in the pointcut definition.

This is the annotation:

public @interface MyAnno {
  String[] types;
}

An example of how the annotation could be applied:

public class MyClass {
  @MyAnno(types={"type1", "type2"})
  public void doSomething() {
    // ...
  }
  @MyAnno(types={"type3"})
  public void doSomethingElse() {
    // ...
  }
}

Now I would like to have two pointcut definitions which select those two methods, based on the contents of the annotation.

Creating a pointcut on the annotation itself is relatively easy:

@Pointcut("@annotation(myAnno)")
public void pointcutAnno(MyAnno myAnno) {
}

@Pointcut("execution(* *(..)) && pointcutAnno(myAnno)")
public void pointcut(MyAnno myAnno) {
}

This will match every occurrence of the of @MyAnno. But how can I define two pointcuts, one matching @MyAnno with types containing "type1" and the other matching @MyAnno with types containing "type3"


Answer:

Currently AspectJ supports annotation value matching for a subset of the allowed kinds of annotation value. Unfortunately the array type you are using is not supported (class isn't supported either). This feature is documented in the 1.6.0 AspectJ README (https://eclipse.org/aspectj/doc/released/README-160.html). There is a section on 'Annotation value matching'. As described there the syntax is actually quite intuitive for the basic cases:

enum TraceLevel { NONE, LEVEL1, LEVEL2, LEVEL3 }

@interface Trace {
  TraceLevel value() default TraceLevel.LEVEL1;
}

aspect X {
  // Advise all methods marked @Trace except those with a tracelevel of none
  before(): execution(@Trace !@Trace(TraceLevel.NONE) * *(..)) {
    System.err.println("tracing "+thisJoinPoint);
  }
}

So just include the value you want to match on in the annotation. Unfortunately the array case is more complicated and so not implemented yet. It needs a little more syntax to allow you to specify whether your pointcut means 'at least this in the array value' or 'exactly this and only this in the array value'. Presumably that would reuse .. notation, something like this maybe:

execution(@MyAnno(types={"type1"}) * *(..)) { // exactly and only 'type1'
execution(@MyAnno(types={"type1",..}) * *(..)) { // at least 'type1'

Without the language support I'm afraid you do have to programmatically dig through the annotation in your code to check if it matches your constraint.

Question:

I am trying to to extend a 3rd lib code with new capabilities.

And since I only need to inject some code around one method from one class, I figured I can either:

  1. Fork the project and apply my changes (seems sloppy, and will definitely require lots of work whenever I try to upgrade to a newer version of the lib, not to mention licensing nightmare)
  2. Use [AOP] to intercept that one method from that one class inside a huge jar (seems cleaner) and inject my extra tests

In case any of you wants to know, that one class is not a spring bean and is used deep in the code, so I can not simply extend it and override/wrap that method easily, it would require at least a couple extra layers of extend&override/wrap. So AspectJ & AOP seems like the better way to go.

I managed to set my project up with some plugin to invoke ajc and weave the code with my desired jar in the -inpath param. And the only problem is that ajc seems to weave everything (or at least duplicate it);

So what I need basically is to ask AJC to simply wave that class from that jar, and not the whole jar !


Answer:

As you have noticed, the AspectJ compiler always outputs all files found in weave dependencies (in-JARs), no matter if they are changed or not. This behaviour cannot be changed via command line, AFAIK. So you need to take care of packaging your JARs by yourself.

Here is a sample project incl. Maven POM showing you how to do that. I have chosen a rather stupid example involving Apache Commons Codec:

Sample application:

The application base64-encodes a text, decodes it again and prints both texts to console.

package de.scrum_master.app;

import org.apache.commons.codec.binary.Base64;

public class Application {
    public static void main(String[] args) throws Exception {
        String originalText = "Hello world!";
        System.out.println(originalText);
        byte[] encodedBytes = Base64.encodeBase64(originalText.getBytes());
        String decodedText = new String(Base64.decodeBase64(encodedBytes));
        System.out.println(decodedText);
    }
}

Normally the output looks like this:

Hello world!
Hello world!

No surprises here. But now we define an aspect which manipulates the results returned from the third party library, replacing each character 'o' (oh) by '0' (zero):

package de.scrum_master.aspect;

import org.apache.commons.codec.binary.Base64;

public aspect Base64Manipulator {
    byte[] around() : execution(byte[] Base64.decodeBase64(byte[])) {
        System.out.println(thisJoinPoint);
        byte[] result = proceed();
        for (int i = 0; i < result.length; i++) {
            if (result[i] == 'o')
                result[i] = '0';
        }
        return result;
    }
}

BTW, if you would just use call() instead of execution() here, there would be no need to actually weave into third party code. But anyway, you asked for it, so I am showing you how to do it.

Maven POM:

<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>de.scrum-master.stackoverflow</groupId>
  <artifactId>aspectj-weave-single-3rd-party-class</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.source-target.version>1.8</java.source-target.version>
    <aspectj.version>1.8.10</aspectj.version>
    <main-class>de.scrum_master.app.Application</main-class>
  </properties>

  <build>

    <pluginManagement>
      <plugins>

        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.6.0</version>
          <configuration>
            <source>${java.source-target.version}</source>
            <target>${java.source-target.version}</target>
            <!-- IMPORTANT -->
            <useIncrementalCompilation>false</useIncrementalCompilation>
          </configuration>
        </plugin>

        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>aspectj-maven-plugin</artifactId>
          <version>1.9</version>
          <configuration>
            <!--<showWeaveInfo>true</showWeaveInfo>-->
            <source>${java.source-target.version}</source>
            <target>${java.source-target.version}</target>
            <Xlint>ignore</Xlint>
            <complianceLevel>${java.source-target.version}</complianceLevel>
            <encoding>${project.build.sourceEncoding}</encoding>
            <!--<verbose>true</verbose>-->
            <!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn>-->
            <weaveDependencies>
              <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
              </dependency>
            </weaveDependencies>
          </configuration>
          <executions>
            <execution>
              <!-- IMPORTANT -->
              <phase>process-sources</phase>
              <goals>
                <goal>compile</goal>
                <goal>test-compile</goal>
              </goals>
            </execution>
          </executions>
          <dependencies>
            <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjtools</artifactId>
              <version>${aspectj.version}</version>
            </dependency>
            <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjweaver</artifactId>
              <version>${aspectj.version}</version>
            </dependency>
          </dependencies>
        </plugin>

        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>exec-maven-plugin</artifactId>
          <version>1.5.0</version>
          <configuration>
            <mainClass>${main-class}</mainClass>
          </configuration>
        </plugin>

      </plugins>
    </pluginManagement>

    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
      </plugin>
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>2.5</version>
        <executions>
          <execution>
            <id>remove-unwoven</id>
            <!-- Phase 'process-classes' is in between 'compile' and 'package' -->
            <phase>process-classes</phase>
            <goals>
              <goal>clean</goal>
            </goals>
            <configuration>
              <!-- No full clean, only what is specified in 'filesets' -->
              <excludeDefaultDirectories>true</excludeDefaultDirectories>
              <filesets>
                <fileset>
                  <directory>${project.build.outputDirectory}</directory>
                  <includes>
                    <include>org/apache/commons/codec/**</include>
                    <include>META-INF/**</include>
                  </includes>
                  <excludes>
                    <exclude>**/Base64.class</exclude>
                  </excludes>
                </fileset>
              </filesets>
              <!-- Set to true if you want to see what exactly gets deleted -->
              <verbose>false</verbose>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
      </plugin>
    </plugins>

  </build>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
        <scope>runtime</scope>
      </dependency>
      <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.10</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
    </dependency>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
    </dependency>
  </dependencies>

  <organization>
    <name>Scrum-Master.de - Agile Project Management</name>
    <url>http://scrum-master.de</url>
  </organization>
</project>

As you can see I am using <weaveDependencies> in the AspectJ Maven plugin (which translates to -inpath for the AspectJ compiler) in combination with a special execution of the Maven Clean plugin that deletes all unneeded classes and the META-INF directory from the original JAR.

If the you run mvn clean package exec:java you see:

[INFO] ------------------------------------------------------------------------
[INFO] Building aspectj-weave-single-3rd-party-class 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
(...)
[INFO] --- aspectj-maven-plugin:1.9:compile (default) @ aspectj-weave-single-3rd-party-class ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
(...)
[INFO] --- maven-clean-plugin:2.5:clean (remove-unwoven) @ aspectj-weave-single-3rd-party-class ---
[INFO] Deleting C:\Users\Alexander\Documents\java-src\SO_AJ_MavenWeaveSingle3rdPartyClass\target\classes (includes = [org/apache/commons/codec/**, META-INF/**], excludes = [**/Base64.class])
(...)
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ aspectj-weave-single-3rd-party-class ---
[INFO] Building jar: C:\Users\Alexander\Documents\java-src\SO_AJ_MavenWeaveSingle3rdPartyClass\target\aspectj-weave-single-3rd-party-class-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- exec-maven-plugin:1.5.0:java (default-cli) @ aspectj-weave-single-3rd-party-class ---
Hello world!
execution(byte[] org.apache.commons.codec.binary.Base64.decodeBase64(byte[]))
Hell0 w0rld!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

And this is what my target/classes directory looks like after the build:

As you can see, there is only one Apache Commons class file left which goes into the created JAR.

Question:

I have a (newbie) question regarding Spring framework, Aspect Orientated Programming and AspectJ.

Is there a way to find out which method caused call to "beforeAdvice" and "afterAdvice" ?

For example , in the example below , can I find out if Dog.bark() or Dog.sleep() caused call to "beforeAdvice" and "afterAdvice" ?

I have attached the console output below the source code.

Thanks for your time and help, James

Dog.java

package com.tutorialspoint;

public class Dog
{
    public void bark()
    {
        System.out.println("Dog.bark()");
    }

    public void sleep()
    {
        System.out.println("Dog.sleep()");
    }
}

DogMonitor.java

package com.tutorialspoint;

public class DogMonitor
{
    public void beforeAdvice()
    {
        System.out.println("DogMonitor.beforeAdvice()  --  but was it bark or sleep ?");
    }

    public void afterAdvice()
    {
        System.out.println("DogMonitor.afterAdvice()  --  but was it bark or sleep ?");
    }

    public void afterReturningAdvice(Object retVal)
    {
        System.out.println("DogMonitor.afterReturningAdvice(): " + retVal.toString());
    }

    public void AfterThrowingAdvice(IllegalArgumentException ex)
    {
        System.out.println("DogMonitor.AfterThrowingAdvice(): " + ex.toString());
    }
}

MainApp.java

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp
{
   public static void main(String[] args)
   {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");

      Dog dog = (Dog) context.getBean("dog");
      dog.bark();
      dog.sleep();
   }
}

Beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

   <aop:config>
      <aop:aspect id="dogMonitorAspect" ref="dogMonitorBean">
         <aop:pointcut  id="selectAll"            expression="execution(* com.tutorialspoint.Dog.*(..))"/>
         <aop:before    pointcut-ref="selectAll"  method="beforeAdvice"/>
         <aop:after     pointcut-ref="selectAll"  method="afterAdvice"/>
      </aop:aspect>
   </aop:config>

   <!-- Definition for dog bean -->
   <bean id="dog" class="com.tutorialspoint.Dog"/>

   <!-- Definition for dogMonitor bean -->
   <bean id="dogMonitorBean" class="com.tutorialspoint.DogMonitor"/>

</beans>

Console output

DogMonitor.beforeAdvice()  --  but was it bark or sleep ?
Dog.bark()
DogMonitor.afterAdvice()  --  but was it bark or sleep ?
DogMonitor.beforeAdvice()  --  but was it bark or sleep ?
Dog.sleep()
DogMonitor.afterAdvice()  --  but was it bark or sleep ?

Answer:

Try adding a JoinPoint as a parameter to your Aspect methods:

 public void beforeAdvice(JoinPoint jp) {
   // This will print out "bark"
   System.out.println( p.getSignature().getName );
 }

In Spring, this JoinPoint will always have a MethodSignature as a Signature (since spring can only access methods that way), so you can then do (if you want detailed information about the method, more than what the default signature interface tells you)...

MethodSignature signature = (MethodSignature)jp.getSignature();
Method method = signature.getMethod();

And for an Around Aspect, you can use a ProceedingJoinPoint.

Question:

I'm sure this amounts to Newbie question for AspectJ but reviewing books and web sites, I'm not seeing the answer in terms I recognize.

Summary: In my Client Jar, I am getting compilation errors complaining that methods that were added as a part of "Aspect B" are not present.

I have a setup similar to :

         +---------------------+     
         |                     |     
         |  Client Jar         |     
         |                     |     
         +--+---------------+--+     
            |               |        
            |               |        
 +----------+----+  +-------v-------+
 | JSON Serial / |  |  Other Aspect |
 |  Deser Aspect |  +---------------+
 +-------------+-+  +-------v-------+
               |    |  Potential    |
               |    |   Other Jar   |
               |    +---------------+
               |                     
          +----v-----------+         
          |   Javabean     |         
          |   Aspects      |         
          +----------------+         
          +----v-----------+         
          |   Basic Data   |         
          |    Objects     |         
          +----------------+         

Essentially, I have two levels of aspects where behaviors are being extended in each layer.

Assume the following class in "Basic Data Objects":

BasicDataObjects SampleObject

public class SampleObject {
    private String name;
    private int age;
}

and the following aspect in JavaBean Aspects:

privileged aspect SampleObject_JavaBean {
    public String SampleObject.getName() {
       return this.name;
    }
}

And the following aspect in JSON Aspects:

privileged aspect SampleObject_Json {
    public String SampleObject.getNameValue() {
       return this.name == null ? null : this.name.serialize();
    }
}

Finally, in the actual client jar, I am getting the following as a compilation error:

public void someMethod (SampleObject obj) {
    obj.getNameValue() // <-- This has a compilation error that the getNameValue() is unresolvable.
}

In my Client Jar, I am getting compilation errors that methods that were added as a part of "Aspect B" are not available.

My expectation was that the "Aspect A" generated jar file should have all its own classes compiled as well as all the classes that were provided as a part of "Aspect B".

Aspect B pom:

<project>
    <!-- (...) -->

    <artifactId>aspect-b</artifactId>

        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>${aspectj.version}</version>
            </dependency>
            <dependency>
                <groupId>com.example</groupId>
                <artifactId>lib-data-objects</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
        </dependencies>

        <build>
            <plugins>


        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.7</version>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <outxml>true</outxml>
                <complianceLevel>${java.version}</complianceLevel>
                <source>${java.version}</source>
                <target>${java.version}</target>

                <weaveDependencies>
                    <weaveDependency>
                        <groupId>com.example</groupId>
                        <artifactId>lib-data-objects</artifactId>
                    </weaveDependency>
                </weaveDependencies>
            </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>
</build>

    <!-- (...) -->
</project>

Aspect A pom:

<project>

<!-- (...) -->

<artifactId>aspect-a</artifactId>

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
    </dependency>

    <dependency>
        <groupId>com.example</groupId>
        <artifactId>lib-data-objects</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>aspect-b</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.7</version>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <outxml>true</outxml>
                <complianceLevel>${java.version}</complianceLevel>
                <source>${java.version}</source>
                <target>${java.version}</target>

                <weaveDependencies>
                    <weaveDependency>
                        <groupId>com.example</groupId>
                        <artifactId>aspect-b</artifactId>
                    </weaveDependency>
                </weaveDependencies>
            </configuration>
        </plugin>
    </plugins>
</build>

<!-- (...) -->

</project>

Client Jar pom:

<project>

<!-- (...) -->

<dependencies>
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>aspect-a-wrapper</artifactId>
        <version>${aspect-a.version}</version>
    </dependency>
    <groupId>com.example</groupId>
        <artifactId>lib-data-objects</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.7</version>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <outxml>true</outxml>
                <complianceLevel>${java.version}</complianceLevel>
                <source>${java.version}</source>
                <target>${java.version}</target>

                <weaveDependencies>
                    <weaveDependency>
                        <groupId>com.example</groupId>
                        <artifactId>aspect-a</artifactId>
                    </weaveDependency>
                </weaveDependencies>
            </configuration>
        </plugin>
    </plugins>
</build>

<!-- (...) -->

</project>

Answer:

As you said in your own answer, in your client JAR pom.xml you have defined dependencies on both

  • the plain data objects library (without aspect code) and
  • the aspect-enhanced data objects library after two stages of weaving (Java Beans and JSON inter-type declarations).

But you only need the latter, so you should remove the former.

That you use weaveDependencies in your aspect libraries is okay and necessary because otherwise they will not compile in your scenario: Aspect B needs the data objects library because otherwise it cannot find the classes it should add new methods to. Aspect B needs Aspect A because it wants to use an already aspect-enhanced library to add even more methods via ITD. I don't think that this is a particularly nice setup because Aspect B needs to know about Aspect A, which creates an unnecessary transitive dependency ClientJar -> AspB -> AspA -> DataObj. Maybe it would be wiser to aspect-enhance the data objects library directly and shorten the chain to ClientJar -> DataObj. This is only bad if you really need the plain library without any added ITD methods in other circumstances. Then you could still create a plain and a fully aspect-enhanced version (only one stage of aspect enhancement, not two transitively dependent ones).


Update, 2015-01-02:

I had some leftover time and have started looking into this again. What I have ended up with is a nice solution (see GitHub repo) with the following characteristics:

  • There is a parent module aspectj-multi-module, child modules are:
    • data-objects (application class, no aspects), no dependencies
    • aspect-javabean (Java Bean-related ITD aspect), depends on data-objects
    • aspect-json (JSON-related ITD aspect), depends on data-objects
    • data-objects-aspectj (weave aspects into core classes), depends on data-objects, aspect-javabean, aspect-json
    • client-jar (create JAR of JARs containing core + aspect code, sample class with main method using aspect-enhanced core class and AspectJ runtime), depends on data-objects-aspectj
  • Please note that both aspect-{javabean,json} modules only depend on the core module, but no aspect module depends on the other one. Both aspect types are woven into the core code in module data-objects-aspectj via binary weaving.
  • A little trick was used in order to compile the ITD aspects, but excluding the woven core modules from the resulting aspect library because we only want the aspects in the library. In order to understand the trick you need to know the difference between the Ajc (AspectJ compiler)'s inpath and its aspectpath:
    • Whatever is on the inpath will also be in the output directory/JAR. The corresponding AspectJ Maven config setting is <weaveDependency>, section <weaveDependencies>.
    • Whatever is on the aspectpath is only available during compile time and will not end up in the output directory/JAR. The corresponding AspectJ Maven config setting is <aspectLibrary>, section <aspectLibraries>.
  • So, using the semantics mentioned above, the core module is defined as an <aspectLibrary> (even though it does not contain any aspects, don't be confused by the naming). This effectively avoids any woven core classes from being part of aspect libraries. It would not be useful to have multiple versions of woven core classes with mutually exclusive aspects in the aspect library because which one should win in the end? We need a version of our core code with all aspect libraries woven in at the same time, or at least all we choose to configure in another module.
  • The other module just mentioned is data-objects-aspectj, and its sole purpose is to do post-compile, binary aspect weaving, using as its input the pure Java core module and both pure aspect libraries. All of these modules are configured as <weaveDependencies> this time, because all of them should be in the resulting JAR. In order to enable binary weaving in the AspectJ Maven plugin, we need to add one dummy class because the plugin does not compile or weave anything if it does not find any source files in its own module. The dummy class is stripped from the output again via an explicit exclusion configured in the Maven JAR plugin. The exclusion is nice to have, you could also just ignore the dummy class in the output JAR.
  • Last, but not least, there is module client-jar which adds a little driver application with a main method to the whole mix in order to make it runnable and testable from the command line. The driver application uses getter methods created by both the JSON and the Java Beans aspects in order to prove that they really exist and are functional.
  • Another nicety in module client-jar is the creation of a One-JAR (über-JAR) containing all dependencies (even the AspectJ runtime) and a main class configuration. Effectively you can just run the result via: java -jar client-jar/target/client-jar-1.0-SNAPSHOT.one-jar.jar
  • Finally, module client-jar also contains an Exec Maven plugin configuration for directly running the über-JAR via: mvn --projects client-jar exec:exec. This is also nice to have, just like the über-JAR itself, but why make life harder than necessary? ;-)

Console in-/output:

$ java -jar client-jar/target/client-jar-1.0-SNAPSHOT.one-jar.jar

SampleObject{name='John Doe', age=33}

Java Bean properties:
  John Doe
  33

JSON properties:
  "Name" : "John Doe"
  "Age" : 33

Update, 2015-01-03:

I added the capability to create a custom mix of aspects applied to your core code during weaving in module data-objects-aspectj by means of Maven profiles, see changeset 32ee5fc.

Question:

I am new to aspectj and I had a function which gets the integer variable and adds 100 to it as follows

public static void add(int no)
    {
        no=no+100;


    }

My aspect is as follows

pointcut printMessage(int m) : execution(* add(..)) && args(m);
 after(int m) returning: printMessage(m) {
            System.out.println(m);
}

I am calling the function with the value 10. But when I run the code, it returns the result as 10. can any one tell me why it is not returning 110. correct me if I am wrong


Answer:

Because in java an int is not modifiable. If you write

int i = 10;
add(i);
System.out.println(i);

You will still get 10. So your aspect does what you asked : you pass a variable of value 10 to a function, the fuction does what it wants with its local copy, and on return the variable is unchanged

Edit :

If you want to get a modified value, you could pass a modifiable variable like an array, or more simply use the return value (because your current add is a no op) :

Edit 2 here is full test code :

public class AspectTest {
    public static int add(int i) {
        return i+100;
    }

    @Test
    public void test() throws Exception {
        int j = add(10);
        assertEquals(110, j);
        add(20);
    }
}

and :

aspect A {
pointcut printMessage() : execution(* add(..));
 after() returning (int m): printMessage() {
            System.out.println(m);
}
}

Output :

Running ...AspectTest
110
120
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.214 sec

Question:

I have an aspect that intercepts a lot of methods in my code. I was wondering if joinPoint's signature and declaring type can ever be null. If no, then my try...catch is not required.

In other words, is try...catch block in following code required?

 private Object logPerfomanceInfo(ProceedingJoinPoint joinPoint) {
        StringBuilder tag = new StringBuilder();
        try {
            tag.append(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        } catch (Exception e) {
            // Do not do anything, let the execution continue
        }
        StopWatch stopWatch = new StopWatch(tag.toString());
        Object result = joinPoint.proceed(); // continue on the intercepted method
        stopWatch.stop();
        PerformanceUtils.logInPerf4jFormat(stopWatch.getStartTime(), stopWatch.getElapsedTime(), stopWatch.getTag(), stopWatch.getMessage(), getRemoteAddress());
        return result;
    }

Answer:

I was wondering if joinPoint's signature and declaring type can ever be null.

No, they can't.

One way (long way) to verify is reading the source code of Spring's implementation.

Alternatively, we can turn to the very good AspectJ documentation. The javadoc for JoinPoint#getSignature() states

Returns the signature at the join point.

And Signature#getDeclaringTypeName()

Returns the fully-qualified name of the declaring type.

Both javadoc entries are very specific about what they return. It would make no sense for either of them to return null.

Question:

I am using Spring specific pointcut expression called bean(). For the following expression only the left part is being catched:

@AfterReturning("bean(FirstService).firstMethod(..) || bean(SecondService).secondMethod(..)")

if I do reverse, again the left part is being catched:

@AfterReturning("bean(SecondService).secondMethod(..) || bean(FirstService).firstMethod(..)")

If i write:

@AfterReturning("bean(SecondService).secondMethod(..)")

and @AfterReturning("bean(FirstService).firstMethod(..)") in two methods

then both works. What's wrong with the first OR statement ?


Answer:

The reason for this point cut expression to not work as expected is because it is incorrect. The Spring framework is not throwing any exception for this is another reason that leads to confusion.

As per the Spring Reference Documentation Section 5.4.3. Declaring a Pointcut the correct way to declare a bean() pointcut designator is as follows

bean(idOrNameOfBean)

The idOrNameOfBean token can be the name of any Spring bean. .

An aspect like the following code is the correct way to define the aspect and this will intercept all the method calls for both beans .

@Component
@Aspect
public class BeanAdviceAspect {

    @AfterReturning("bean(firstService) || bean(secondService)")
    public void logMethodCall(JoinPoint jp) {
        System.out.println(jp.getSignature());
    }
}

A point cut expression bean(firstService).firstMethod() is incorrect and the framework seems to discard anything after the bean(firstService) and that is the reason your testcases behaves differently when the declaration is reversed.

To confirm this behaviour , the following aspect

@Component
@Aspect
public class BeanAdviceAspect {

    @AfterReturning("bean(firstService).firstMethod() || bean(secondService)")
    public void logMethodCall(JoinPoint jp) {
        System.out.println(jp.getSignature());
    }
}

would also advice a method firstService.thirdMethod() for the reasons explained above.

Another way to declare bean pointcut designator is as follows . This matches the method execution in any Spring beans names that matches the wildcard expression.

@AfterReturning("bean(*Service)")
public void logMethodCall(JoinPoint jp) {
    System.out.println(jp.getSignature());
}

Hope this helps

Question:

Using the aspectjweaver version 1.11 with aspectjrt greater than version 1.8.5 leads to multiple NPE during the build of our GWT 1.8.2 application with Java 8:

[INFO] --- aspectj-maven-plugin:1.11:compile (compile) @ myproject ---
...
[ERROR] java.lang.NullPointerException
    at org.aspectj.org.eclipse.jdt.internal.compiler.lookup.FieldBinding.sourceField(FieldBinding.java:437)
    at org.aspectj.org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl$SourceLocationComparator.determineSourceStart(TypeElementImpl.java:110)
    at org.aspectj.org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl$SourceLocationComparator.getSourceStart(TypeElementImpl.java:74)
    at org.aspectj.org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl$SourceLocationComparator.compare(TypeElementImpl.java:67)
    at org.aspectj.org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl$SourceLocationComparator.compare(TypeElementImpl.java:1)
    at java.util.TimSort.countRunAndMakeAscending(TimSort.java:360)
    at java.util.TimSort.sort(TimSort.java:234)
    at java.util.Arrays.sort(Arrays.java:1512)
    at java.util.ArrayList.sort(ArrayList.java:1462)
    at java.util.Collections.sort(Collections.java:175)
    at org.aspectj.org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl.getEnclosedElements(TypeElementImpl.java:168)
    at com.google.web.bindery.requestfactory.apt.DomainChecker.isDefaultInstantiable(DomainChecker.java:407)
    at com.google.web.bindery.requestfactory.apt.DomainChecker.visitType(DomainChecker.java:253)
    at com.google.web.bindery.requestfactory.apt.DomainChecker.visitType(DomainChecker.java:44)
    at org.aspectj.org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl.accept(TypeElementImpl.java:139)
    at javax.lang.model.util.ElementScanner6.scan(ElementScanner6.java:146)
    at com.google.web.bindery.requestfactory.apt.ScannerBase.scan(ScannerBase.java:76)
    at com.google.web.bindery.requestfactory.apt.State.executeJobs(State.java:248)
    at com.google.web.bindery.requestfactory.apt.RfValidator.process(RfValidator.java:86)
    at org.aspectj.org.eclipse.jdt.internal.compiler.apt.dispatch.RoundDispatcher.handleProcessor(RoundDispatcher.java:142)
    at org.aspectj.org.eclipse.jdt.internal.compiler.apt.dispatch.RoundDispatcher.round(RoundDispatcher.java:124)
    at org.aspectj.org.eclipse.jdt.internal.compiler.apt.dispatch.BaseAnnotationProcessorManager.processAnnotations(BaseAnnotationProcessorManager.java:171)
    at org.aspectj.org.eclipse.jdt.internal.compiler.Compiler.processAnnotations(Compiler.java:956)
    at org.aspectj.org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:451)
    at org.aspectj.org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:427)
    at org.aspectj.ajdt.internal.core.builder.AjBuildManager.performCompilation(AjBuildManager.java:1107)
    at org.aspectj.ajdt.internal.core.builder.AjBuildManager.performBuild(AjBuildManager.java:276)
    at org.aspectj.ajdt.internal.core.builder.AjBuildManager.batchBuild(AjBuildManager.java:189)
    at org.aspectj.ajdt.ajc.AjdtCommand.doCommand(AjdtCommand.java:114)
    at org.aspectj.ajdt.ajc.AjdtCommand.runCommand(AjdtCommand.java:60)
    at org.aspectj.tools.ajc.Main.run(Main.java:371)
    at org.aspectj.tools.ajc.Main.runMain(Main.java:248)
    at org.codehaus.mojo.aspectj.AbstractAjcCompiler.execute(AbstractAjcCompiler.java:544)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:956)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:288)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:192)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)

This happens in all @ProxyFor classes, that are proxies for classes outside the project (resolved by maven dependency).

@ProxyFor(value = ClassOfOtherProject.class)
public interface ClassOfOtherProjectProxy extends EntityProxy { // <- NPE happens in this Line!

    ...

}

Excerpt from the pom.xml:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <useIncrementalCompilation>false</useIncrementalCompilation>
        <encoding>UTF-8</encoding>
        <annotationProcessors>
            <annotationProcessor>com.google.web.bindery.requestfactory.apt.RfValidator</annotationProcessor>
        </annotationProcessors>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>com.google.web.bindery</groupId>
            <artifactId>requestfactory-apt</artifactId>
            <version>2.8.2</version>
        </dependency>
    </dependencies>
</plugin>

Only with aspectjrt 1.8.4 (or lower) it runs fine. What should I do? After migrating from Java 7 to 8 and GWT 1.7.x to 1.8.2 these errors still persists. How can I update aspectjrt without getting these NPE?


Answer:

This is not failing in the GWT compile, but simply in the course of compiling the java sources to bytecode. GWT's RequestFactory uses an annotation-processor to validate that each of your proxies correctly matches the entity/value/service types that they map to on the server, and it appears that this version of aspectjrt and jdt somehow can't correctly look up the members of ClassOfOtherProject so they can be filtered down to find the constructor. From your stack trace, in com/google/web/bindery/requestfactory/apt/DomainChecker.java:407:

List<ExecutableElement> constructors = ElementFilter.constructorsIn(x.getEnclosedElements());

This is a very standard way to do things in annotation processors - if calling TypeElement.getEnclosedElements() is failing with an NPE for this annotation processor, I would be concerned about other bugs in this build as well. It is very likely that this would happen with any annotation processor, and is nothing to do with GWT.

Question:

I'm an inexperienced developer that is learning Java. I'm working on this AddressBook, where I'm implementing AspectJ to one of my functions (Update Contact). Before updating the contact, obviously the user needs to add a Contact, and my saveContact code looks like this:

public class Contacts { //class to manage the contacts information

    public String name;
    public String street;
    public String city;
    public String state;
    public int zip;
    public long phoneNumber;
    public Scanner input;

    public void saveContact()
    {//code to add and save a contact to the book
        input = new Scanner(System.in);

        System.out.println("Plase enter contact Name and Lastname: ");
        name = input.nextLine();

        System.out.println("\nPlase enter Street of contact: ");
        street = input.nextLine();

        System.out.println("\nPlase enter City of the contact: ");
        city = input.nextLine();

        System.out.println("\nPlase enter State of the contact: ");
        state = input.nextLine();

        System.out.println("\nPlase enter the Zipcode of the contact: ");
        zip = input.nextInt();

        System.out.println("\nPlase enter the contact Phone number (Ex 1115550000): ");
        phoneNumber = input.nextLong();

        System.out.println("Done! Contact Saved");
}

I have more options like Update Contact, Find Contact and Delete Contac. before the Update Contact function executes, I want to run an Aspect that saves the values that the user entered to the variables(name, city, state, etc) in a file.txt, before assigning the new values in the Update Contact code. My issue is that when the Aspect advise executes, my .txt file comes with null instead of the values assigned by the user in the Add Contact code.

My Aspect looks like this:

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public aspect AspectUpdateContact { //code to save the old information of the contact to the file before updating the contact

    pointcut aspectCallUpdateFile() : call (void updateContact()) && within (Menu);
    before() : aspectCallUpdateFile() 
        {
/*******Code is running and saving to the file but not bringing the values of the variables, saving null values*/
        Contacts ct = new Contacts();
        try {

        PrintWriter pwrite = new PrintWriter(new FileWriter("UpdatesLog.txt", true));//to append the write to the end of the file

        pwrite.println("Record Updated->" + ct.name +":"+ ct.street +":"+ ct.city +":"+ ct.state +":"+ ct.zip +":"+ ct.phoneNumber);

        pwrite.close();//close the Print Writer

            }
            catch (IOException e) {
                System.out.println(e.getMessage());
            }

    }// end of code for pointcut

}//end of aspect

My final output in the txt file is: Record Updated:null:null:null:null:0:0


Answer:

I refactored your code a bit (no more plural in class name, renamed methods, private fields, toString() method, convenience constructor, try with resources in aspect) and also fixed the aspect by using target() with argument binding in the aspect:

Contact data class:

package de.scrum_master.app;

import java.util.Scanner;

public class Contact {
  private String name;
  private String street;
  private String city;
  private String state;
  private int zip;
  private long phoneNumber;

  private Scanner input;

  public Contact() {}

  public Contact(String name, String street, String city, String state, int zip, long phoneNumber) {
    this.name = name;
    this.street = street;
    this.city = city;
    this.state = state;
    this.zip = zip;
    this.phoneNumber = phoneNumber;
  }

  @Override
  public String toString() {
    return "Contact[name=" + name + ", street=" + street + ", city=" + city + ", state=" + state +
      ", zip=" + zip + ", phoneNumber=" + phoneNumber + "]";
  }

  public void updateContact() {
    input = new Scanner(System.in);

    System.out.println("Please enter contact Name and Lastname: ");
    name = input.nextLine();
    System.out.println("\nPlease enter Street of contact: ");
    street = input.nextLine();
    System.out.println("\nPlease enter City of the contact: ");
    city = input.nextLine();
    System.out.println("\nPlease enter State of the contact: ");
    state = input.nextLine();
    System.out.println("\nPlease enter the Zipcode of the contact: ");
    zip = input.nextInt();
    System.out.println("\nPlease enter the contact Phone number (Ex 1115550000): ");
    phoneNumber = input.nextLong();

    System.out.println("Done! Contact updated.\n");
  }
}

Dummy menu class with main method:

package de.scrum_master.app;

public class Menu {
  public void updateContact(Contact contact) {
    contact.updateContact();
  }

  public static void main(String[] args) {
    Menu menu = new Menu();
    Contact contact = new Contact("Albert Einstein", "101 Main St", "Middle of Nowhere", "Utah", 12345, 11223344);
    menu.updateContact(contact);
    menu.updateContact(contact);
  }
}

As you can see, I am creating an initial contact object and then update it twice in order to create two lines of log output.

Logging aspect:

package de.scrum_master.aspect;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import de.scrum_master.app.Contact;
import de.scrum_master.app.Menu;

public aspect UpdateContactAspect {
  pointcut callUpdateContact(Contact contact) :
    call(void updateContact()) && within(Menu) && target(contact);

  before(Contact contact) : callUpdateContact(contact) {
    try (PrintWriter writer = new PrintWriter(new FileWriter("UpdatesLog.txt", true))) {
      writer.println("Record updated -> " + contact);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

Console log for sample run:

Please enter contact Name and Lastname: 
John Doe

Please enter Street of contact: 
321 Broadway

Please enter City of the contact: 
New York City

Please enter State of the contact: 
New York

Please enter the Zipcode of the contact: 
54321

Please enter the contact Phone number (Ex 1115550000): 
0123456789
Done! Contact updated.

Please enter contact Name and Lastname: 
Donald Duck

Please enter Street of contact: 
33 Wherever

Please enter City of the contact: 
Quacktown

Please enter State of the contact: 
Duckstate

Please enter the Zipcode of the contact: 
88099

Please enter the contact Phone number (Ex 1115550000): 
999333111
Done! Contact updated.

Log file content after sample run:

Record updated -> Contact[name=Albert Einstein, street=101 Main St, city=Middle of Nowhere, state=Utah, zip=12345, phoneNumber=11223344]
Record updated -> Contact[name=John Doe, street=321 Broadway, city=New York City, state=New York, zip=54321, phoneNumber=123456789]

There are more things which need refactoring, but I am stopping here.

Question:

I've got an pointcut that I am trying to use with LTW. I have 2 methods that I am trying to advise, each with a different parameter list. However, they both have a single common parameter that I want.

These are the method signatures I want to advise:

   public static WorkflowModifierFlags authenticateUser(String username, String password, String ip, boolean webGUI, boolean realAuthentication)

   public static boolean loginJAAS(HttpServletRequest request, HttpServletResponse response, String username, String password, HttpSession session)

I've tried the following pointcut/advice, but it is failing; the username variable is sometimes getting injected with the IP address (ie: the args() from the first pointcut).

@Before("(execution(public static * business.security.service.LoginManagerHelper.authenticateUser(..)) && args( username, ..)) || "
        + "(execution(public static * webapp.util.LoginManagerAction.loginJAAS(..)) && args( *, *, username, ..))" )
public void setUsername(JoinPoint jp, String username) {
    // inject the username into the MDC
    MDCUtils.setUsername(username);
}

I would have expected that the args() parameter is associated to the execution() method, but sometimes it would appear that it is "confused", and gives me the IP instead of the username.

Am I using AspectJ incorrectly, or is this a bug in the LTW? I'm running AspectJ 1.6.13


Answer:

AspectJ 1.8.9 has the same behavior. One solution/workaround to this would be to split the advice into two using a different pointcut for each case, then delegate the logic you want to do with the username to avoid code duplication. It would look similar to this:

@Before("execution(public static * business.security.service.LoginManagerHelper.authenticateUser(..)) && args( username, ..)")
public void pointcut1(String username) {
    doSomethingWithUsername(username);
}

@Before("execution(public static * webapp.util.LoginManagerAction.loginJAAS(..)) && args( *, *, username, ..)")
public void pointcut2(String username) {
    doSomethingWithUsername(username);
}

private void doSomethingWithUsername(String username) {
    // inject the username into the MDC
    MDCUtils.setUsername(username);
}

I always split advices based on OR-ed pointcuts using bindings like that for each use-case (i.e. the pointcut expressions originally combined with ||) because with @annotation() type pointcuts it results in an error message about inconsistent binding. See my two other answers about those cases and a similar solution to extract the common functionality to a separate method: answer 1, answer 2.

I believe AspectJ should exhibit the same behavior in your case as with @annotation() type pointcuts, so I think the compiler not reporting an error and doing unexpected things is a bug in the AspectJ compiler itself.

Question:

Could someone please help me understand the below pointcut in aspectj?

This pointcut works for annotation @DynamicValue but how it works is confusing.

Below is my custom annotation:

@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DynamicValue {
String lookupName() default "";
}

My class using the annotation:

com.package.sample;
Class SampleA{

@DynamicValue("Hello")
public String greet;

//getters & setters

}

And the aspect containing pointcut:

@Aspect
@Configurable
@Component
public class DynamicValueAspect
{

@Pointcut("get(@com.sample.aspect.DynamicValue java.lang.String com.package.sample..*.*)")
public void isDynamicValue() {}

@Around("isDynamicValue()")
public void getLocalized(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("Annotation called");
//How can I access the parameter in annotation here 
//i.e "Hello" from the @DynamicValue("Hello")
}

Is the pointcut correct, and will it work wherever I use the @DynamicValue annotation?

Also I would like to know how to access the Annotation Parameter in the advice?


Answer:

Annotation:

package de.scrum_master.app;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.FIELD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DynamicValue {
    String lookupName() default "";
}

Driver application with an annotated member:

package de.scrum_master.app;

public class Application {
    @DynamicValue(lookupName = "foobar")
    public String greet;
    public String anotherMember;

    public static void main(String[] args) {
        Application application = new Application();
        application.greet = "world";
        application.anotherMember = "Another member";
        application.sayHello();
    }

    private void sayHello() {
        System.out.println(anotherMember);
        System.out.println("Hello " + greet);
    }
}

Aspect:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;

import de.scrum_master.app.DynamicValue;

@Aspect
@Configurable
@Component
public class DynamicValueAspect {
    @Pointcut("get(String de.scrum_master.app..*) && @annotation(dynamicValue)")
    public void isDynamicValue(DynamicValue dynamicValue) {}

    @Around("isDynamicValue(dynamicValue)")
    public Object getLocalized(DynamicValue dynamicValue, ProceedingJoinPoint thisJoinPoint) throws Throwable {
        System.out.println(thisJoinPoint);
        System.out.println("    " + dynamicValue);
        return thisJoinPoint.proceed();
    }
}

Console log:

Another member
get(String de.scrum_master.app.Application.greet)
    @de.scrum_master.app.DynamicValue(lookupName=foobar)
Hello world

By the way, a @Before advice is sufficient if you do not want to change the result for get(). For just printing something @Around is overkill.


Because OP asked if it is possible to limit pointcut matching to a certain primitive type like int, both capturing real primitives and the boxed type Integer, I am going to show a variant doing just that. As as I said earlier, if there is not need to manipulate the value returned by the field accessor pointcut, there is no need to use @Around either. We just use @AfterReturning because it has an optional returning parameter by means of which we can bind the actual return value to an advice parameter. If then we choose something other than Object for that advice parameter - in this case we just use int - we get what was asked for.

So let us add two annotated parameters typed int and Integer to the original code:

Driver application with annotated members:

package de.scrum_master.app;

public class Application {
    @DynamicValue(lookupName = "foobar")
    public String greet;
    public String anotherMember;
    @DynamicValue(lookupName = "primitive")
    public int primitiveNumber;
    @DynamicValue(lookupName = "boxed")
    public Integer boxedNumber;

    public static void main(String[] args) {
        Application application = new Application();
        application.greet = "world";
        application.anotherMember = "Another member";
        application.primitiveNumber = 11;
        application.boxedNumber = 22;
        application.sayHello();
    }

    private void sayHello() {
        System.out.println(anotherMember);
        System.out.println("Hello " + greet);
        System.out.println(primitiveNumber);
        System.out.println(boxedNumber);
    }
}

Mofified aspect targetting int/Integer field accessors only:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;

import de.scrum_master.app.DynamicValue;

@Aspect
@Configurable
@Component
public class DynamicValueAspect {
    @Pointcut("get(* de.scrum_master.app..*) && @annotation(dynamicValue)")
    public void isDynamicValue(DynamicValue dynamicValue) {}

    @AfterReturning(pointcut = "isDynamicValue(dynamicValue)", returning = "field")
    public void getLocalized(DynamicValue dynamicValue, int field, JoinPoint thisJoinPoint) throws Throwable {
        System.out.println(thisJoinPoint);
        System.out.println("    " + dynamicValue);
    }
}

New console log:

Another member
Hello world
get(int de.scrum_master.app.Application.primitiveNumber)
    @de.scrum_master.app.DynamicValue(lookupName=primitive)
11
get(Integer de.scrum_master.app.Application.boxedNumber)
    @de.scrum_master.app.DynamicValue(lookupName=boxed)
22

BTW, I answered a similar question here.

Question:

I am attempting to use aspectJ to intercept calls to public methods on classes which implement my Loggable interface. Loggable is a marker interface and defines no methods.

I have a before advice, in which I want to get the name of the Concrete class containing the method that is being called. By using thisJoinPoint.getTarget() I can get the concrete class, but when I call thisJoinPoint.getTarget().getClass.getName() I get a stackoverflow exception.

I'm pretty sure that this is because I am calling a public method on the Concrete class, which then causes my before advice to re-fire.

Here's my pointcut :

pointcut dave() : target(Loggable) && call (public * *(..) ) ;

How do I limit this to only the public methods that are defined directly within the concrete class, ignoring those that are inherited from java.lang.Object?


Answer:

While StackOverflow is not an opinion-based discussion forum, I am going to answer with a few concrete examples in order to be a bit more explicit:

If !this(LoggerAspect) works for you, use it. But beware: It will not keep the advice from firing when a call() is indirectly, i.e. a method called by your advice, calling another method.

Option 1: use execution() instead of call()

When using an execution() pointcut, AspectJ fires only when the callee is executed, i.e. in one single place, not in many places where your callee is called by the caller. This is more efficient and in this context whould work for you because you seem to control the called code. Only if the aspect weaver/compiler does do have access to the callee, you should weave the caller using a call() pointcut.

As a side effect, executions of 3rd party library or JDK code will not be intercepted by execution() anyway because it is not accessible to the compiler/weaver with one exception being 3rd party libs (but not JDK code) woven via LTW (load-time weaving).

Option 2: adviceexecution() pointcut

By combining your pointcut with && !adviceexecution() you can stop the advice from firing when a call() is made while any advice in any of your aspects is being executed. This also excludes indirect calls and works nicely for a single advice. But if you combine multiple aspects and want your advice to still fire when a call() is made by another aspect's advice, you probably want to use another option such as...

Option 3: within() pointcut

By combining your pointcut with && !within(LoggerAspect) you can stop the advice from firing when a call() is made from within any advice in your LoggerAspect. Calls from other aspects are still being logged.

What exactly you want to achieve determines which option (or combination thereof) you should choose. There is no simple answer because I do not know your exact situation.

Question:

I have an @After java aspect that runs certain logic. I need it to return a result (an object) that can be used in the methods intercepted by the aspect's pointcut. Is it possible?


Answer:

What you need is @Around which allows you to return whatever you want to the advised object:

@Around("com.xyz.myapp.UserService.createUser()")
public Object userCreationAdvice(ProceedingJoinPoint pjp) throws Throwable {
    //Do something if needed before method execution
    Object retVal = pjp.proceed();
    //Do something if needed after method execution
    return retVal;
}

Question:

I am trying to learn AspectJ and figuring out how to retrieve specific joinpoints at certain points in a flow. My example is something like this:

I want to run an unit test annotated with JUnit's @Test then any methods called in that test that may be in another class annotated with another annotation, let's say @Example, then I could access basically the entire flow at those certain points so I had the ability to get the class name/method name of the test annotated with @Test and then also get the method information for the method annotated @Example. I've included some example code for clarification:

Test class:

public class ExampleTest {
  @Test
  public void shouldTestSomething() {
    ExampleClass exampleClazz = new ExampleClass();
    exampleClazz.something();
    // ...
  }

POJO:

public class ExampleClass {
  @Example
  public void something() {
    // do something
  end
end

So with these classes, I would like to make an aspect that would basically find any kind of @Example called within a @Test so I can then have access to both (or more) join points where I can grab the method/class signatures from the AspectJ JoinPoint object.

I tried something like this:

@Aspect
public class ExampleAspect {
  @Pointcut("execution(@org.junit.Test * *(..)) 
             && !within(ExampleAspect)")
  public void testPointCut() {}

  @Pointcut("@annotation(com.example.Example)")
  public void examplePointCut() {}

  @After("cflow(testPointCut) && examplePointCut()")
  public void doSomething(JoinPoint joinPoint) {
    System.out.println(joinPoint.getSignature());
  }
}

But the output looks like this:

void ExampleTest.ExampleClass.something()

The main issue is that it is missing the name of the test method (shouldTestSomething()) in the signature. What would be the best way to retrieve that?


Answer:

Not sure if I understand correctly, but if you need to access information about the context from where a piece of code under a join point of your interest gets called, then what you need is the thisEnclosingJoinPointStaticPart (in native AspectJ syntax). If you are using AspectJ 5 annotation style aspects, just add a parameter to your advice method with the type JoinPoint.EnclosingStaticPart.

Note that this is not available for execution() style pointcuts, only for call() style pointcuts, otherwise the JoinPoint.EnclosingStaticPart and JoinPoint.StaticPart will be the same.

This means you need to rewrite your aspect in the following way:

@Aspect
public class ExampleAspect {

    @Pointcut("execution(@org.junit.Test * *(..)) && !within(ExampleAspect)")
    public void testPointCut() {
    }

    @Pointcut("call(@com.example.Example * *(..))")
    public void examplePointCut() {
    }

    @After("cflow(testPointCut()) && examplePointCut()")
    public void doSomething(JoinPoint joinPoint, EnclosingStaticPart enclosingStaticPart) {
        System.out.println(joinPoint.getSignature() + " was invoked from "
            + enclosingStaticPart.getSignature());
    }

}

The output with your test code would be:

void q35991663.com.example.ExampleClass.something() was invoked from void q35991663.com.example.ExampleTest.shouldTestSomething()

I also rewrote your examplePointCut. The pointcut expression @annotation(com.example.Example) would mean

any join point where the subject has an annotation of type com.example.Example

which would include both execution() and call() type join points. We need only the call() join points in this case, so @annotation() isn't even necessary if you are not planning to bind the value of the annotation to the advice context.

Question:

please consider this :

public class A
{
  private B bMemeber;
  private Properties myProperties;
}

and

public class B { 
 private Object field;
 public void setField(Object o){...}
}

I have an aspect

    @After("execution(* B.setField(..)) &&! within(PropertiesAspect)")
    public void afterSetField(JoinPoint jp)
    {....}

my question is : is it possible to get the enclosing type of Busing aspectj in my afterSetField as I need to test on some properties contained in the A object


Answer:

What you want is not easily possible because it is not what AOP was made for. An instance of class B has no idea about whether it is assigned to a member of any other class or is part of any collection or array. The JVM garbage collector does reference counting for internal purposes (freeing memory after an object is no longer referenced), but this is nothing you have access to from an aspect. What you can do with AspectJ is

  • intercept whenever a value or object is assigned to a member variable (set()) pointcut) or when that member is read (get() pointcut). By the way, these pointcuts do not work for local variables, only for members. But when a method is called upon any object that happens to be assigned to a member variable, technically that variable's value does not change, it is still the same (mutable) object, i.e. a method call or an internal state change in a referenced object does not trigger set() in the referencing object, only in the referenced object itself.
  • intercept method calls or executions, which you already do.

I am not sure that what you want makes any practical sense, but what you can do with some overhead is manual reference bookkeeping like this:

  • Whenever an object of interest is assigned to a member variable, intercept it via set() pointcut and remember it by putting it into a collection maintained by the aspect.
  • By the way, at the same time you also have to remove the old member object from the collection if (and only if!) it is no longer referenced.
  • In your execution() pointcut, find out if the object in question is in the internal collection, retrieve the info about the owning object(s) from the collection and do with it whatever you like.

I hope this explanation is comprehensible even without sample code. Feel free to ask follow-up questions.

Question:

I am instrumenting a 3rd-party application - and have defined the following pointcut

@Aspect
public class MyAspect {

    @Pointcut("execution(some.app.Application.new(..))")
    public void appCreation() {
    }

    @After("appCreation()")
    public void afterCreation() {
        MyUtil.doSomething();
    }  
}

Now the problem comes from the fact that MyUtil.doSomething() eventually calls the constructor of some.app.Application - this is of course then "detected" by my aspect and MyUtil.doSomething() is called again and it calls .... you got the point.

I tried to put a && !within(MyAspect) in the Pointcut definition but it did not help. Is there any way to suppress the detection of the pointcut in the cases where MyUtil is further up the call stack?

If it is relevant: MyUtil.doSomething() is not calling the application constructor directly but after a couple of intermediate calls


Answer:

Okay, first let us reproduce your problem:

Java classes:

package de.scrum_master.app;

public class Application {
    public Application() {
        System.out.println("Creating application");
    }

    public static void main(String[] args) {
        new Application();
    }
}
package de.scrum_master.app;

public class MyUtil {
    public static void doSomething() {
        System.out.println("Doing something");
        new Application();
    }
}

Problematic aspect causing recursion:

package de.scrum_master.aspect;

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

import de.scrum_master.app.MyUtil;

@Aspect
public class MyAspect {
    @Pointcut("execution(*..Application.new(..))")
    public void appCreation() {}

    @After("appCreation()")
    public void afterCreation() {
        MyUtil.doSomething();
    }
}

Console log:

Creating application
Doing something
Creating application
Doing something
(...)
Exception in thread "main" java.lang.StackOverflowError
    at sun.nio.cs.UTF_8$Encoder.encodeLoop(Unknown Source)
    at java.nio.charset.CharsetEncoder.encode(Unknown Source)
    at sun.nio.cs.StreamEncoder.implWrite(Unknown Source)
    at sun.nio.cs.StreamEncoder.write(Unknown Source)
    at java.io.OutputStreamWriter.write(Unknown Source)
    at java.io.BufferedWriter.flushBuffer(Unknown Source)
    at java.io.PrintStream.write(Unknown Source)
    at java.io.PrintStream.print(Unknown Source)
    at java.io.PrintStream.println(Unknown Source)
    at de.scrum_master.app.MyUtil.doSomething(MyUtil.java:5)
    at de.scrum_master.aspect.MyAspect.afterCreation(MyAspect.aj:16)
    at de.scrum_master.app.Application.<init>(Application.java:6)
    at de.scrum_master.app.MyUtil.doSomething(MyUtil.java:6)
    (...)

Now how do we avoid the problem? We need to avoid executing the advice if it is already being executed, i.e. if it is in the current control flow or cflow(). For advice execution there even is a special pointcut adviceexecution().

Improved aspect avoiding infinite recursion:

package de.scrum_master.aspect;

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

import de.scrum_master.app.MyUtil;

@Aspect
public class MyAspect {
    @Pointcut("adviceexecution() && within(MyAspect)")
    public void myAdvice() {}

    @Pointcut("execution(*..Application.new(..))")
    public void appCreation() {}

    @After("appCreation() && !cflow(myAdvice())")
    public void afterCreation() {
        MyUtil.doSomething();
    }
}

Console log after correction:

Creating application
Doing something
Creating application

One final remark: So far I was not questioning your application logic. Now I am: Does it really make sense to create another application from within a utility method if one was already created? I guess that even though this was a fun AOP exercise for me, the real problem is in the Java code, not in the AspectJ code.

Question:

Given these pointcuts taken from the following resource:

http://maverick-amey.blogspot.ru/2007/12/using-cflow-and-cflowbelow-in-pointcuts.html

pointcut methodCalls() : 
                     call(public void Foo.*(..)) ;

pointcut methodCallFromWebTier() : 
                     methodCalls() && cflow(call(* com.webtier.*+.*(..)));

The methodCallFromWebTier pointcut is supposed to match all the calls made to any public method of the Foo class with any arguments which returns void provided that (the && operator) the call is inside the control flow of any call made to a method of:

  • Any class (and its subclasses) in the com.webtier package;
  • Any abstract class (its subclasses) in the com.webtier package;
  • Any interface implementation in the com.webtier package of any interface in the com.webtier package;

Now, if the pointcut would have been this instead:

pointcut methodCallFromWebTier() : 
                     methodCalls() && cflow(call(* com.webtier.*.*(..)));

Therefore without the + subtype TypePattern operator, would the pointcut be the same? I mean, it still matches everything (any class, abstract class subclass, interface implementation) provided that this everything is inside the com.webtier package, so I don't really see the usage for the + sign here...

Am I wrong? Are there some edge cases that perhaps I don't see?

Is the plus sign really necessary in this example?

Thanks for the attention!


Answer:

The plus would make a difference if you are working with types that subclass a type in the com.webtier package but are not in the com.webtier package. The plus would mean that those types would also be considered when computing cflow. If that doesn't happen in your application then the plus makes no difference.

It also makes a difference whether your Foo class is in the com.webtier package. If it is then calls to it are always in the cflow of call(* com.webtier.*+.*(..)). And if that were the situation I'd probably use cflowbelow instead of cflow.

Question:

I need to know the name of my .jar inside the aspect so I can create a string field with it via @DeclareParents.

I know I can pass things to the ajc compiler, but is it actually possible to use the passed arguments from the aspect? The end result should be classes with an additional field containing as value the name of my .jar.

UPDATE: Test of suggestion. Gson.jar is a .jar on the classpath

    InputStream r = Gson.class.getClassLoader().getResourceAsStream("META-INF/MANIFEST.MF");
    String x = getString(r);
    System.out.println(x);

Output:

Manifest-Version: 1.0

Name: org/aspectj/lang/
Specification-Title: AspectJ Runtime Classes 
Specification-Version: 1.7
Specification-Vendor: aspectj.org
Implementation-Title: org.aspectj.tools
Implementation-Version: 1.7.3
Implementation-Vendor: aspectj.org
Bundle-Name: AspectJ Runtime
Bundle-Version: 1.7.3
Bundle-Copyright: (C) Copyright 1999-2001 Xerox Corporation, 2002 Palo 
  Alto Research Center, Incorporated (PARC), 2003-2009 Contributors. 
  All Rights Reserved.

Seems like there can only be one MANIFEST.MF resource at the same time and AspectJ.jar happens to be first on the class path.


Answer:

I do not know any way to do what you want. Even if it was possible, the string values would still be the same if you unpacked the JAR and loaded the modified classes from the file system or repackaged/renamed the JAR. The solution would be static, not dynamic.

Anyway, how about putting information like that into a configuration file packaged into the JAR or maybe even right into the manifest file? Maven has capabilities to add information to the manifest and Java can read them during runtime. I have not thought it through, not to speak of trying to implement something like that, but maybe this is a way you can go.

Feel free to ask follow-up questions.


Update: You can avoid the manifest approach and try to directly determine the JAR file for each loaded class, see also this answer.

Utility class:

package de.scrum_master.util;

import java.net.URL;

public class ClassFileHelper {
    public static URL getClassURL(Class<?> clazz) {
        return clazz.getResource('/' + clazz.getName().replace('.', '/') + ".class");
    }

    public static String getJARFromURL(URL url) {
        if (!url.getProtocol().equals("jar"))
            return null;
        String fileName = url.getFile();
        fileName = fileName.substring(0, fileName.lastIndexOf('!'));
        fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
        return fileName;
    }
}

Usage:

I tried this in a Java + AspectJ project in which the aspects are wrapped in a JAR file and the Java files are stored in a file system directory. I just added the following advice to an aspect within the JAR:

before() : execution(public static void main(..)) {
    try {
        Class<?>[] classes = { String.class, this.getClass(), Class.forName("com.BadReader") };
        for (Class<?> clazz : classes) {
            System.out.println(clazz);
            URL classURL = ClassFileHelper.getClassURL(clazz);
            System.out.println(classURL);
            System.out.println(ClassFileHelper.getJARFromURL(classURL));
            System.out.println();
        }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

As you can see, the array contains

  • a JRE bootstrap class (String),
  • the aspect class itself (this.getClass()),
  • a class from the Java project outside the JAR (Class.forName("com.BadReader")).

Console output:

class java.lang.String
jar:file:/C:/Programme/Java/jre7/lib/rt.jar!/java/lang/String.class
rt.jar

class com.SafeReaderAspect
jar:file:/C:/Users/Alexander/Documents/java-src/SO_AJ_ITD2StepCompilation_AspectJ/aspectLib.jar!/com/SafeReaderAspect.class
aspectLib.jar

class com.BadReader
file:/C:/Users/Alexander/Documents/java-src/SO_AJ_ITD2StepCompilation_Java/bin/com/BadReader.class
null

Is this what you want?

Question:

So my question revolves around the use of Spring AOP with XML based schema versus using it with AspectJ. From looking around online I've been trying to figure out which approach to take for AOP. One particular scenario has me slightly confused;

Suppose I have a number of classes with n number of methods, and I want to apply advice from my aspect class to certain methods/join points but not all, I can see when using AspectJ that this would be fairly straightforward - I just apply my aspect annotation to the methods that should use the advice. However, from what I've seen of the xml based approach, I would have to create a pointcut for each of these methods (assuming they can't be covered by one expression i.e. each method has a distinct name) and (if I was using the proxy based approach) a proxy class for each target/class. The AspectJ approach seems much tidier in this sense.

So is my understanding of the two methods correct or have I missed out on some part of Spring AOP that can achieve a neater solution for the xml approach?

Sorry for the long-winded explanation, but I wanted to make the scenario as clear as possible...


Answer:

It sounds like you are trying to decide between Spring AOP and AspectJ, but you're assuming that Spring AOP requires XML-based configuration. It doesn't. You can use AspectJ annotations for both Spring AOP and AspectJ:

package com.example.app;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;

@Aspect
public class NotificationAspect {
    @Autowired private NotificationGateway notificationGateway;

    @Pointcut("execution(* com.example.app.ItemDeleter.delete(com.example.app.Item))")
    private void deleteItemOps() { }

    @AfterReturning(pointcut = "deleteItemOps() && args(item)")
    public void notifyDelete(Item item) {
        notificationGateway.notify(item, ConfigManagementEvent.OP_DELETE);
    }
}

So if you're trying to compare Spring AOP and AspectJ, it's more sensible to compare AspectJ to annotation-based Spring AOP.

Spring AOP is generally simpler (you don't need the AspectJ compiler); hence the reference docs recommend Spring AOP over AspectJ unless you need more exotic pointcuts.

UPDATE: Responding to the OP's comment below, we can use XML configuration to advise specific methods:

<aop:config>
    <aop:pointcut
        id="deleteItemOps"
        expression="execution(* com.example.app.ItemDeleter.delete(com.example.app.Item))" />
    <aop:advisor
        advice-ref="notificationAdvice"
        pointcut-ref="deleteItemOps() && args(item)" />
</aop:config>

If you want to embed the pointcut right in the <aop:advisor>, you can do that too:

<aop:config>
    <aop:advisor
        advice-ref="notificationAdvice"
        pointcut="execution(* com.example.app.ItemDeleter.delete(com.example.app.Item)) && args(item)" />
</aop:config>

(I haven't checked the && args(item) part of the XML configuration, but I think that's OK for the example I gave. If it doesn't work, try removing it and feel free to edit the answer accordingly.)

Question:

I am developing an application with Spring Boot which I want it to have all the logging going through Aspects but I am not able to make it work. I set 2 methods with @AfterThrowing and @Before, this last one as testing. The pointcuts are inspecting the packages of Controller, Services and Repositories. The issue is that neither the log nor the System.out.println() is being shown in the console.

I have tried the different solutions I have seen here but none of them worked for me. I have the right dependencies, no further configuration is needed because it is already done with Spring Boot and I even tried to use the poincuts with the annotations of the classes.

This is my package hierarchy

Spring dependecies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

LoggingAspect

package com.tlc.tracker.global.logging;

import com.tlc.tracker.global.exception.BusinessServiceException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

@Aspect
@Slf4j
public class LoggingAspect {

@Pointcut("execution(* com.tlc.tracker.v01.controller.*.*(..))")
public void controllerMethods() { }

@Pointcut("execution(* com.tlc.tracker.v01.service.imp.ProjectServiceImpl.*(..))")
public void serviceMethods(){  }

@Pointcut("execution(* com.tlc.tracker.v01.repository.*.*(..))")
public void respositoryMethods(){  }

@Before("serviceMethods()")
public void Areturn(JoinPoint point){
    System.out.println("Hola");
    log.info("HOLA");
}

@AfterThrowing(pointcut = "controllerMethods() && serviceMethods() && respositoryMethods()", throwing = "exception")
public void logAfterThrowing(JoinPoint joinPoint, Throwable exception){

    if(exception instanceof BusinessServiceException){
        //Get the parts of the exception message
        String exceptions[] = exception.getMessage().split(":", 2);
        //Get the message contained in the exception message
        String message = exceptions.length == 1 ? "" : exceptions[1];

        log.error("[" + joinPoint.getSignature().getName() + "] - Type: " + exceptions[0] + ". Message: "+ message);
    }

    if(exception instanceof Exception){
        log.error("[" + joinPoint.getSignature().getName() + "] - Type: ServerError. Message: "  + exception.getMessage());
    }
}

}

ProjectController

@RestController
@RequestMapping("/v01")
@Slf4j
public class ProjectController {

    @Autowired
    private ProjectServiceIface projectService;

    @PostMapping(path = "/project", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Project> createProject(@Valid @RequestBody Project project, BindingResult result){
        if(result.hasErrors()){
            throw new BusinessServiceException(result.getFieldError().getDefaultMessage(), result.getFieldError().getField() + " " + result.getFieldError().getCode());
        }
        Project projectSaved = projectService.createProject(project);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Location", projectSaved.getId().toString());

        return new ResponseEntity<>(project, headers, HttpStatus.CREATED);
    }
}

ProjectService

@Service
public class ProjectServiceImpl implements ProjectServiceIface {

    @Autowired
    private ProjectRepository projectRepository;

    @Override
    public Project createProject(Project project) {
        Project projectFound = projectRepository.findByName(project.getName());
        if(projectFound == null){
            throw new BusinessServiceException(Constants.FUNCTIONAL_ERROR, "The Project already exists");
        }
        project.setCreateTime(new Date());

        Project projectSaved = projectRepository.save(project);
        return projectSaved;
    }
}

ProjectRepository

public interface ProjectRepository extends CrudRepository<Project, Integer> {

    @Query(value = "SELECT * FROM Project p WHERE p.name = :projectName", nativeQuery = true)
    public Project findByName(String projectName);
}

Answer:

My guess is that your LoggingAspect class is not picked up during component scanning as it is not explicitly declared in JavaConfigor XmlConfig, and does not have a @Component annotation (and @Aspect annotations do not have this meta annotation themself).

Furthermore, the @AfterThrowing advice includes all named pointcuts using && instead of ||, stating that all the pointcuts must match (which is not possible considered they all refer to different packages).

Question:

I am using aspect oriented programming for separating logging concern in my project but while deployment I am getting following error in tomcat while deploying the application

error Cannot register 'com.temp.request.util.aspect.TraceLogger' because the type found with that name is not an aspect

TraceLogger class is as follows

package com.temp.request.util.aspect;

import java.util.Arrays;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

        public class TraceLogger {

            public Object logMethodEntryAndExit(ProceedingJoinPoint joinPoint) throws Throwable {
                LOG.trace(joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "() begins with " + Arrays.toString(joinPoint.getArgs()));
                Object result = joinPoint.proceed();
                LOG.trace(joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "() ends with " + result);
                return result;
            }
        }

I have declared aspect and TraceLogger bean in spring.xml file as follows

<bean id="TraceLogger" class="com.temp.request.util.aspect.TraceLogger" />

<aop:config>
        <aop:aspect id="methodLogger" ref="TraceLogger">
            <aop:pointcut id="logMethod"
                expression="execution(*  com.temp.request..*.*(..)) and !execution(*  com.temp.request.listener.*.*(..)) and !execution(*  com.temp.request.ws.*.*(..)) and !execution(* .util.*.*(..))" />
            <aop:around pointcut-ref="logMethod" method="logMethodEntryAndExit" />
        </aop:aspect>
</aop:config>

dependency declared in dependencies.gradle as follows

compile (
'org.aspectj:aspectjrt:1.8.4',
'org.aspectj:aspectjweaver:1.8.4',
'org.springframework:spring-instrument-tomcat:4.0.9.RELEASE'
)

Using load time weaving and specified following line in spring.xml as follows

 <context:load-time-weaver aspectj-weaving="on" weaver-class="org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver" />

Loading spring.xml by specifying contextConfigLocation in web.xml as follows

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring.xml</param-value>
</context-param>

Loading the aspect by specifying aspect name in aop.xml located in META-INF folder of my project as follows

<aspectj>
    <weaver options="-Xset:weaveJavaxPackages=true">        
        <include within="javax.jms.*"/>
    </weaver>
    <aspects>
        <aspect name="com.temp.request.util.aspect.TraceLogger" />
    </aspects>
</aspectj>

Why tomcat is not able to find TraceLogger aspect while doing load time weaving ?


Answer:

I think you are having a conceptual problem here:

  • On the one hand you want to register a normal POJO class as a Spring AOP aspect via <aop:config>.
  • On the other hand you want to use AspectJ load-time weaving via aop.xml.

Please note that AspectJ is not the same as Spring AOP, you should decide which of the two to use. I suggest to stick with Spring AOP for now and ditch the whole LTW stuff.

Looking at your Spring AOP aspect declaration <aop:aspect id="methodLogger" ref="TraceLogger"> and the error message you get, I would think that you forgot to declare a Spring bean named "TraceLogger". If an aspect is not a Spring bean/component, you cannot use it as an aspect.

I warmly recommend to read the Spring AOP manual.

If you ever reach the limits of Spring AOP and want to explore the more powerful AspectJ there also is a chapter about how to configure AspectJ via LTW. Please note that AspectJ is completely independent of Spring, you can use it inside of Spring projects or for any POJO or non-Spring container application you like, even for JVM languages other than Java.

Question:

I get the below error while adding AOP feature to my simple project can someone shed light over it for me? I also mentioned related part of the code in the following.

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.AOP.Car' available
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:346)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:337)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1123)
    at com.AOP.App.main(App.java:13)

package com.AOP;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;    
@Configuration
@ComponentScan(basePackages = "com.AOP")
public class AppConfig {        
}

package com.AOP;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App 
{
    public static void main( String[] args )
    {
        ApplicationContext context = new  AnnotationConfigApplicationContext(AppConfig.class);
        Car car =  context.getBean(Car.class);      
        car.drive();
    }
}

package com.AOP;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Car implements Vehicle{

    @Autowired
    private Tyre tyre;      
    public Tyre getTyre() {
        return tyre;
    }

    public void setTyre(Tyre tyre) {
        this.tyre = tyre;
    }

    public void drive()
    {
        System.out.println("driving a car");
        System.out.println(tyre);
    }
}

package com.AOP;

public interface Vehicle {
    void drive();

}

package com.AOP;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
@Component
@Aspect
@EnableAspectJAutoProxy
public class AOPClass {

    @After("execution(* setT*(..))")    
    public void afterAdvice2()
    {
        System.out.println("After Advise (set) start here");
    }

    @Before("execution(* drive(..))")   
    public void beforeAdvice1()
    {
        System.out.println("Before Advise (drive) start here");
    }
}

If I get a simple class "Car" without implementing the "Vehicle" interface , every thing works fine. But adding that extension will cause the menterror.


Answer:

This behavior is well described in Spring documentation. Your case is exactly:

If the target object to be proxied implements at least one interface, a JDK dynamic proxy is used.

You can still get the bean by name, and see what is its class:

    Object b = context.getBean("car");      
    System.out.println(b.getClass().getName());

It will be something like com.sun.proxy.$Proxy38, and if you try to browse its interfaces, there will be com.AOP.Vehicle among them.

At this point, it is clear why it is impossible to get the bean by class.

What to do ? There are some options:

  • Make Car do not implement Vehicle (any interface). This way, bean will be proxified by CGLIB (and its class remains unchanged), and your code will work
  • Force use CGLIB-proxies everywhere by adding following property to annotation @EnableAspectJAutoProxy(proxyTargetClass=true). Your code will work
  • Get bean by its name (see code above)
  • Get bean(s) by interface:
    Vehicle car =  context.getBean(Vehicle.class);      
    car.drive();

Question:

Say I have a pointcut on the run() method.

pointcut run(): execution(public void *.run());
before(): run() {
    // do something with run
}

But I only want to catch some instances of run. For example:

new Thread(new Runnable() {
    @Override
    public void run() {
        // this run should be intercepted
    }
});

new Timer().scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        // this run should be ignored
    }
}, 0, 1000);

How can I change my pointcut to forget about the run() that's not from a Thread?


Answer:

If you would like to advise all implementations of the Runnable.run() method except where the class providing the implementation of that run method is a subclass of TimerTask, it can be done efficiently with the following pointcut expression:

execution(public void Runnable+.run()) && !execution(public void java.util.TimerTask+.run());

Question:

I need to modify return type of a method of a legacy code using aspectj.

class MyClass{
   public void processTracker(TrackInfo trackInfo) {        
     if (isValid(this.getStatus()) {
        process(trackInfo);
     }
   }

  boolean isValid(Status status){
   ...
  } 
}

I want isValid method to return true/false by some other logic based state of TrackInfo object (which is passed parameter to processTracker method)

aspecting processTracker method will give me paramaeter but won't give option to modify return value of isValid

@Around("execution(* MyClass.processTracker(..))

aspecting isValid won't give me access to parameter trackInfo

2 aspects it's not possible as this code runs in multi-threaded... I am not using Spring and can't add custom annotation to the legacy code.

any ideas?


Answer:

Actually, your question is hard to understand, maybe because your command of English is not particularly good. In particular, I have no idea why you think that multi-threading should be any issue here. Maybe you can explain that in a little more detail.

Anyway, I am offering you two AOP solutions here:

  1. Just call process(TrackInfo) directly from the aspect if the if condition really is the whole logic in processTracker(TrackInfo), as indicated by your sample code. Semantically, you just replace the whole logic of the intercepted method.

  2. If there is in fact more logic within processTracker(TrackInfo) and your sample code was over-simplified, like a surgeon you need to cut with a finer knive and apply what in AOP terms is often referenced to as a wormhole pattern.

Application + helper classes:

Because your sample code is incomplete, I had to guess and make up an MCVE, which next time I expect you to do as it is actually your job, not mine.

package de.scrum_master.app;

public enum Status {
    VALID, INVALID
}
package de.scrum_master.app;

public class TrackInfo {
  private String info;

  public TrackInfo(String info) {
    this.info = info;
  }

  public String getInfo() {
    return info;
  }

  @Override
  public String toString() {
    return "TrackInfo(" + info + ")";
  }
}
package de.scrum_master.app;

import static de.scrum_master.app.Status.*;

public class MyClass {
  private Status status = VALID;

  public void processTracker(TrackInfo trackInfo) {
    if (isValid(getStatus()))
      process(trackInfo);
  }

  public void process(TrackInfo trackInfo) {
    System.out.println("Processing " + trackInfo);
  }

  private Status getStatus() {
    if (status == VALID)
      status = INVALID;
    else
      status = VALID;
    return status;
  }

  boolean isValid(Status status) {
    return status == VALID;
  }

  public static void main(String[] args) {
    MyClass myClass = new MyClass();
    myClass.processTracker(new TrackInfo("normal"));
    myClass.processTracker(new TrackInfo("whatever"));
    myClass.processTracker(new TrackInfo("special"));
  }
}

As you can see, I am just alternating the validity from invalid to valid and back with every call, just to get different results when running the main method.

The console log is:

Processing TrackInfo(whatever)

So far, so good. No let us assume that if the TrackInfo matches the string "special", we want to always assume the validity check evaluates to true.

1.) Aspect replacing logic of processTracker(TrackInfo)

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import de.scrum_master.app.MyClass;
import de.scrum_master.app.TrackInfo;

@Aspect
public class SimpleAspect {
  @Around("execution(* de.scrum_master.app.MyClass.processTracker(..)) && args(trackInfo) && target(myClass)")
  public void modifyValidityCheck(ProceedingJoinPoint thisJoinPoint, TrackInfo trackInfo, MyClass myClass) throws Throwable {
    if (trackInfo.getInfo().equalsIgnoreCase("special")) {
      // Kick off processing based on some special logic
      myClass.process(trackInfo);
    }
    else {
      // Proceed normally
      thisJoinPoint.proceed();
    }
  }
}

Here we do not need to know what the validity check would evaluate to but just call process(TrackInfo) directly if needed. The log output changes to:

Processing TrackInfo(whatever)
Processing TrackInfo(special)

2.) Wormhole pattern solution

Here we actually pull the TrackInfo from the calling method processTracker(TrackInfo) as context information into isValid(Status status) so we can directly modify the validity check result if necessary.

package de.scrum_master.aspect;

import static de.scrum_master.app.Status.*;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import de.scrum_master.app.Status;
import de.scrum_master.app.TrackInfo;

@Aspect
public class WormholePatternAspect {
  @Pointcut("execution(* de.scrum_master.app.MyClass.processTracker(..)) && args(trackInfo)")
  public static void processTracker(TrackInfo trackInfo) {}

  @Pointcut("execution(* de.scrum_master.app.MyClass.getStatus())")
  public static void getStatus() {}

  @Around("getStatus() && cflow(processTracker(trackInfo))")
  public Status modifyValidityCheck(ProceedingJoinPoint thisJoinPoint, TrackInfo trackInfo) throws Throwable {
    if (trackInfo.getInfo().equalsIgnoreCase("special")) {
      // Return true based on some special logic
      return VALID;
    }
    else {
      // Proceed normally
      return (Status) thisJoinPoint.proceed();
    }
  }
}

The console log is the same as with the first aspect, but if there is more logic within processTracker(TrackInfo), the rest of it would also be executed, not cut off (replaced) as in the first aspect.

Take your pick. I recommend to go with the simpler solution if applicable. The wormhole pattern is elegant but more difficult to understand and requires runtime call-stack analysis due to cflow(), thus it should be slightly slower as well.

Question:

Is it possible to intercept object method call and modify those object properties at that moment?

What I have so far

@Pointcut("execution(* java.net.HttpURLConnection.setRequestProperty(..))")
public void connectMethodCall() {
}

@Around("connectMethodCall()")
public Object onGetUrlConnection(ProceedingJoinPoint pjp) throws Throwable {
    HttpURLConnection connection = (HttpURLConnection) pjp.proceed();
    connection.setRequestProperty("header key", "header value");
    return pjp.proceed();
}

I want to at this example set connection headers and return the object to execution point. Weaving is done at compile time. I try to log headers after this but there are no headers that I have set in @Around advice. No errors are thrown either.


Answer:

The answer to your follow-up question about how to get hold of an instance of the target object is simple, if I understand the question correctly: Just use the target() parameter binding. A quick look into the AspectJ documentation would have showed you that, e.g. the part about pointcut parameters. I do believe it is much easier and less time-consuming (also with regard of having to wait for answers on SO) than asking questions here. But anyway, this is a place where developers help each other. So here we go:

Disregarding the fact that your MVCE sample code does not do anything meaningful with the Google API, let's just add one line of diagnostic output in order to verify that the aspect actually did add a request parameter:

// (...)
      urlConnection.connect();

      // Just in order to check if the property has indeed been set in the aspect
      System.out.println(urlConnection.getRequestProperty("From"));

      OutputStream outputStream = urlConnection.getOutputStream();
// (...)

Then use this aspect:

package de.scrum_master.aspect;

import java.net.HttpURLConnection;

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 MyAspect {
  @Pointcut("call(* java.net.HttpURLConnection.connect()) && target(connection)")
  public void connectMethodCall(HttpURLConnection connection) {}

  @Around("connectMethodCall(connection)")
  public Object onGetUrlConnection(ProceedingJoinPoint pjp, HttpURLConnection connection) throws Throwable {
    connection.setRequestProperty("From", "user@example.com");
    return pjp.proceed();
  }
}

Or a little bit more compact, if you do not need the poinctut to be re-useable because you only use it in one advice:

@Aspect
public class MyAspect {
  @Around("call(* java.net.HttpURLConnection.connect()) && target(connection)")
  public Object onGetUrlConnection(ProceedingJoinPoint pjp, HttpURLConnection connection) throws Throwable {
    connection.setRequestProperty("From", "user@example.com");
    return pjp.proceed();
  }
}

The console log would be:

user@example.com
false : 405

Question:

Given java.util.Timer you can do something like:

// where TimerMock extends Timer
Timer around(): call (Timer.new()) {
    return new TimerMock();
}

Is this possible to do with abstract classes? Take for example java.util.TimerTask which is an abstract class with the following signature:

public abstract class TimerTask implements Runnable {
    (...)
    public abstract void run();
}

Would it be possible to return a class that extends TimerTask?

How?


Answer:

You will have a hard time matching the join points correctly.

Let me use your initial example to explain the problems :

public aspect InterceptTimer
{
    // where TimerMock extends Timer
    Timer around(): call(Timer.new())
    {
         return new TimerMock();
    }
}

public class Test {

    public void method() 
    {
        Timer a = new Timer();
        System.out.println(a.toString());
    }
}

After the weaving AspectJ will replace Timer a = new Timer(); for something semantically equivalent to Timer a = new TimerMock(); which works fine.

However, with the abstract class, things are not so smooth. In this case, you want to replace the concrete implementations of the abstract class by your concrete class. An aspect to do that could be something like (assuming now that TimerMock extends TimerTask) :

public aspect InterceptTimer
{
    // where TimerMock extends Timer
    TimerTask around(): call(TimerTask+.new()) && !within(InterceptTimer)
    {
        return new TimerMock();
    }  
}

The "TimerTask+" makes sure you intercept all classes that extend TimerTask and "!within(InterceptTimer)" makes sure that the pointcut does not intercept the join point "new TimerMock();" which would lead to infinite recursion.

Now let's assume that you have a concrete class such that:

public class MyTimer extends TimerTask {

    @Override
    public void run() 
    {
       // ...
    }
}  

If you want to intercept the following creation:

public void method() {
    MyTimer a = new MyTimer();
    a.run();
} 

You get immediately the error: " incompatible return type applying to constructor-call(void test.MyTimer.()) "

that is because the join point "new MyTimer()" is lexically different than "TimerTask". If you could change the "new MyTimer()" join point by "new TimerTask()" it would work, however, you cannot do that since TimerTask is an abstract class.

If you try to be clever and change the "advice" to: Object around(): call(MyTask+.new()) && !within(InterceptTimer){...}

you will not get a compile error but instead a runtime error:

"java.lang.ClassCastException: test.TimerMock cannot be cast to test.MyTimer"

that is because during the weaving AspectJ will do the following: MyTimer a = (MyTimer) new TimerMock();

I do not think is possible to do what you want, at least not with that approach, maybe there is a way of doing it by exploiting the differences between "execution" and "call" join points.

Question:

I am trying to have the following logic;

  • Method within class x.b.Classy
  • Public method
  • It has at least one annotation of any type

I have been trying to use this but annotation with any type logic is failing, how do I represent class type with 100% wildcard?

@Pointcut("within(x.b.Classy) && execution(public * *(..)) && @annotation(*)")

Though getting the following;

java.lang.IllegalArgumentException: Pointcut is not well-formed: expecting 'identifier'
within(x.b.Classy) && execution(public * *(..)) && @annotation(*)
                                                               ^

How do I represent any type of annotation within my pointcut definition?


Answer:

I think that what you want is something like:

@Pointcut("within(x.b.Classy) && execution(@(*) public * *(..))")

Question:

I have problem with AspectJ. I added arguments to annotation before which Aspect will be woven and as a result it doesn't work.

Annotation interface:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Logged {
   Event event();
   System system();
}

My Aspect:

@Aspect
@Component
public class Aspect {
    @Pointcut("@annotation(Logged) && args(event, system)")
    public void invoke(Event event, System system) { }

    @Around("invoke(event, system)")
    public void aspectMethod (ProceedingJoinPoint, Event event, System system) {
        System.out.println(event + " " + system);
    }
}

Event and System are Enums.

and added annotation before some method like that:

@Logged(event = Event.USER_LOGGED, system = System.WIN)
someTestingMethod();

It works only when I leave Aspect as:

@Aspect
@Component
public class Aspect {
    @Pointcut("@annotation(Logged)")
    public void invoke() { }

    @Around("invoke()")
    public void aspectMethod (ProceedingJoinPoint) {
        System.out.println("Hey");
    }
}

I don't know how to pass arguments into Aspect with annotation.


Answer:

The basic solution is to bind the annotation:

@Aspect
class MyAspect {
    @Pointcut("execution(* *(..)) && @annotation(l)")
    public void invoke(Logged l) {}

    @Around("invoke(l)")
    public void aspectMethod (ProceedingJoinPoint pjp, Logged l) {
        java.lang.System.out.println(l.event()+" "+l.system());
    }
}

I've used the execution() pointcut to select only methods (so we want annotated methods) otherwise it will bind other users of the annotation (on fields/types/etc). As someone pointed out, args is for binding method parameters, rather than annotations.

Question:

I'm new with Spring AOP and I was wondering if it is possible to return a value from @Before to method and use this variable inside it, for example:

@Before("@annotation(CheckUserReservationPermission) && args(username,idReservation)")
public Reservation userCreationAdvice(ProceedingJoinPoint pjp, String username, Integer idReservation) throws Throwable {
    Reservation reservation = reservationServices.findById(idReservation);
    if (!reservation.getUser().getUsername().equals(username))
        throw new PermissionException("You can't delete the reservation with id: " + idReservation);
    return reservation;
}

and my method:

@Override
@CheckUserReservationPermission
public void deleteReservationById(String username, Integer idReservation) throws QueryException {
    synchronized(ReservationsSchedulerServicesImpl.class){
        databaseReservationServices.deleteReservationById(username, reservation);  
    }
}

Is there a way to make this? Otherwise I have to repeat the query. Thanks

UPDATE: With @Around I may have this code, but how can I retrieve the variable into deleteReservationById method?

@Around("@annotation(CheckUserReservationPermission) && args(username,idReservation)")
public Object userCreationAdvice(ProceedingJoinPoint pjp, String username, Integer idReservation) throws Throwable {
    Reservation reservation = reservationServices.findById(idReservation);
    if (!reservation.getUser().getUsername().equals(username))
        throw new PermissionException("You can't delete the reservation with id: " + idReservation);
    return pjp.proceed(new Object[] {reservation});
}

Answer:

Edit 2:

  1. Advice

    @Around("@annotation(CheckUserReservationPermission) && args(username,idReservation)")
    public Object userCreationAdvice(ProceedingJoinPoint pjp, DeleteByIdRequest req) throws Throwable {
        Reservation reservation = reservationServices.findById(idReservation);
        if (!reservation.getUser().getUsername().equals(username)) {
            throw new PermissionException("You can't delete the reservation with id: " + idReservation);}
    
         req.setReservation(reservation);  
        return pjp.proceed(new Object[] {req});
    

    }

2. New Request POJO

 class DeleteByIdRequest {
      Reservation reservation;
      String username;
      Integer idReservation;
    }

3.Target Method

@Override
@CheckUserReservationPermission
public void deleteReservationById(DeleteByIdRequest request) throws QueryException {
    synchronized(ReservationsSchedulerServicesImpl.class){
        databaseReservationServices.deleteReservationById(username, reservation);  
    }
}

See the interfaces of this advices,

check what they return.

1.ThrowsAdvice

public void afterThrowing(IllegalArgumentException e) throws Throwable {
}

2.AfterReturningAdvice

public void afterReturning(Object returnValue, Method method,
        Object[] args, Object target) throws Throwable {
}

3.MethodBeforeAdvice

public void before(Method method, Object[] args, Object target)
        throws Throwable {

}

4.MethodInterceptor (Around Advice)

public Object invoke(MethodInvocation methodInvocation) throws Throwable {

}

If you note in 4th point only Around advice is returning object.

you have to define the joinPoint.proceed() to control when should the interceptor return the control to the original method.

Check simple example here

EDIT: I think this can be achieved with help of proceeding with arguments Basically you can then call proceed() with the new arguments.

Question:

I've got a simple aspect that supposed to set the value of class fied, that has annotation @GuiceInject.

Originally I have this

@GuiceInject(module=RepositoryModule.class)
private IRacesRepository repository;

And I expect to get similar to this

private IRacesRepository repository = GuiceInject.getInstance(IRacesRepository.class);

And here is my aspect

public aspect InjectionAspect {

    Object around(): get(@GuiceInject * *) {
        System.out.println(thisJoinPointStaticPart);
        // instantiate object as it supposed to be null originally
        return GuiceInjector.getInstance(thisJoinPoint.getTarget().getClass());
    }
}

As far as I understand - I am new to AOP - it supposed to replace get invokations of the field with the code in aspect.

It compiles fine, but when I run the application - nothing happens. I get NullPointerException for readRaces method as it stays null so aspect did not work.

My main class looks like this

public class Example {
    @GuiceInject(module=RepositoryModule.class)
    private IRacesRepository racesRepository;

    private void execute() {
        System.out.println("List of races: " + racesRepository.readRaces());
    }

    public static void main(String[] args) {
        new Example().execute();
    }
}

What is the problem? Annotation has this definition

@Target(ElementType.FIELD)
// make annotation visible in runtime for AspectJ
@Retention(RetentionPolicy.RUNTIME)
public @interface GuiceInject {
    Class<? extends AbstractModule> module();
}

Answer:

Please try to redefine pointcut syntax as

Object around(): get(@package.subpackage.GuiceInject * *.*) 

Correct field signature must specify the type of the field, the declaring type, and name. If your annotation is in different package, it should be fully qualified.

Question:

I have written below code in controller.

For this controllerMethod method the aspectj Pointcut expression is working fine but for executeService method Aspect is not working.

@RequestMapping(value = "URL", method = RequestMethod.POST)
public ModelAndView controllerMethod(@ModelAttribute ModelAttribute reqModel, HttpServletRequest req, HttpServletResponse res) {

    try {
        response = executeService(param1, param2);

    } catch (Exception e) {

    }

    }       
private ResponseObject executeService(String param1, String param2){
    //Code....
}

I have written the aspect as below.

@Before("execution(* com.*.*.Controller.executeService(..))")
public void logBefore(JoinPoint joinPoint) {
    logger.info("Before aspect: " + joinPoint.getSignature().getName());
}

Can you please let me know where is the issues. I need to execute aspect before calling executeService method.


Answer:

Because the AOP not intercept internal call ,so you can add a self-controller field,and call the internal method by self.method(...). Following code:

@Controller
public class ExampleController{

    @Autowired
    private ExampleController self;

    @RequestMapping(value = "URL", method = RequestMethod.POST)
    public ModelAndView controllerMethod(@ModelAttribute ModelAttribute reqModel, HttpServletRequest req, HttpServletResponse res) {

        try {
            response = self.executeService(param1, param2);

        } catch (Exception e) {

        }

    }
    public ResponseObject executeService(String param1, String param2){
        //Code....
    }
}

Question:

I'd like to weave an advice on a method that is NOT part of a Spring bean (Spring Boot 1.4.4.RELEASE) :

@Component
@Aspect
...
@Around("execution(public * com.netflix.appinfo.InstanceInfo.getId())")

I added aspectjrt and spring-instrument (??) dependencies

I added @EnableAspectJAutoProxy and @EnableLoadTimeWeaving(aspectjWeaving = AspectJWeaving.ENABLED) annotations

I added VM arguments:

-javaagent:d:\.m2\repository\org\springframework\spring-instrument\4.3.6.RELEASE\spring-instrument-4.3.6.RELEASE.jar
-javaagent:d:\.m2\repository\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar

The bean is handled (postconstruct log) but the execution isn't intercepted. Does anyone has a clue on something I could miss ? Thx in advance


Answer:

Ok, here is the trick for those interested, a singleton pattern is handling access to a singleton for both LTW and Spring, so it can be injected with Spring dependencies after being weaved by LTW:

@Configuration
@Aspect
public class MyAspect {
    @Value("${mycompany.property}")
    private String myKey;

    @Around("execution(public * com.mycompany.NotASpringean.getProperty())")
    public String weave(ProceedingJoinPoint jp) throws Throwable {
        String value = (String) jp.proceed();
        // transform the value thx to injected myKey value
        return value;
    }

    @Bean("post-construct-aspect")
    public MyAspect init() {
        return MyAspect.aspectOf(); // get existing instance via factory method
    }

    private static MyAspect instance = new MyAspect();
    /** Singleton pattern used by LTW then Spring */
    public static MyAspect aspectOf() {
        return instance;
    }
}

Question:

Here are classes and xml configuration for Java/AspectJ demo project, but it fails. Project is built in eclipse. I searched on the net, added all libraries but it still fails. Any idea what might be wrong?

UPDATE: These classes were added to eclipse aspectj project: aopalliance.jar asm.jar aspectj.jar aspectjrt.jar aspectjtools.jar aspectjweaver.jar cglib.jar org.aspectj.matcher.jar

class MainApp:

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        Student student = (Student) context.getBean("student");
        student.getName();
        student.getAge();
        student.printThrowException();
    }
}

class Logging:

package com.tutorialspoint;

public class Logging {

    /**
     * This is the method which I would like to execute before a selected method
     * execution.
     */
    public void beforeAdvice() {
        System.out.println("Going to setup student profile.");
    }

    /**
     * This is the method which I would like to execute after a selected method
     * execution.
     */
    public void afterAdvice() {
        System.out.println("Student profile has been setup.");
    }

    /**
     * This is the method which I would like to execute when any method returns.
     */
    public void afterReturningAdvice(Object retVal) {
        System.out.println("Returning:" + retVal.toString());
    }

    /**
     * This is the method which I would like to execute if there is an exception
     * raised.
     */
    public void AfterThrowingAdvice(IllegalArgumentException ex) {
        System.out.println("There has been an exception: " + ex.toString());
    }
}

class Student:

package com.tutorialspoint;

public class Student {
    private Integer age;
    private String name;

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getAge() {
        System.out.println("Age : " + age);
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        System.out.println("Name : " + name);
        return name;
    }

    public void printThrowException() {
        System.out.println("Exception raised");
        throw new IllegalArgumentException();
    }
}

Beans.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">

   <aop:config>
      <aop:aspect id="log" ref="logging">
         <aop:pointcut id="selectAll" 
         expression="execution(* com.tutorialspoint.*.*(..))"/>
         <aop:before pointcut-ref="selectAll" method="beforeAdvice"/>
         <aop:after pointcut-ref="selectAll" method="afterAdvice"/>
         <aop:after-returning pointcut-ref="selectAll" 
                              returning="retVal"
                              method="afterReturningAdvice"/>
         <aop:after-throwing pointcut-ref="selectAll" 
                             throwing="ex"
                             method="AfterThrowingAdvice"/>
      </aop:aspect>
   </aop:config>

   <!-- Definition for student bean -->
   <bean id="student" class="com.tutorialspoint.Student">
      <property name="name"  value="Zara" />
      <property name="age"  value="11"/>      
   </bean>

   <!-- Definition for logging aspect -->
   <bean id="logging" class="com.tutorialspoint.Logging"/> 

</beans>

Stack trace:

Jan 19, 2017 9:43:02 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@27bc2616: startup date [Thu Jan 19 21:43:02 CET 2017]; root of context hierarchy
Jan 19, 2017 9:43:02 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [Beans.xml]
Jan 19, 2017 9:43:02 PM org.springframework.context.support.ClassPathXmlApplicationContext refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0': Cannot create inner bean '(inner bean)#aec6354' of type [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice] while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#aec6354': Cannot resolve reference to bean 'selectAll' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'selectAll': Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/tools/PointcutPrimitive
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0': Cannot create inner bean '(inner bean)#aec6354' of type [org.springframework.aop.aspectj.AspectJMethodBeforeAdvice] while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#aec6354': Cannot resolve reference to bean 'selectAll' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'selectAll': Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/tools/PointcutPrimitive
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:313)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:129)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:648)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:145)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1154)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1056)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
    at com.tutorialspoint.MainApp.main(MainApp.java:8)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#aec6354': Cannot resolve reference to bean 'selectAll' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'selectAll': Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/tools/PointcutPrimitive
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:634)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:145)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1154)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1056)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:299)
    ... 17 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'selectAll': Instantiation of bean failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/tools/PointcutPrimitive
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1116)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1060)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
    ... 25 more
Caused by: java.lang.NoClassDefFoundError: org/aspectj/weaver/tools/PointcutPrimitive
    at org.springframework.aop.aspectj.AspectJExpressionPointcut.<clinit>(AspectJExpressionPointcut.java:87)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:142)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1108)
    ... 31 more

Answer:

It's a long stack trace, but the most relevant part is the NoClassDefFoundError near the end:

Caused by: java.lang.NoClassDefFoundError: org/aspectj/weaver/tools/PointcutPrimitive at org.springframework.aop.aspectj.AspectJExpressionPointcut.(AspectJExpressionPointcut.java:87) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:142) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1108) ... 31 more

This indicates the AspectJ classes were not available to the JVM on the runtime classpath. However this application is invoked, you'll need to ensure that the aspectjweaver.jar file is on the runtime classpath. For a project managed by Maven, you could specify it as a dependency in pom.xml. Using purely Eclipse, another option would be to download aspectjweaver.jar (and all of its dependencies) and add it directly to the Eclipse project as an external library.

Question:

Trying to created a point cut which take parameter from annotation and then can use it further.So far I have reached:

pointcut callDemoAspectPointCut():
      call(Papa+.new()) && @within(MyAnnotation); //With param here

   after() returning(Object r) :callDemoAspectPointCut(){//use param here
      sysout("executed");
}

Please advice ..


Answer:

There are several kinds of annotations you can capture:

  • class annotations
  • method annotations
  • member annotations
  • method parameter annotations

Here is an example for each:

Marker annotation:

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    int id();
    String name();
}

Driver application using annotations in different places:

package de.scrum_master.app;

@MyAnnotation(id = 1, name = "class")
public class Application {
    @MyAnnotation(id = 2, name = "member")
    private String member = "foo";

    @MyAnnotation(id = 3, name = "method")
    public static void main(String[] args) {
        new Application().doSomething("blah", Math.PI);
    }

    private String doSomething(String text, @MyAnnotation(id = 4, name = "parameter") double number) {
        String returnValue = member + " " + number;
        member = text;
        return returnValue;
    }
}

Aspect capturing annotations:

Most of the pointcut/advice pairs are quite elegant. But unfortunately you need some rather ugly reflection to get hold of parameter annotations.

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aspectj.lang.SoftException;
import org.aspectj.lang.reflect.MethodSignature;

import de.scrum_master.app.MyAnnotation;

public aspect AnnotationParameterAspect {
    pointcut methodExecutionInAnnotatedClass(MyAnnotation myAnnotation) :
        @within(myAnnotation) && execution(* *(..));

    pointcut annotatedMemberReadAccess(MyAnnotation myAnnotation) :
        @annotation(myAnnotation) && get(* *);

    pointcut annotatedMemberWriteAccess(MyAnnotation myAnnotation) :
        @annotation(myAnnotation) && set(* *);

    pointcut annotatedMethodExecution(MyAnnotation myAnnotation) :
        @annotation(myAnnotation) && execution(* *(..));

    pointcut annotatedMethodParameter() :
        execution(* *(.., @MyAnnotation (*), ..));

    after(MyAnnotation myAnnotation) returning(Object returnValue) :
        methodExecutionInAnnotatedClass(myAnnotation)
    {
        System.out.println(thisJoinPoint + " -> " + returnValue);
        printAnnotation(myAnnotation);
    }

    after(MyAnnotation myAnnotation) returning(Object returnValue) :
        annotatedMemberReadAccess(myAnnotation)
    {
        System.out.println(thisJoinPoint + " -> " + returnValue);
        printAnnotation(myAnnotation);
    }

    after(MyAnnotation myAnnotation, Object newValue) :
        annotatedMemberWriteAccess(myAnnotation) && args(newValue)
    {
        System.out.println(thisJoinPoint + " -> " + newValue);
        printAnnotation(myAnnotation);
    }

    after(MyAnnotation myAnnotation) returning(Object returnValue) :
        annotatedMethodExecution(myAnnotation)
    {
        System.out.println(thisJoinPoint + " -> " + returnValue);
        printAnnotation(myAnnotation);
    }

    after() : annotatedMethodParameter() {
        System.out.println(thisJoinPoint);
        MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
        Class<?> clazz = methodSignature.getDeclaringType();
        try {
            Method method = clazz.getDeclaredMethod(methodSignature.getName(), methodSignature.getParameterTypes());
            for (Annotation[] parameterAnnotations : method.getParameterAnnotations()) {
                for (Annotation annotation : parameterAnnotations) {
                    if (annotation instanceof MyAnnotation)
                        printAnnotation((MyAnnotation) annotation);
                }
            }
        }
        catch (NoSuchMethodException nsme) {
            throw new SoftException(nsme);
        }
    }

    private static void printAnnotation(MyAnnotation myAnnotation) {
        System.out.println("  " + myAnnotation);
        System.out.println("    id   = " + myAnnotation.id());
        System.out.println("    name = " + myAnnotation.name() + "\n");
    }
}

Console log:

Please note how annotations in different places are logged along with their parameter values:

set(String de.scrum_master.app.Application.member) -> foo
  @de.scrum_master.app.MyAnnotation(id=2, name=member)
    id   = 2
    name = member

get(String de.scrum_master.app.Application.member) -> foo
  @de.scrum_master.app.MyAnnotation(id=2, name=member)
    id   = 2
    name = member

set(String de.scrum_master.app.Application.member) -> blah
  @de.scrum_master.app.MyAnnotation(id=2, name=member)
    id   = 2
    name = member

execution(String de.scrum_master.app.Application.doSomething(String, double)) -> foo 3.141592653589793
  @de.scrum_master.app.MyAnnotation(id=1, name=class)
    id   = 1
    name = class

execution(String de.scrum_master.app.Application.doSomething(String, double))
  @de.scrum_master.app.MyAnnotation(id=4, name=parameter)
    id   = 4
    name = parameter

execution(void de.scrum_master.app.Application.main(String[])) -> null
  @de.scrum_master.app.MyAnnotation(id=1, name=class)
    id   = 1
    name = class

execution(void de.scrum_master.app.Application.main(String[])) -> null
  @de.scrum_master.app.MyAnnotation(id=3, name=method)
    id   = 3
    name = method

Question:

I know you can specify code to be run in a wide variety of situations like when an exception is throw, method is executed, method is called, etc.

Is there any way that I can specify code to be run after every single line of execution of a given method?


Answer:

No. How would AspectJ know how to do that? One line of Java code can be compiled into one or multiple Java bytecode statements. And why would you want to do this anyway? Better learn how to use a debugger.

Question:

This is my situation:

I have a maven project my-project-aj-dependency composed by two jar modules:

  • my-project-aj-dependencyJarWithAJ (where I have an Inter-type declaration, see the ahah() method below inside the aspect AppWithAj_Ahah.aj)
  • my-project-aj-dependencyJarWithoutAJ

My problem is that I would like to use some declared method defined in the aspect of the first module inside the second module, but probably I missed something.

My poms configuration is the following:

Maven project pom (my-project-aj-dependency):

<?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/maven-v4_0_0.xsd">
    <name>MyProjectAjDependency</name>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.madx</groupId>
    <artifactId>my-project-aj-dependency</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <!-- <module>TestMaven-ejb</module> -->
        <module>my-project-aj-dependencyJarWithAJ</module>
        <module>my-project-aj-dependencyJarWithoutAJ</module>
    </modules>

    <properties>
        <maven.compiler.target>1.7</maven.compiler.target>
        <maven.compiler.source>1.7</maven.compiler.source>
        <aspectj.version>1.8.9</aspectj.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.madx</groupId>
                <artifactId>my-project-aj-dependencyJarWithAj</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>com.madx</groupId>
                <artifactId>my-project-aj-dependencyJarWithoutAj</artifactId>
                <version>${project.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <pluginManagement>
            <plugins>
            </plugins>
        </pluginManagement>
    </build>

</project>

Maven module 1 pom (my-project-aj-dependencyJarWithAJ):

<?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>
   <parent>
      <groupId>com.madx</groupId>
      <artifactId>my-project-aj-dependency</artifactId>
      <version>0.0.1-SNAPSHOT</version>
   </parent>
   <groupId>com.madx</groupId>
   <artifactId>my-project-aj-dependencyJarWithAJ</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>my-project-aj-dependencyJarWithAJ</name>
   <url>http://maven.apache.org</url>
   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.aspectj</groupId>
         <artifactId>aspectjrt</artifactId>
         <version>1.8.9</version>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
               <source>${java-version}</source>
               <target>${java-version}</target>
            </configuration>
         </plugin>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
               <execution>
                  <id>install</id>
                  <phase>install</phase>
                  <goals>
                     <goal>sources</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
         <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <!--
                    Have to use version 1.2 since version 1.3 does not appear to work
                    with ITDs
                -->
            <version>1.2</version>
            <dependencies>
               <!--
                        You must use Maven 2.0.9 or above or these are ignored (see
                        MNG-2972)
                    -->
               <dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjrt</artifactId>
                  <version>${org.aspectj-version}</version>
               </dependency>
               <dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjtools</artifactId>
                  <version>${org.aspectj-version}</version>
               </dependency>
            </dependencies>
            <executions>
               <execution>
                  <goals>
                     <goal>compile</goal>
                     <goal>test-compile</goal>
                  </goals>
               </execution>
            </executions>
            <configuration>
               <outxml>true</outxml>
               <source>${java-version}</source>
               <target>${java-version}</target>
            </configuration>
         </plugin>
      </plugins>
   </build>
</project>

Maven module 2 pom (my-project-aj-dependencyJarWithoutAJ):

<?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>
   <parent>
      <groupId>com.madx</groupId>
      <artifactId>my-project-aj-dependency</artifactId>
      <version>0.0.1-SNAPSHOT</version>
   </parent>
   <groupId>com.madx</groupId>
   <artifactId>my-project-aj-dependencyJarWithoutAJ</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>my-project-aj-dependencyJarWithoutAJ</name>
   <url>http://maven.apache.org</url>
   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>
   <dependencies>
      <dependency>
         <groupId>com.madx</groupId>
         <artifactId>my-project-aj-dependencyJarWithAj</artifactId>
         <version>${project.version}</version>
      </dependency>
   </dependencies>
   <build>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
               <source>${java-version}</source>
               <target>${java-version}</target>
            </configuration>
         </plugin>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
               <execution>
                  <id>install</id>
                  <phase>install</phase>
                  <goals>
                     <goal>sources</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
         <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <!--
                    Have to use version 1.2 since version 1.3 does not appear to work
                    with ITDs
                -->
            <version>1.2</version>
            <dependencies>
               <!--
                        You must use Maven 2.0.9 or above or these are ignored (see
                        MNG-2972)
                    -->
               <dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjrt</artifactId>
                  <version>${org.aspectj-version}</version>
               </dependency>
               <dependency>
                  <groupId>org.aspectj</groupId>
                  <artifactId>aspectjtools</artifactId>
                  <version>${org.aspectj-version}</version>
               </dependency>
            </dependencies>
            <executions>
               <execution>
                  <goals>
                     <goal>compile</goal>
                     <goal>test-compile</goal>
                  </goals>
               </execution>
            </executions>
            <configuration>
               <outxml>true</outxml>
               <source>${java-version}</source>
               <target>${java-version}</target>
            </configuration>
         </plugin>
      </plugins>
   </build>
</project>

Where AppWithAj.java is:

package org.my.project.aj.dependencyJarWithAJ;

public class AppWithAj {
    public static void main( String[] args ){
        System.out.println( "Hello World!" );
    }
}

and AppWithAj_Ahah.aj is:

package org.my.project.aj.dependencyJarWithAJ;

public aspect AppWithAj_Ahah {
    public String AppWithAj.ahah(){
        return "Ahahahah!";
    }
}

and finally App.java is:

package org.my.project.aj.dependencyJarWithoutAJ;
import org.my.project.aj.dependencyJarWithAJ.AppWithAj;

public class App {
    public static void main( String[] args ) {
        System.out.println( "Hello World! " + new AppWithAj().ahah());
    }
}

Answer:

Your solution is way too complicated:

  • The AspectJ (AJ) module needs the AJ Maven plugin and a dependency on aspectjrt. So far, so good.
  • But the declared aspect only affects a class within its own module, extending it via ITD. So there is no need to use the AJ compiler on the pure Java module which only calls a method from the AJ module. It is irrelevant that the called method was created by ITD, to the other module it looks just like normal Java.
  • Consequently, all the non-AJ module needs is a normal dependency on the AJ module because it uses one of its classes. The AJ runtime dependency is transitive and should be used automatically.

Update:

You asked for POMs, here they are.

Root POM:

<?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>com.madx</groupId>
    <artifactId>my-project-aj-dependency</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>MyProjectAjDependency</name>
    <packaging>pom</packaging>

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

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>${aspectj.version}</version>
                <scope>runtime</scope>
            </dependency>
            <dependency>
                <groupId>com.madx</groupId>
                <artifactId>my-project-aj-dependencyJarWithAj</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>com.madx</groupId>
                <artifactId>my-project-aj-dependencyJarWithoutAj</artifactId>
                <version>${project.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.5.1</version>
                    <configuration>
                        <source>${java.source-target.version}</source>
                        <target>${java.source-target.version}</target>
                        <!-- IMPORTANT -->
                        <useIncrementalCompilation>false</useIncrementalCompilation>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.8</version>
                    <configuration>
                        <!--<showWeaveInfo>true</showWeaveInfo>-->
                        <source>${java.source-target.version}</source>
                        <target>${java.source-target.version}</target>
                        <Xlint>ignore</Xlint>
                        <complianceLevel>${java.source-target.version}</complianceLevel>
                        <encoding>${project.build.sourceEncoding}</encoding>
                        <!--<verbose>true</verbose>-->
                        <!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn>-->
                    </configuration>
                    <executions>
                        <execution>
                            <!-- IMPORTANT -->
                            <phase>process-sources</phase>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                    <dependencies>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjtools</artifactId>
                            <version>${aspectj.version}</version>
                        </dependency>
                    </dependencies>
                </plugin>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>1.4.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

    <modules>
        <module>my-project-aj-dependencyJarWithAJ</module>
        <module>my-project-aj-dependencyJarWithoutAJ</module>
    </modules>

</project>

Module with AspectJ:

<?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>

    <parent>
        <groupId>com.madx</groupId>
        <artifactId>my-project-aj-dependency</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>my-project-aj-dependencyJarWithAJ</artifactId>

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

    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
        </dependency>
    </dependencies>
</project>

Plain Java module:

<?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>

    <parent>
        <groupId>com.madx</groupId>
        <artifactId>my-project-aj-dependency</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>my-project-aj-dependencyJarWithoutAJ</artifactId>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <configuration>
                    <mainClass>org.my.project.aj.dependencyJarWithoutAJ.App</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>com.madx</groupId>
            <artifactId>my-project-aj-dependencyJarWithAj</artifactId>
        </dependency>
    </dependencies>
</project>

Please note: I have added the Exec Maven plugin just for demo purposes, so you can do something like this:

mvn clean install
mvn -pl my-project-aj-dependencyJarWithoutAJ exec:java

Then you should see something like this on the console:

(...)
[INFO] --- exec-maven-plugin:1.4.0:java (default-cli) @ my-project-aj-dependencyJarWithoutAJ ---
Hello World! Ahahahah!

Remove Exec Maven from both the root and the plain Java POMs in order to get even shorter POMs.

Question:

Suppose I have the following recursive function

public class MyClass{
    public int foo(int arg){
        ...
    }
}

I want to throw an exception in an aspect if the initial value for arg is say 10 (it's okay for it to be afterwards). I'm new to AspectJ, but came up with the following which doesn't seem to be working.

public aspect CheckBounds{
    pointcut initialCall(int x):
        call(int MyClass.foo(int))
        && !cflow(call(int MyClass.foo(int)))
        && args(x);

    before(int x) : initialCall(x){
        if(x == 10){
            throw new IllegalArgumentException("x must not be 10");
        }
    }
}

Do you have any suggestions/recommended ways of accomplishing this?


Answer:

Firstly, your own solution cannot work because it contains a syntax error: !withincode(call(int MyClass.foo(int))) does not compile because withincode() does not take a pointcut parameter, only a signature. So it should really be: !withincode(int MyClass.foo(int)).

Secondly, I think that what you really want is similar to (but not quite exactly) your initial solution because the solution from your own answer only works for direct recursion, not indirect recursion. Here is an example:

Driver application:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        Application application = new Application();
        System.out.println("Directly recursive factorials:");
        for (int i = 0; i < 12; i++)
            System.out.printf("%2d! = %10d%n", i, application.factorial(i));
        System.out.println("\nIndirectly recursive factorials:");
        for (int i = 0; i < 12; i++)
            System.out.printf("%2d! = %10d%n", i, application.factorial_indirect(i));
    }

    public int factorial(int i) {
        return i > 1 ? i * factorial(i - 1) : 1;
    }

    public int factorial_indirect(int i) {
        return helper(i);
    }

    public int helper(int i) {
        return i > 1 ? i * factorial_indirect(i - 1) : 1;
    }
}

As you can see, factorial(int) calculates the factorial by direct recursion whereas factorial_indirect(int) does so via indirect recursion because it calls helper(int) which in turn calls the original method again. I am going to present an aspect which works for both situations, only blocking the initial call, no directly or indirectly recursive ones.

Aspect:

The original pointcut from your question was almost correct, it just should have used cflowbelow() instead of cflow().

Please note that I am not really throwing exceptions but only logging them for demo purposes so as not to interrupt the program flow.

package de.scrum_master.aspect;

import de.scrum_master.app.Application;

public aspect CheckBounds {
    pointcut factorialCall() :
        call(int Application.factorial*(int));

    pointcut initialFactorialCall(int i) :
        factorialCall() &&
        !cflowbelow(factorialCall()) &&
        args(i);

    pointcut initialFactorialCall2(int i) :
        factorialCall() &&
        !withincode(int Application.factorial*(int)) &&
        args(i);

    before(int i) : initialFactorialCall(i) {
        if (i < 1 || i == 10) {
            System.out.println(new IllegalArgumentException("x must be >=1 and != 10"));
        }
    }
}

Console log:

Directly recursive factorials:
java.lang.IllegalArgumentException: x must be >=1 and != 10
 0! =          1
 1! =          1
 2! =          2
 3! =          6
 4! =         24
 5! =        120
 6! =        720
 7! =       5040
 8! =      40320
 9! =     362880
java.lang.IllegalArgumentException: x must be >=1 and != 10
10! =    3628800
11! =   39916800

Indirectly recursive factorials:
java.lang.IllegalArgumentException: x must be >=1 and != 10
 0! =          1
 1! =          1
 2! =          2
 3! =          6
 4! =         24
 5! =        120
 6! =        720
 7! =       5040
 8! =      40320
 9! =     362880
java.lang.IllegalArgumentException: x must be >=1 and != 10
10! =    3628800
11! =   39916800

As you can see my test condition logs errors for initial values of 0 and 10 in both direct and indirect recursion cases. Now if we switch to initialFactorialCall2(i) in the before() advice, the log for the indirect case changes to:

Indirectly recursive factorials:
java.lang.IllegalArgumentException: x must be >=1 and != 10
 0! =          1
 1! =          1
 2! =          2
 3! =          6
 4! =         24
 5! =        120
 6! =        720
 7! =       5040
 8! =      40320
 9! =     362880
java.lang.IllegalArgumentException: x must be >=1 and != 10
10! =    3628800
java.lang.IllegalArgumentException: x must be >=1 and != 10
11! =   39916800

Please note the wrong reaction for 11! where an exception is also logged for the internal call of factorial_indirect(10). This is clearly wrong, so you want to go with the cflowbelow() solution instead.

Question:

I have a Spring 3 project which acts as a Rest API, and wanted to wire a spring bean I have into an unmanaged class for logging purposes.

After trying many different things, what worked was marking my unmanaged class with the annotation @Configurable.

Like:

@Configurable
public class ClassNotManagedBySpring {
     @Autowired
     @Qualifier("myBean")
     private MyBean myBean;
}

@Service("myBean")
public class MyBean {
     @Autowired
     @Qualifier("someOtherBean")
     private SomeOtherBean someOtherBean;
}

And then in my beans.xml:

<context:spring-configured/>

So now let's say that ClassNotManagedBySpring.java, is one of 6 classes that all do something similar, except 3 of them ARE managed by spring because they have the @Component annotation.

But all 6 of these classes need to @Autowire MyBean.java and only some need the @Configurable annotation.

To note, I was already previously using AspectJ in this app for multiple other purposes.

I want to know what is the risk in my spring application by all of a sudden wiring spring managed dependencies into un managed classes in this way?

Can there be performance issues? Risks of errors at runtime?

If this isn't the best way of wiring a spring managed bean into an unmanaged class, what is?


Answer:

I've been using @Configurable for years without issues, it's a very easy solution if you need app instantiated beans configured by Spring. My use cases were all in the UI tier. I also used @Configurable(preConstruction = true) whenever I needed autowired values already in the constructor. Of course, if you make millions of @Configurable objects it might be a performance issue, otherwise I wouldn't worry too much about it. The only small aesthetic problem I had was Eclipse giving me some red underlines at class definitions extending @Configurable classes, complaining that the hierarchy of class SomeClass is inconsistent, but it compiled them nevertheless, no errors in the Problems view or at runtime whatsoever.

Question:

I'm building a generic exception handler in dropwizard. I want to provide custom annotation as part of library, which will invoke a handleException method whenever exception is raised in method(method that contains annotation)

Details: Custom annotation is @ExceptionHandler

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExceptionHandler{
    Class<? extends Throwable>[] exception() default {};
}

There is a handler method handleException(Exception, Request) in class ExceptionHandlerImpl.

Now there's a business class that has method with annotation

@ExceptionHandler(exception = {EXC1,EXC2})
Response doPerformOperation(Request) throws EXC1,EXC2,EXC3{}

Now whenever EXC1 and EXC2 are raised by method doPerformOperation, I want to invoke handleException method.

I tried reading about AOP(AspectJ), Reflection, but not able to figure out the best optimal way to perform this.


Answer:

I have solved this using aspectj. I have created interface

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HandleExceptionSet {
    HandleException[] exceptionSet();
}

Where HandleException is another annotation. This is to allow array of exceptions.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface HandleException {
    Class<? extends CustomException> exception() default CustomException.class;
}

Now I have a ExceptionHandler class, which has handler. To bind a method to this annotation, I'm using below configuration in module.

bindInterceptor(Matchers.any(), Matchers.annotatedWith(HandleExceptionSet.class), new ExceptionHandler());

I use this annotation in classes, with below snippet.

@HandleExceptionSet(exceptionSet = {
        @HandleException(exception = ArithmeticException.class),
        @HandleException(exception = NullPointerException.class),
        @HandleException(exception = EntityNotFoundException.class)
})
public void method()throws Throwable {
    throw new EntityNotFoundException("EVENT1", "ERR1", "Entity Not Found", "Right", "Wrong");
}

This is working for me right now. Not sure, if this is the best approach.

Is there any better way to achieve this?

Question:

I am trying to modify the working of some code using AspectJ. The aspectJ code is of the form (Profiler.java):

public aspect Profiler {
      pointcut beforeMethod(): !within(Profiler);
      before(): beforeMethod() { /* Do something */ }
      pointcut afterMethod(): !within(Profiler);
      after(): afterMethod() { /* Do something */}
}

I am now trying to run this on the following code (Hello.java):

public class Hello {
    public static void main(String args[]) {
        for (int i = 0; i < 100; i++) {
            a(i);
        }
        System.out.println("Hello");
   }
   public static void a(int x) {
        for (int i = 0; i < 10; i++) {
            b();
        }
    }
   public static void b() {
        int j = 1;
        for (int i = 0; i < 10; i++) {
            j++;
        }
    }
}

Using ajc compiler to compile both Hello.java and Profiler.java gives me the expected result. But when I compile Profiler.java to a jar file using ajc, and try to use a javaagent, it gives a bytecode error:

Exception in thread "main" java.lang.VerifyError: Bad <init> method call from after the start of a try block

Exception Details:
  Location:
    Hello.<init>()V @55: invokespecial
  Reason:
    Error exists in the bytecode
  Bytecode:
    0000000: 2ab2 0065 0101 b800 2e3a 05b8 0034 1905
    0000010: b200 65b6 0038 00a7 0013 3a06 b800 3419
    0000020: 05b2 0065 b600 3b19 06bf 00b8 0034 1905
    0000030: b200 65b6 003b 00b7 0001 b200 622a 2ab8
    0000040: 002e 4eb8 0034 2db2 0062 b600 38b2 0028
    0000050: 2a2a b800 2e4c b800 342b b200 28b6 0038
    0000060: a700 104d b800 342b b200 28b6 003b 2cbf
    0000070: b800 342b b200 28b6 003b a700 123a 04b8
    0000080: 0034 2db2 0062 b600 3b19 04bf b800 342d
    0000090: b200 62b6 003b b1 

Any ideas what the problem is?


Answer:

I think you are hitting a variant of https://bugs.eclipse.org/bugs/show_bug.cgi?id=443477 related to weaving of the pre-initialization joinpoint. First step I'd say try using the most recent AspectJ version (you don't mention what version you are using). However, that may not fix things because the fix for 443477 related to cflow, which you aren't using. If it does still happen I'd say raise a bug against AspectJ on bugs.eclipse.org. You do have pretty wide reaching pointcuts - we don't really recommend writing pointcuts that don't use a kinded component (call/execution/get/set/etc) - without them you are hitting those preinitialization join points alongside everything else. You could exclude preinitialization by adjusting your pointcuts, that may be a workaround.

Question:

I'm trying to use AspectJ to hook calls into the Java API. For example, let's say I have an aspect for java.io.File:

import java.io.File;

aspect FileTest {
  File around(String arg0): args(arg0) && call(public File.new(String)) {
    throw new RuntimeException("Example");
  }
}

This hooks calls to the File(String) constructor just fine. However it will not do anything for the following code:

public class FileLoophole extends File {
    public FileLoophole(String filename) {
        super(filename);
    }
}

According to https://eclipse.org/aspectj/doc/next/progguide/language-joinPoints.html, I should use the execution() pointcut to handle super() calls instead. However, this doesn't work because the execution point is in the Java API, which I can't weave code into. Is there a pointcut to capture these super() callsites? Is there a way to do it without knowing about the FileLoophole class beforehand?


Answer:

You basically have two options:

  • Use the pattern File+ in order to match pointcuts including subclasses. There is no need to know their names.
  • Use AspectJ binary (post-compile) weaving and inject your aspect code directly into the JDK classes from rt.jar, creating a modified version of it or just packaging the modified JDK classes into a new JAR and prepending it to the boot classpath.

While the former approach is non-intrusive and independent of your ability to modify the JDK in your runtime environment, it is also indirect and not exactly what you asked for. The latter approach is what you asked for but probably not the thing you want to do except for very special cases.

Driver application:

package de.scrum_master.app;

import java.io.File;

public class FileLoophole extends File {
    public FileLoophole(String filename) {
        super(filename);
    }

    public static void main(String[] args) {
        new File("file.txt");
        new FileLoophole("loophole.txt");
    }
}

Aspect:

package de.scrum_master.aspect;

import java.io.File;

public aspect FileInterceptor {
    Object around(String fileName): call(File+.new(String)) && args(fileName) {
        System.out.println(thisJoinPoint + " -> " + fileName);
        return proceed(fileName);
    }

    void around(String fileName): execution(File+.new(String))  && args(fileName) {
        System.out.println(thisJoinPoint + " -> " + fileName);
        proceed(fileName);
    }
}

Console output:

call(java.io.File(String)) -> file.txt
call(de.scrum_master.app.FileLoophole(String)) -> loophole.txt
execution(de.scrum_master.app.FileLoophole(String)) -> loophole.txt

P.S.: Please note that while call(*.new(..)) returns an object, execution(*.new(..)) does not, which is why the around() advice's return type is void. These semantics are described in the AspectJ documentation.


Update: You asked about inner classes in your comment. Well, my pointcut works for static inner classes without any change. But a non-static inner class needs an instance of its surrounding class in its constructor. Check this out, I created a class + debug aspect for you:

package de.scrum_master.app;

import java.io.File;

public class Application {
    private class FileLoophole extends File {
        public FileLoophole(String filename) {
            super(filename);
        }
    }

    public static void main(String[] args) {
        new File("file.txt");
        new Application().new FileLoophole("loophole.txt");
    }
}
package de.scrum_master.aspect;

public aspect FileInterceptor {
    before() : within(de.scrum_master.app.Application) {
        System.out.println(thisJoinPoint);
    }
}

Now look at the console log:

staticinitialization(de.scrum_master.app.Application.<clinit>)
execution(void de.scrum_master.app.Application.main(String[]))
call(java.io.File(String))
call(de.scrum_master.app.Application())
preinitialization(de.scrum_master.app.Application())
initialization(de.scrum_master.app.Application())
execution(de.scrum_master.app.Application())
call(Class java.lang.Object.getClass())
call(de.scrum_master.app.Application.FileLoophole(Application, String))
staticinitialization(de.scrum_master.app.Application.FileLoophole.<clinit>)
preinitialization(de.scrum_master.app.Application.FileLoophole(Application, String))
initialization(de.scrum_master.app.Application.FileLoophole(Application, String))
execution(de.scrum_master.app.Application.FileLoophole(Application, String))

As you can see at the end of the log, an inner class's constructor is converted into something which takes the surrounding class instance as its first parameter, thus the mismatch. Now, knowing that, we can change our original pointcut in order to capture all constructors:

void around(): execution(File+.new(..)) {
    System.out.println(thisJoinPoint);
    proceed();
}

If you still want to capture the file name, it gets a little more complicated:

void around(String fileName): execution(File+.new(*, String)) && args(*, fileName) {
    System.out.println(thisJoinPoint + " -> " + fileName);
    proceed(fileName);
}

Question:

There are quite a few questions on SO regarding adding JavaFX property support to existing POJO classes. Properties for those classes can be created by using adapters in javafx.beans.property.adapter package. However, properties created in such way will not reflect changes made using setter methods of POJO classes, unless PropertyChangeSupport is added to POJO class.

Changing existing classes is sometimes not possible, and even when it is, adding PropertyChangeSupport can be extremely tedious if you have a lot of classes. So I wanted to share a way to do it which does not require changing existing classes.


Answer:

The solution is inspired by an article by Ben Galbraith, and uses AspectJ. It requires absolutely no changes to existing model classes. Installing AspectJ is beyond the scope of this tutorial, suffice to say that all major IDEs support it (installing it in Eclipse is trivial).

This example assumes that all your model classes extend a base class, called BaseEntity in this case. If your implementation differs from that, you will of course need to adapt the aspect.

First, we will create an interface which defines methods needed for PropertyChangeSupport.

package com.mycompany.myapp;

import java.beans.PropertyChangeListener;

public interface ChangeSupport {
    // Add listener for all properties
    public void addPropertyChangeListener(PropertyChangeListener listener);
    // Remove listener for all properties
    public void removePropertyChangeListener(PropertyChangeListener listener);
    // Add listener for specific property
    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener);
    // Remove listener for specific property
    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener);
    // Fire change event for specific property
    public void firePropertyChange(String propertyName, Object oldValue, Object newValue);
    // Check if property has any listeners attached
    public boolean hasListeners(String propertyName);
}

Next, we will create an implementation of that interface.

package com.mycompany.myapp;

import com.mycompany.myapp.model.BaseEntity;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class ChangeSupportImpl implements ChangeSupport {
    // Declared transient as there is no need to serialize these fields
    private transient PropertyChangeSupport propertyChangeSupport;
    private final transient Object source;

    public ChangeSupportImpl() {
        super();
        this.source = this;
    }

    // Needed for annotation-style aspect
    public ChangeSupportImpl(final BaseEntity baseEntity) {
        super();
        this.source = baseEntity;
    }

    @Override
    public void addPropertyChangeListener(final PropertyChangeListener listener) {
        // PropertyChangeSupport is loaded lazily
        if (this.propertyChangeSupport == null)
            this.propertyChangeSupport = new PropertyChangeSupport(this.source);
        this.propertyChangeSupport.addPropertyChangeListener(listener);
    }

    @Override
    public void removePropertyChangeListener(final PropertyChangeListener listener) {
        if (this.propertyChangeSupport != null)
            this.propertyChangeSupport.removePropertyChangeListener(listener);
    }

    @Override
    public void addPropertyChangeListener(final String propertyName, final PropertyChangeListener listener) {
        // PropertyChangeSupport is loaded lazily
        if (this.propertyChangeSupport == null)
            this.propertyChangeSupport = new PropertyChangeSupport(this.source);
        this.propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
    }

    @Override
    public void removePropertyChangeListener(final String propertyName, final PropertyChangeListener listener) {
        if (this.propertyChangeSupport != null)
            this.propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
    }

    @Override
    public void firePropertyChange(final String propertyName, final Object oldValue, final Object newValue) {
        if (this.propertyChangeSupport != null)
            this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
    }

    @Override
    public boolean hasListeners(final String propertyName) {
        return this.propertyChangeSupport != null && (this.propertyChangeSupport.hasListeners(propertyName)
                || this.propertyChangeSupport.hasListeners(null));
    }
}

Finally, we will create an aspect which adds PropertyChangeSupport to BaseEntity class. The aspect uses a custom class ReflectUtils to get the property's old value. You can use any utility you like, or plain old Java reflection (that may affect performance, though).

package com.mycompany.myapp;

import com.mycompany.myapp.model.BaseEntity;
import com.mycompany.myapp.util.ReflectUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareMixin;

import java.util.Objects;

@Aspect
public class BaseEntityObservabilityAspect {
    @DeclareMixin("com.mycompany.myapp.model.BaseEntity")
    public static ChangeSupport createChangeSupportImplementation(final BaseEntity baseEntity) {
        return new ChangeSupportImpl(baseEntity);
    }

    // Intercept setters in all BaseEntity objects in order to notify about property change
    @Around("this(baseEntity) && execution(public void set*(*))")
    public void firePropertyChange(final BaseEntity baseEntity,
            final ProceedingJoinPoint joinPoint) throws Throwable {
        // Get property name from method name
        final String setterName = joinPoint.getSignature().getName();
        final String property = setterName.substring(3, 4).toLowerCase() + setterName.substring(4);
        final ChangeSupport support = (ChangeSupport)baseEntity;
        if (support.hasListeners(property)) {
            // Get old value via reflection
            final Object oldValue = ReflectUtils.invokeGetter(baseEntity, property);

            // Proceed with the invocation of the method
            joinPoint.proceed();

            // New value is the first (and only) argument of this method
            final Object newValue = joinPoint.getArgs()[0];
            // Fire only if value actually changed
            if (!Objects.equals(oldValue, newValue))
                support.firePropertyChange(property, oldValue, newValue);
        } else {
            // No listeners have been registered with BaseEntity, so there is no need to fire property change event
            joinPoint.proceed();
        }
    }
}

If you cannot use annotation style for some reason, here is the same using AspectJ code style.

package com.mycompany.myapp;

import java.util.Objects;

import com.mycompany.myapp.model.BaseEntity;
import com.mycompany.myapp.util.ReflectUtils;

public aspect BaseEntityObservabilityAspect {
    declare parents: BaseEntity extends ChangeSupportImpl;

    // Intercept setters in all BaseEntity objects in order to notify about property change
    void around(final BaseEntity entity, final ChangeSupport support):
            this(entity) && this(support) && execution(public void BaseEntity+.set*(*)) {
        // Get property name from method name
        final String setterName = thisJoinPoint.getSignature().getName();
        final String property = setterName.substring(3, 4).toLowerCase() + setterName.substring(4);
        if (support.hasListeners(property)) {
            final Object oldValue;
            try {
                // Get old value via reflection
                oldValue = ReflectUtils.invokeGetter(entity, property);
            } catch (final Throwable e) {
                // Should not happen
                proceed(entity, support);
                return;
            }

            // Proceed with the invocation of the method
            proceed(entity, support);

            // New value is the first (and only) argument of this method
            final Object newValue = thisJoinPoint.getArgs()[0];
            // Fire only if value actually changed
            if (!Objects.equals(oldValue, newValue))
                support.firePropertyChange(property, oldValue, newValue);
        } else {
            // No listeners have been registered with BaseEntity, so there is no need to fire property change event
            proceed(entity, support);
        }
    }
}

Question:

I am trying to create an around advice here using LTW. The com.sample.core.Task is in a different library jar. when I try to compile, I get warning

 "advice defined in com.aop.MyAspect has not been applied [Xlint:adviceDidNotMatch]
MyAspect.java:19"

Any ideas whats the problem ? Also when I run with the javaagent, the point cut is not called. Am I missing anything ?

@Aspect
public class MyAspect {

    @Pointcut("call(* com.sample.core.Task.*(..))")
    public void callcs() {

    }

    @Around("com.test.callcs()")
    public Object myTrace(ProceedingJoinPoint joinPoint) throws Throwable {
      System.out.println("hijacked method : " + joinPoint.getSignature().getName());

      System.out.println("hijacked arguments : " + Arrays.toString(joinPoint.getArgs()));

      Object retVal = null;
      try {
           retVal = joinPoint.proceed();
      } finally {
          //do nothing
      }
      return retVal;
   }


  }

Answer:

For the load time weaving use case I don't expect the advice to apply when you compile it. With load time weaving the advice will apply when the system loads the types involved.

This means on compilation you will typically see an adviceDidNotMatch. You can suppress it by adding an annotation to the advice:

@SuppressAjWarnings("adviceDidNotMatch")

Now if it isn't applying at load-time, that is different and it is unrelated to the warning there. As Hakan comments, you don't need to qualify your pointcut, it should be @Around("callcs()"). With load time weaving I might turn on the showWeaveInfo option in the aop.xml to see if the pointcut/advice is matching.

Question:

I was reading about caching mechanism and created a sample project of EhCache using SpringCaching with AspectJ and benchmark it against google cache using SpringCaching with AspectJ. What i found, is bit surprising to me.

Note:- Spring Caching I meant, methods are annotated with @Cacheable/@Caching annotations.

SpringCaching with AspectJ is fater but on the other hand google cache with AspectJ performs slower. Below are mean of the times they took to process requests:-

GoogleCacheWithoutAspect 
1.262323232 ms

GoogleCacheWithAspect
5.205010101 ms

SpringCachingWithoutAspect
3.08548 ms

SpringCachingWithAspect
2.77782 ms

As i'm newbie, so i'm also wanted to confirm, why should one use AspectJ with Spring Caching, how does AspectJ make caching faster.

I also follow the below post, but still not sure, does AspectJ really improves the caching performance. http://architects.dzone.com/articles/cacheable-overhead-spring-0


Answer:

still not sure, does AspectJ really improves the caching performance

The figures from the article clearly show that AspectJ is far superior (and on eye-level with or even better than manual caching) regarding runtime overhead in comparison to Spring AOP. This is because:

  • Spring uses dynamic proxies (i.e. subclasses or interface implementations dyamically created during runtime) and always introduces call chaining due to each call being routed through a proxy in order to implement AOP interception behaviour. This is true for Java dynamic proxies (used for interfaces) as well as CGLIB proxies (used for classes).
  • AspectJ does not need any proxies because it is weaving optimised code directly into the original classes via bytecode instrumentation. This is done during compile-time or optionally once per JVM start-up during class-loading. This is fast and efficient.

Question:

I am facing a problem while implementing concrete aspect in aspectJ. Below are the related code snippets. I have two abstract aspects - FieldAspect.java and AbstractTracing.java. I am defining concrete aspects in xml - ConcreteTracingimpl and MyFieldAspect and this is not by code. In Main.java, I am calling Test.getTestMethod() and so, before calling this method, as @method is annotated, around advice in AbstractTracing.java gets applied but AbstractTracing.java has also a static field annotated with @field annotation and hence, the field should be initialized with the value andy but it is null.

If an abstract aspect contains fields with annotations and these fields are applicable for load time weaving, how this should be implemented ? Please guide me. Many thanks.

AbstractTracing.java

package main.java.aop.extend;
import main.java.aop.field.Field;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;. 
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public abstract class AbstractTracing {

@Field
static String x;

@Pointcut
public abstract void trace();

@Around("trace()")
public void traceMethod() {
    System.out.println("In trace method of AbstractTracing class : " + x);
 }   

}

FieldAspect.java

package main.java.aop.field;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public abstract class FieldAspect {
@Pointcut
public abstract void getField();

@Around("getField()")
public String getFieldValue() {     
    return "Andy";
 }  
}

aop.xml

<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
<aspects>
<concrete-aspect name="main.java.aop.extend.ConcreteTracingimpl"
        extends="main.java.aop.extend.AbstractTracing">
        <pointcut name="trace"
            expression="execution(@main.java.aop.method.Method * * (..))" />
    </concrete-aspect>
<concrete-aspect name="main.java.aop.field.MyFieldAspect"
        extends="main.java.aop.field.FieldAspect">
        <pointcut name="getField" expression="get(@main.java.aop.field.Field * *)" />
    </concrete-aspect>
<weaver options="-verbose -showWeaveInfo" />
</aspectj>

Field.java

package main.java.aop.field;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Field {
}

Method.java

package main.java.aop.field;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Method {
}

Main.java

package main.java.aop.main;

import main.java.aop.extend.Test;

public class Main {

public static void main(String[] args) {

    System.out.println("<---------- EXTENDS example ---------->");
    Test.testMethod();
 }
}

Test.java

package main.java.aop.extend;

import main.java.aop.method.Method;

public class Test {

@Method
public static void testMethod() {
    System.out.println("calling test method in test class");
 }
}

Answer:

Interesting situation, looks like an AspectJ bug. From what I can see the abstract aspects themselves are not being passed to the weaver for weaving. We can see that if you turn on the additional flag in weaver options (-debug):

[AppClassLoader@58644d46] info AspectJ Weaver Version 1.8.4 built on Thursday Nov 6, 2014 at 20:19:21 GMT
[AppClassLoader@58644d46] info register classloader sun.misc.Launcher$AppClassLoader@58644d46
[AppClassLoader@58644d46] info using configuration /Users/aclement/play/sridhar/META-INF/aop.xml
[AppClassLoader@58644d46] info define aspect main.java.aop.extend.ConcreteTracingimpl
[AppClassLoader@58644d46] info define aspect main.java.aop.field.MyFieldAspect
[AppClassLoader@58644d46] debug weaving 'main.java.aop.extend.ConcreteTracingimpl'
[AppClassLoader@58644d46] debug generating class 'main.java.aop.extend.ConcreteTracingimpl'
[AppClassLoader@58644d46] debug weaving 'main.java.aop.field.MyFieldAspect'
[AppClassLoader@58644d46] debug generating class 'main.java.aop.field.MyFieldAspect'
[AppClassLoader@58644d46] debug weaving 'main.java.aop.main.Main'
[AppClassLoader@58644d46] weaveinfo Join point 'field-get(java.lang.String main.java.aop.extend.AbstractTracing.x)' in Type 'main.java.aop.main.Main' (Main.java:11) advised by around advice from 'main.java.aop.field.MyFieldAspect' (FieldAspect.java:7)
<---------- EXTENDS example ---------->
[AppClassLoader@58644d46] debug weaving 'main.java.aop.extend.Test'
[AppClassLoader@58644d46] weaveinfo Join point 'method-execution(void main.java.aop.extend.Test.testMethod())' in Type 'main.java.aop.extend.Test' (Test.java:8) advised by around advice from 'main.java.aop.extend.ConcreteTracingimpl' (AbstractTracing.java)
[AppClassLoader@58644d46] debug generating class 'main.java.aop.extend.Test$AjcClosure1'
[AppClassLoader@58644d46] debug cannot weave 'org.aspectj.lang.NoAspectBoundException'
In trace method of AbstractTracing class : null

Now why it isn’t being passed to the weaver, good question. Possibly it is the re-entrancy guards that are in place to stop the weaver entering itself once already doing something.

However, I’ve changed things a little and can get it to work, I use a special feature that is hidden in one of the release READMEs. When you have aspects like you have you can actually define the whole aspect in the XML and just use the code to hold the behavior, you don’t need any aspect annotations. So if I rewrite your abstract aspects like this:

package main.java.aop.field;

class FieldAspect {
  static String getField() {
    return "Andy";
  }
}

package main.java.aop.extend;

public class AbstractTracing {

  @Field
  public static String x;

  public static void traceMethod() {
    System.out.println("In trace method of AbstractTracing class : " + x);
  }   

}

Then this aop.xml:

<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
<aspects>

  <concrete-aspect name="main.java.aop.field.MyFieldAspect">
    <around pointcut="get(@main.java.aop.field.Field * *)" invokeClass="main.java.aop.field.FieldAspect" invokeMethod="getField()"/>
  </concrete-aspect>

  <concrete-aspect name="main.java.aop.extend.ConcreteTracingImpl">
    <around pointcut="execution(@main.java.aop.method.Method * *(..))" invokeClass="main.java.aop.extend.AbstractTracing" invokeMethod="traceMethod()"/>
  </concrete-aspect>

</aspects>
<weaver options="-verbose -showWeaveInfo" />
</aspectj>

(The documentation on this feature is here: http://www.eclipse.org/aspectj/doc/released/README-1612.html )

Now when I run it

[AppClassLoader@58644d46] info AspectJ Weaver Version 1.8.4 built on Thursday Nov 6, 2014 at 20:19:21 GMT
[AppClassLoader@58644d46] info register classloader sun.misc.Launcher$AppClassLoader@58644d46
[AppClassLoader@58644d46] info using configuration /Users/aclement/play/sridhar/META-INF/aop.xml
[AppClassLoader@58644d46] info define aspect main.java.aop.field.MyFieldAspect
[AppClassLoader@58644d46] info define aspect main.java.aop.extend.ConcreteTracingImpl
<---------- EXTENDS example ---------->
[AppClassLoader@58644d46] weaveinfo Join point 'method-execution(void main.java.aop.extend.Test.testMethod())' in Type 'main.java.aop.extend.Test' (Test.java:8) advised by around advice from 'main.java.aop.extend.ConcreteTracingImpl' (no debug info available)
[AppClassLoader@58644d46] weaveinfo Join point 'field-get(java.lang.String main.java.aop.extend.AbstractTracing.x)' in Type 'main.java.aop.extend.AbstractTracing' (AbstractTracing.java:13) advised by around advice from 'main.java.aop.field.MyFieldAspect' (no debug info available)
In trace method of AbstractTracing class : Andy

You can see the join points in the 'abstract aspects' are being woven this time. However, the constraints on the code you point to from the XML (i.e. that the methods need to be static) - I don’t know if that is ok for you or not? The problem you found is definitely a bug (please raise it), I just offer this alternative way of expressing aspects as a workaround.

Question:

I have a problem quite similar to: How to create an aspect on an Interface Method that extends from A "Super" Interface, but my save method is in an abstract super class.

The structure is as follows -

Interfaces:

public interface SuperServiceInterface {
    ReturnObj save(ParamObj);
}

public interface ServiceInterface extends SuperServiceInterface {
    ...
}

Implementations:

public abstract class SuperServiceImpl implements SuperServiceInterface {
    public ReturnObj save(ParamObj) {
        ...
    }
}

public class ServiceImpl implements ServiceInterface extends SuperServiceImpl {
    ...
}

I want to inspect any calls made to the ServiceInterface.save method.

The pointcut I have currently looks like this:

@Around("within(com.xyz.api.ServiceInterface+) && execution(* save(..))")
public Object pointCut(final ProceedingJoinPoint call) throws Throwable {
}

It gets triggered when the save method is put into the ServiceImpl, but not when it is in the SuperServiceImpl. What am I missing in my around pointcut?


Answer:

I just want to pointcut on the ServiceInterface, if I do it on SuperServiceInterface wouldn't it also intercept save calls on interfaces that also inherit from SuperServiceInterface?

Yes, but you can avoid that by restricting the target() type to ServiceInterface as follows:

@Around("execution(* save(..)) && target(serviceInterface)")
public Object pointCut(ProceedingJoinPoint thisJoinPoint, ServiceInterface serviceInterface)
    throws Throwable
{
    System.out.println(thisJoinPoint);
    return thisJoinPoint.proceed();
}

Question:

I am attempting to use AspectJ AOP to intercept a call to a Spring Batch Step execution and advise on what file to log into.

Following the configuration in this example, my pointcuts look like this:

@Before("execution(* org.springframework.batch.core.Step.execute(..)) && " + "args(stepExecution)")
public void setupLogging(Object stepExecution) {...}

@After("execution(* org.springframework.batch.core.Step.execute(..))")
public void tearDownLogging() {...}

Using the following test (and a similar one for when I tear down my logging), the pointcuts match, but do not seem to work when I try deploying them.

@Test
    public void testSetupLoggingMatcher() throws NoSuchMethodException, SecurityException {
        java.lang.reflect.Method method = LoggingAspect.class.getMethod("setupLogging", Object.class);
        Annotation[] annotations = method.getDeclaredAnnotations();

        boolean matched = false;
        for (Annotation annotation: annotations) {
            if (annotation.annotationType() == org.aspectj.lang.annotation.Before.class) {
                org.aspectj.lang.annotation.Before beforeAnnotation = (org.aspectj.lang.annotation.Before) annotation;
                String pointcutstring = beforeAnnotation.value();
                PointcutParser pointcutParser =
                        PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
                Collection<PointcutParameter> parameters = new ArrayList<PointcutParameter>();
                parameters.add(new PointcutParameter() {

                    @Override
                    public Class getType() {
                        return StepExecution.class;
                    }

                    @Override
                    public String getName() {
                        return "stepExecution";
                    }

                    @Override
                    public Object getBinding() {
                        return mockStepExecution;
                    }
                });
                PointcutExpression pointcut =
                        pointcutParser.parsePointcutExpression(pointcutstring, LoggingAspect.class,
                                parameters.toArray(new PointcutParameter[0]));
                ShadowMatch match = pointcut.matchesMethodExecution(Step.class.getMethod("execute", StepExecution.class));
                matched = matched || match.alwaysMatches();
            }
        }
        assertTrue("No pointcuts on setupLogging matched Step.execute(StepExecution.class)", matched);
    }

I have verified that my pointcuts match the Step interface and that my Aspect is being initialized in the ApplicationContext. However, the pointcuts are not getting triggered when I try to run a job. Why does this occur? Is there any way to fix it?


Answer:

Your execution() pointcut matches method calls with an arbitrary number of arguments. Thus, you need to tell args() the position at which parameter stepExecution is to be found in relation to the others in order to make it match methods with more than one parameter, e.g.

  • 1st parameter: args(stepExecution, ..)
  • 2nd parameter: args(*, stepExecution, ..)
  • 3rd parameter: args(*, *, stepExecution, ..)
  • last parameter: args(.., stepExecution)

Question:

This is my first post on stackoverflow... Well here it goes. I have a custom spring AOP annotation which works fine for this method

@testInterceptor
public MyObjList getMyObjList( List qlist,Context cntxt){
//some processing
List<MyObj> myObjList= getMyObjs(qlist,cntxt);
//Some more processing
return myObjList;
}


public List<MyObj> getMyObjs( List qlist,Context cntxt){ 
List<MyObj> myObjList= new ArrayList<MyObj>(); 
//Some more processing 
return myObjList; 
}

I realized that this annotation should actually be at the getMyObjs() method. So I moved the annotation to the getMyObjs() but for some reason now the aspect is not being applied. I have no idea why.

@testInterceptor
public List<MyObj> getMyObjs( List qlist,Context cntxt){ 
List<MyObj> myObjList= new ArrayList<MyObj>(); 
//Some more processing 
return myObjList; 
}

Answer:

Due to how Spring uses AOP, in order for @testInterceptor to work on getMyObjs, that method needs to be called from outside the class. Calling it from getMyObjList will not get the interceptor involved.

Check out this blog post for more details.

To clarify what I above with an example:

Let's say you have another class

class Foo {

   @Autowired
   private MyObjList myObjList; 

   //this will invode the interceptor
   public void willWork() {
     myObjList.getMyObjs();
   }

   public void willNotWork() {
     myObjList.getMyObjList(); //will not invoke interceptor since `getMyObjs` is being invoked from inside the class that it's defined
   }

}

Question:

After following so many search results on google on this subject, my Aspect doesn't work still on my spring boot application

I am using spring boot version 2.1.6, which seem to have already spring aop, aspectjweaver and aspectjrt (stand to be corrected). i created an annotation, aspect component and use my annotation on a target class with no success.

here is my annotation class

    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;

    import static java.lang.annotation.ElementType.*;
    import static java.lang.annotation.RetentionPolicy.RUNTIME;

    @Retention(RUNTIME)
    @Target({TYPE, METHOD})
    public @interface AopAudit {
    }

my aspect class

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

    @Aspect
    @Component
    public class AuditAnnotationAspect {
        @Before("execution(* com.rainestech.hrm.modules.settings.entity.ABC.set*(..))")
        public void before(JoinPoint joinPoint) {
    System.out.println("Audit Works!!! = ");
        }
    }

class ABC

@Entity
@AopAudit
public class ABC {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @NotEmpty
    @NotNull
    @Column
    private String name;

    //... getters and setters
}

configuration class

@Configuration
@EnableWebSecurity
@EnableAspectJAutoProxy
public class WebSecurity extends WebSecurityConfigurerAdapter {

}

running the application and running set method on class ABC produce no effect whereas i expect to see Audit Works in the console


Answer:

First, make sure your pom.xml contains all of these:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.2.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
</dependencies>

<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>

Second, annotate your configuration with @EnableAspectJAutoProxy, this will enable it.

Third, make sure you update your pointcut:

@Pointcut("@annotation(com.path.to.your.annotation.AopAudit)")
private void auditable() {}

And then use it in your @Before.

@Before("auditable()")

Question:

When i try to use:

@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)

transaction not working, but if i use

@EnableTransactionManagement(mode = AdviceMode.PROXY)

everything works fine.

My code:

SpringBootAplication

@SpringBootApplication
@EnableScheduling
@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
public class SpringBootAplication
{
    private static ConfigurableApplicationContext applicationContext;


    public static void main(String[] args)
    {              System.out.println(InstrumentationLoadTimeWeaver.isInstrumentationAvailable());
        applicationContext = SpringApplication.run(SpringBootAplication.class, args);
    }

Controller

@RestController
public class MyController
{
    @Autowired
    MyRepository repository;

    @Transactional
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public void test()
    {
        repository.findById("name");
        System.out.println(TransactionAspectSupport.currentTransactionStatus());
    }
}

Also i have a VM options: -javaagent:"spring-instrument-5.1.2.RELEASE.jar" for ASPECTJ.

And this is exception which i accept when try to get current transaction.

org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope

Also my depend

implementation('org.springframework.boot:spring-boot-starter-data-jpa')
implementation('org.springframework.boot:spring-boot-starter-thymeleaf')
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation("org.springframework.boot:spring-boot-starter-websocket")
implementation('org.springframework.boot:spring-boot-starter-security')
implementation("org.springframework.boot:spring-boot-devtools")

Answer:

Adding aspectjweaver.jar agent like this: -javaagent:/path/to/aspectjweaver.jar should solve your problem.

Question:

I would like to intercept all constructor invocations where the class is annotated with a specific annotation.

I have an aspect like this:

@Aspect
public class ConstructorClassLevelAspect {
  @Before(
      "execution(*.new(..)) && @annotation(ConstructorClassLevel)")
    public void doConstructorClassLevel(
      JoinPoint point) throws Throwable {
    System.out.println("constructed" + point);
  }
}

And an instance:

@ConstructorClassLevel
public class ConstructorClassLevelExample {

}

Now, if I change the aspect and remove the @annotation filter, then I see aspectj is intercepting the call. Additionally, if I create a default constructor, then annotate it with the annotation, it also works.

But, I want the annotation to live on the class so that if I have 1 constructor or 10, they'll all be intercepted the same (and I only have to put it on the class).


Answer:

It seems that if I do @within(ConstructorClassLevelExample), it works!

Question:

I'm new to AspectJ. Was able to create a simple JUnit and Aspect classes to log ThreadId, which logs Parent Thread Id. But I'm not able to figure out how to log Child ThreadId.

Given the following snippet of code, I'd like to log Thread Id of both parent and child using AspectJ.

JUnit:

@Test
public void testExecutorService() {
    ExecutorService service = Executors.newSingleThreadExecutor();
    Runnable task = new Runnable() {
        @Override
        public void run() {
            System.out.println("working on the task");
        }
    };
    service.submit(task);
}

Aspect: The following aspect logs Parent ThreadId.

before() :
    call(* ExecutorService+.submit(..))
 {
    System.out.println("Parent Thread Id: "+Thread.currentThread().getId());
    //System.out.println("Child Thread Id: "+??); //?? - how to capture child thread id?
 }

I understand that it is using "before" advice here and also it is intercepting submit method, which might be an issue as well. How can I log child Thread Id along with Parent Thread Id using correct Pointcut expression? Thank you.


Answer:

What you can do is to intercept the task parameter of the submit and enhanced that task to print what you want:

Object around(Runnable task) : call(* ExecutorService+.submit(Runnable, ..)) && args( task)
{
    final long parentID = Thread.currentThread().getId();
    Runnable newTask =  new Runnable() {
        Runnable newTask =  () -> {
            System.out.println("Parent Thread Id: "+ parentID);
            System.out.println("Child Thread Id: "+Thread.currentThread().getId()); //?? - how to capture child thread id?
            task.run();
        };
    return proceed(newTask);
}

As soon as the asynchronous task is executed the id of the thread executing it will be print.

Question:

Here's my code:

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

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

@Around("cutPointToken()")
public Object authenticateToken(ProceedingJoinPoint joinPoint) throws Throwable {
    LOGGER.info("authenticate -- start --");
    ...
    Object o = joinPoint.proceed();
    LOGGER.info("authenticate -- end --");
    return o;
}

@Around("cutPointEmptyParam()")
public Object checkParameter(ProceedingJoinPoint joinPoint) throws Throwable {
    LOGGER.info("check param -- start --");
    ...
    Object o = joinPoint.proceed();
    LOGGER.info("check param -- end --");
    return o;
}

I got:

authenticate -- start --
check param -- start --
...
check param -- end --
authenticate -- end --

Expected:

check param -- start --
authenticate -- start --
...
authenticate -- end --
check param -- end --

How can I change the executing order of those two methods?

Tried @Order annotation, @Order(1) on the checkParameter method, and @Order(2) on the other, but it doesn't work.


Answer:

The idea of using @Order annotation is correct, however, place it on the class level as the documentation 7.2.4.7 Advice ordering states.

This is done in the normal Spring way by either implementing the org.springframework.core. Ordered interface in the aspect class or annotating it with the Order annotation.

The placement on the methods annotated with @Aspect will not work since it is not registered as a bean. Find @Order annotation in 1.9.2. @Autowired section.

The @Order annotation may be declared at target class level but also on @Bean methods...

@Aspect
@Order(1)
public class CheckParameterAspect {

    @Around("cutPointEmptyParam()")
    public Object checkParameter(ProceedingJoinPoint joinPoint) throws Throwable {
        //...
    }
}

@Aspect
@Order(2)
public class AuthenticateTokenAspect {

    @Around("cutPointToken()")
    public Object authenticateToken(ProceedingJoinPoint joinPoint) throws Throwable {
        //...
    }
}

Edit: The ordering from 0 seems to be possible.

Question:

My test framework uses selenium's PageFactory and Lambok. I want to write an aspect to capture all the web elements that a test flow comes across while running.

A typical page looks like:

@Slf4j
public class MyCustomPage {

    @Inject
    private IWebDriverSet driverSet;

    @Getter
    @FindBy(id = PAGE_ROOT)
    private WebElement root;

    @FindAll({
            @FindBy(css = FOOT_BAR),
            @FindBy(css = FOOT_BAR_B)
    })
    private WebElement navBar;
}

@FindBy determines the webelement that tests deal with. There are 50 of such pages.

The webElement fields are instantiated (assigned with a WebElement instance corresponding to the value in @FindBy) when the page is instantiated using the PageFactory.

I would like to capture these webElements that are annotated with @FindBy/@FindAll as soon as they are instantiated. I dont want to write a separate pointcut for every page class. How to do that?


Answer:

Since value of a WebElement assigned via reflection you can't intercept that with set() pointcut designator. But you can track all calls to java.lang.reflect.Field.set

    @After("call(* java.lang.reflect.Field.set(..)) && args(obj, value) && target(target)")
    public void webelementInit(JoinPoint jp, Object obj, Object value, Field target) {
        //obj - instance of a class (page object) that declares current field
        //value - new field value (instantiated WebElement)
        //field - current field
        //you can filter calls to the fields you need by matching target.getDeclaringClass().getCanonicalName() with page object's package
        //for example:
        //if(target.getDeclaringClass().getCanonicalName().contains("com.example.pageobjects")) {
            //do stuff
        //}
    }

In that case you need to define rt.jar in dependencies section in your pom.xml

<dependencies>
        <dependency>
            <groupId>java</groupId>
            <artifactId>jre-runtime</artifactId>
            <version>1.8</version>
            <scope>system</scope>
            <systemPath>${java.home}/lib/rt.jar</systemPath>
        </dependency>
...
</dependencies>

and in weaveDependencies section of aspectj-maven-plugin

<weaveDependencies>
    <weaveDependency>
        <groupId>java</groupId>
        <artifactId>jre-runtime</artifactId>
    </weaveDependency>
...
</weaveDependencies>

Question:

I have a requirement where in I need to time various method calls into a time series db.

For the same, I have created 2 annotations one for the method call:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable {

    String event();
    String entity();
}

and another one for a field

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Id {
   String id();
}

The reason I need the @ID annotation is that, the id field to be pushed to influx db would be known only at run time.

So, in my method, something like this would happen:

@Id
String key;

@Auditable(event="xxx",entity="yyy")
public void methodToBeIntercepted(){
   String key = <logic to generate key>;
}

The idea that I wanted to use was add an annotation advice along with a field set advice.

@After("@annotation(auditable) && (set(@<package>.ID java.lang.String sample..*.*) && args(id))")
public void pointcutMethod(Auditable auditable,String id){
}

But the flow is never entering into the pointCutMEthod. If I change the condition to || above, then it enters but it clearly suggests that only 1 condition would be true at any given point of time.

What is it that I am doing wrongly here?


Answer:

Your analysis is correct: The advice will never trigger. It just cannot because the two pointcuts you combine are mutually exclusive: Where @Auditable is (method call or execution) is a different joinpoint from set(). What you intend to express is the following: "Intercept member variable assignment within the control flow of a method execution." I.e. you need cflow(@annotation(auditable)).

Annotations and driver application:

package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Id {
  String id();
}
package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable {
  String event();
  String entity();
}
package de.scrum_master.app;

public class Application {
  @Id(id = "my ID")
  String key;

  public static void main(String[] args) {
    Application application = new Application();
    application.methodToBeIntercepted();
  }

  @Auditable(event = "xxx", entity = "yyy")
  public void methodToBeIntercepted() {
    key = "I am the key";
  }
}

Aspect:

package de.scrum_master.aspect;

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

import de.scrum_master.app.Auditable;

@Aspect
public class MyAspect {
  @After("cflow(@annotation(auditable)) && set(@de.scrum_master.app.Id String de.scrum_master..*.*) && args(id)")
  public void pointcutMethod(JoinPoint thisJoinPoint, Auditable auditable, String id) {
    System.out.println(thisJoinPoint);
    System.out.println("  " + auditable);
    System.out.println("  " + id);
  }
}

Console log:

set(String de.scrum_master.app.Application.key)
  @de.scrum_master.app.Auditable(event=xxx, entity=yyy)
  I am the key

Question:

I have an aspect intercepting the logging method. That logging method is a simple method taking one object as an argument:

logMessage(Object message)

How can I modify that object in my aspect and log a new one? Following does not work:

void around() : execution(* com.test.logMessage(..)) {
    String message = thisJoinPoint.getArgs()[0].toString();
    String pattern = "abc";
    String replacement = "xyz";

    message = message.replaceAll(pattern, replacement);
    proceed(message);
}

I'm getting ajc: too many arguments to proceed, expected 0 error.


Answer:

The proceed method takes an object array as argument. You should be able to resolve your issue by calling it like this :

Object[] args = new Object[] { message };
proceed(args);

Question:

I am trying to implement an aspect to time method execution for NIO.

Basically, I need to get the time when a method is initially called and then when a callback is triggered (the callback is always either a failed() or succeeded() call - so I need to associate the initial method call with the appropriate callback.

I have the following implementation but it will not work unless calls are made serially which of course will not be the case.

Any help would be great

public aspect TimerAJ {
    private long timer = 0;
    private String methodName;
    private static Logger logger = LoggerFactory.getLogger(TimerAJ.class);

    //the call to the call back method
    pointcut timerCall1() : target(io.vertx.core.AsyncResult) && (call( * io.vertx.core.AsyncResult.failed(..)) || call( * io.vertx.core.AsyncResult.succeeded(..)));

    //the call to the method itself
    pointcut timerCall2() : execution(@Timer * *(..));

    before() : timerCall2() {
        timer = System.currentTimeMillis();
        methodName = methodSignature.getName();
    }
    after() : timerCall1() {
        logger.info(methodName + " " + String.format("%s took %d ms", thisEnclosingJoinPointStaticPart.getSourceLocation().getWithinType().getName(), (System.currentTimeMillis() - timer)));
    }
}

Answer:

You need to reconsider this approach, as it simply won't work with Vert.x.

What you try to do is start counting when your @Timer method is called, and stop counting when any AsyncResult is returned.

What you can do: use vertx.eventBus().publish() to send start/stop metrics. Use another Verticle to gather metrics with vertx.eventBus().consumer() and display them.

Also, please take a look at Vert.x Dropwizard Metrics. If all you want is actual statistic, they'll provide it for you, without much implementation from your side.

Question:

I'm new with AspectJ and I tried to do this:

public class MyDBDAO {
    public boolean update(MyObject myObject) {}
}

And Aspect:

@Aspect
@Component
public class AspectJClass {
   @Pointcut("execution(* com.myclass.MyDBDAO.update()) && args(myObject)")
    public void update(MyObject myObject) {}
 }

Should I only use Absoulute Type? Are there any ways to solve this problem?


Answer:

have you tried this ?

@Pointcut("execution(void com.myclass.MyDBDAO.update(MyObject)) && args(myObject)")
public void update(MyObject myObject) {}

if you want poincut to all of the methods in the class you can do this :

@Pointcut("this(com.myclass.MyDBDAO)")
public void isMyDBDAO() {}

Question:

This is a simple class which is an aspect:

package aspectTest;

import java.awt.Color;

import javax.swing.JLabel;

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 aspect {
        @Pointcut("execution(static String createMultiLabel(..))")
        public void multilabelCreation() {}

        @Around("multilabelCreation()")
        public String changeLabelColours(ProceedingJoinPoint thisJoinPoint) throws Throwable {

    String st = (String) thisJoinPoint.proceed();
System.out.println("fdfs");
    st = "st"+st;
    return st;
        }


}

and it's my main class:

package aspectTest;

import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

public class messagemethod {
    public static String createMultiLabel(final String msg) {

        return msg;
    }
    public static void main(String[] args) {
        String st1 = createMultiLabel("hello");
        System.out.println(st1);

    }
}

this is my the folder lib:

this is my aop.xml:

<aspectj>
    <aspects>

        <aspect name="aspectTest.aspect"/>

</aspects>

</aspectj>

and this is my Run Configuration:

my problem is that when I run my main class, it just writes hello but not hello hello, which should be because of aspect. Anyone knows why my aspect doesn't make any affect?


Answer:

This works for me.

package test;

@Aspect
public class TestAspect {
    public static String createMultiLabel(final String msg) {
        return msg;
    }
    public static void main(String[] args) {
        String st1 = createMultiLabel("hello");
        System.out.println(st1);
    }

    @Around("execution(java.lang.String test.TestAspect.createMultiLabel(java.lang.String))")
    public String aroundCreateMultiLabel(ProceedingJoinPoint joinPoint) throws Throwable {
        System.err.println("in around before " + joinPoint);
        String string = (String) joinPoint.proceed();
        System.err.println("in around after " + joinPoint);
        return string;
    }
}

Perhaps you need to redefine your project type to aspect project. Compare with your .projects file

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
    <name>Aspects</name>
    <buildSpec>
        <buildCommand>
            <name>org.eclipse.ajdt.core.ajbuilder</name>
        </buildCommand>
    </buildSpec>
    <natures>
        <nature>org.eclipse.ajdt.ui.ajnature</nature>
        <nature>org.eclipse.jdt.core.javanature</nature>
    </natures>
</projectDescription>

Question:

I have no idea why this simple application is not working. Everything is wire together correctly and I am not getting any errors. I am just trying to use AspectJ to call a method before another.

package com.springpractice.app;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/springpractice/app/Beans.xml");

        Camera camera = (Camera) context.getBean("camera");

        try {

            camera.snap();

            camera.snap(100);
        } catch (Exception e) {
            System.out.println("Caught Exception "+ e.getMessage());
        }

        context.close();
    }


}

Camera.java

package com.springpractice.app;

import org.springframework.stereotype.Component;

@Component("camera") 
public class Camera implements PhotoSnapper {

    public Camera(){
        //System.out.println("Hello from constructor");
    }

    void snap(){
        System.out.println("Snaped a picture...");
    }

    void snap(int exposure){
        System.out.println("Exposure.."+exposure);
    }
}

Logger.java

package com.springpractice.app;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component("logger")
public class Logger {

@Pointcut("execution(* com.springpractice.app.Camera.snap(..))")
public void cameraSnap(){

}

@Before("cameraSnap()")
public void aboutToTakePicture(){
    System.out.println("About to take a picture");
}

}

beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd">

    <context:annotation-config></context:annotation-config>
    <context:component-scan base-package="com.springpractice.app"></context:component-scan>

    <aop:aspectj-autoproxy />   
</beans>

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>com.spring.proxies</groupId>
  <artifactId>Proxies_Practice</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>4.1.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.5</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.5</version>
    </dependency>
  </dependencies>
</project>

output

Snaped a picture...
Exposure..100

Answer:

The snap methods need to be part of the public API.

package com.springpractice.app;

import org.springframework.stereotype.Component;

@Component("camera") 
public class Camera implements PhotoSnapper {

    public Camera() {
        //System.out.println("Hello from constructor");
    }

    public void snap() {
        System.out.println("Snaped a picture...");
    }

    public void snap(int exposure) {
        System.out.println("Exposure.."+exposure);
    }
}

Question:

my Project has a MessageUtil class, which has methods to show messages, I'm trying to make the texts of my Jlabels red using aspectJ, without use of aspectJ it is enough to add 'for loop' to one of the methods wich makes multiLabel text message:

public static JLabel[] createMultiLabel(String msg) {

        JLabel[] messages = null;
        if (msg.contains("\n")) {
        messages =  createMultiLabelBySlashN(msg);
        } else {
            messages = createMultiLabelByPixel(msg);
        }
        //this for loop makes the text red
        for (int i = 0; i < messages.length; i++) {
            messages[i].setForeground(Color.RED);
        }
        return messages;
    }

The two methods createMultiLabelByPixel(msg) and createMultiLabelBySlashN(msg) are in this form:

private static JLabel[] createMultiLabelBySlashN(String msg) { 
// the code here 
}

I want to use aspectJ inorder to make the JLabels red, not using the for loop in the body of method createMultiLabel,I don't have any idea how to do this, I'm trying to make a class containing aspecJ annotation with the pointCut below to make the array messages red before the messages is sent to createMultiLabelBySlashN() and createMultiLabelByPixel() as their parameter, but I don't know if it is correct or how to define the JLabel messages[] from the method createMultiLabel in my aspectJ class to make it red using the same for loop and send the String rezult to createMultiLabelBySlashN.

@Pointcut ("execution(public static JLabel[] mehad.util.MessageUtil.createMultiLabelBySlashN(..)) || execution(public static JLabel[] mehad.util.MessageUtil.createMultiLabelByPixel(..)" )

even when I'm calling the pointCut it seems there are errors with my code that says:

no match for this type name: JLabel

Answer:

no match for this type name: JLabel

This is because you do not use the fully qualified class name javax.swing.JLabel.

Now let us assume your class looks like this (just a simple fake):

package mehad.util;

import javax.swing.JLabel;

public class MessageUtil {
    public static void main(String[] args) {
        for (JLabel label : createMultiLabel("Albert Einstein\nWerner Heisenberg\nMax Planck"))
            System.out.println(label.getText() + " / " + label.getForeground());
        System.out.println();
        for (JLabel label : createMultiLabel("Albert Einstein, Werner Heisenberg, Max Planck"))
            System.out.println(label.getText() + " / " + label.getForeground());
    }

    public static JLabel[] createMultiLabel(String msg) {
        return msg.contains("\n")
            ? createMultiLabelBySlashN(msg)
            : createMultiLabelByPixel(msg);
    }

    private static JLabel[] createMultiLabelBySlashN(String msg) {
        String[] lines = msg.split("\n+");
        JLabel[] labels = new JLabel[lines.length];
        for (int i = 0; i < lines.length; i++)
            labels[i] = new JLabel(lines[i]);
        return labels;
    }

    private static JLabel[] createMultiLabelByPixel(String msg) {
        String[] words = msg.split("[, ]+");
        JLabel[] labels = new JLabel[words.length];
        for (int i = 0; i < words.length; i++)
            labels[i] = new JLabel(words[i]);
        return labels;
    }
}

Now if you run the main method without AspectJ, you will see this console output:

Albert Einstein / sun.swing.PrintColorUIResource[r=51,g=51,b=51]
Werner Heisenberg / sun.swing.PrintColorUIResource[r=51,g=51,b=51]
Max Planck / sun.swing.PrintColorUIResource[r=51,g=51,b=51]

Albert / sun.swing.PrintColorUIResource[r=51,g=51,b=51]
Einstein / sun.swing.PrintColorUIResource[r=51,g=51,b=51]
Werner / sun.swing.PrintColorUIResource[r=51,g=51,b=51]
Heisenberg / sun.swing.PrintColorUIResource[r=51,g=51,b=51]
Max / sun.swing.PrintColorUIResource[r=51,g=51,b=51]
Planck / sun.swing.PrintColorUIResource[r=51,g=51,b=51]

I.e. all labels have a default grey colour. Now add this aspect:

package de.scrum_master.aspect;

import java.awt.Color;

import javax.swing.JLabel;

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 RedLabelAspect {
    @Pointcut("execution(static javax.swing.JLabel[] createMultiLabel(..))")
    public void multilabelCreation() {}

    @Around("multilabelCreation()")
    public JLabel[] changeLabelColours(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        JLabel[] labels = (JLabel[]) thisJoinPoint.proceed();
        for (JLabel label : labels)
            label.setForeground(Color.RED);
        return labels;
    }
}

The aspect modifies the labels contained in the result array in place, i.e. the for loop now resides in your aspect code, no longer in the core code. The console output changes to:

Albert Einstein / java.awt.Color[r=255,g=0,b=0]
Werner Heisenberg / java.awt.Color[r=255,g=0,b=0]
Max Planck / java.awt.Color[r=255,g=0,b=0]

Albert / java.awt.Color[r=255,g=0,b=0]
Einstein / java.awt.Color[r=255,g=0,b=0]
Werner / java.awt.Color[r=255,g=0,b=0]
Heisenberg / java.awt.Color[r=255,g=0,b=0]
Max / java.awt.Color[r=255,g=0,b=0]
Planck / java.awt.Color[r=255,g=0,b=0]

Voilà - the cross-cutting concern of colouring the labels has been modularised into an aspect.

Question:

I am running a HelloWorld project using load time weaving (LTW) in aspectJ. I had defined abstract aspect only. I had not defined concrete aspect but mentioned "name" attribute of <concrete-aspect> as main.java.aop.helloworld.MyHelloWorldAspect in the aop.xml as below:

<concrete-aspect name="main.java.aop.helloworld.MyHelloWorldAspect"
        extends="main.java.aop.helloworld.HelloWorldAspect">
        <pointcut name="helloWorld"
            expression="execution(public static void HelloWorld.say*(..))" />
    </concrete-aspect>

I could run the application fine and getting the desired result. But, below line is printed to define the concrete aspect.

[URLClassLoader@ddc3fe] info define aspect main.java.aop.helloworld.MyHelloWorldAspect

I am wondering whether concrete class implementation is mandatory or not as it prints a INFO message to define concrete aspect. Also, weaving and applying aspect and advice works fine as per the below INFO message.

[URLClassLoader@ddc3fe] weaveinfo Join point 'method-execution(void main.java.aop.helloworld.HelloWorld.say(java.lang.String))' in Type 'main.java.aop.helloworld.HelloWorld' (HelloWorld.java:5) advised by before advice from 'main.java.aop.helloworld.MyHelloWorldAspect' (HelloWorldAspect.java)

Could anyone explain whether concrete class implementation is mandatory or not. If not required, then please help me in understanding how it works. Thanks.


Answer:

If you don't provide a concrete aspect then the advice in the abstract aspect will not apply. Compile this:

class C {}
abstract aspect X { before():staticinitialization(C) {}}

and the advice in X will not apply to C. Remove the abstract or provide a concrete sub-aspect of X and it will apply. However, that is only true for advice - any static crosscutting in the abstract aspect will apply, for example and method or field inter type declaration.

You have two options for the concrete aspect - either code or XML, and you are going the XML route which is fine. I think the first (badly worded) info message you show is telling you that the system is defining the concrete aspect according to your spec, not that you need to.

Question:

Is it possible to use Spring AOP or AspectJ to intercept all Service methods (contained in classes in the com.app.service.* package) having the annotation

@Transactional(readOnly = false)

(other elements possible as well in Spring's @Transactional annotation, but we only care about readOnly = false).

I could only find examples pertaining to pointcuts with simple Annotations, or @Annotation(value).

My preference would be to use straight Spring, if possible.

It would probably be something like the below, but not sure about the syntax.

@Around("execution(* com.app.service..*.*(..))" && @Transactional[??])


Answer:

You want to use a pointcut like this:

execution(@org.springframework.transaction.annotation.Transactional(readOnly = false) * com.app.service..*.*(..))

Question:

For instrumentation in Java, why java.lang.instrument is preferred over AspectJ though both does the job of instrumentation equally. Is there any specific advantage of using java.lang.instrument? Thanks in advance...


Answer:

Those are two completely different things. The Instrumentation API offers a hook into the JVM runtime which allows Java agents to access more advanced features of the JVM. It also offers a hook into the JVM's class loading where an agent can be notified when a class is loaded and redefine its class file. Similary, it is possible to redefine/retransform already loaded classes.

AspectJ is a library that offers a more high-level view on redefining existing classses. It works with point cuts and join points to explain how a class should be redefined. The redefinition by AspectJ is then either applied at compile-time with the help of a tool like Maven or AspectJ can use a Java agebt and the instrumentation API to apply the redefinition of classes at runtime.

Question:

I'm migrating some code that uses Spring AOP to AspectJ aspects (weaved at compile time). I'm looking for feedback on how I can modify the pointcut so that that they behave the same after the migration?

Currently Spring AOP Aspects only function as 'Proxies' and therefore only work from external callers on public/interface methods. Now that I've switched to AspectJ weaving; even method calls from within the class to itself are being weaved.

This is causing me a big headache and I was wondering if i can change the pointcut to somehow still behave as if it was still a proxy ? (i.e. exclude calls from within itself at any point in the type hierarchy such as calling an inherited function)


Answer:

I think Jigish's idea to mix aspect styles is a good way to migrate or even to continue on a permanent basis, as long as you do not have any compelling issues (e.g. performance) with Spring.

Now, having said that, I have a workaround for you just in case you do need to exclude internal calls in full-blown AspectJ for any reason. I do not think it is elegant, but it works. Here is a proof of concept:

Two sample application classes:

These classes call their own methods internally, but also other classes' methods. E.g. Foo.fooOne(Bar) calls Bar.doSomethingBarish() externally, but also Foo.fooTwo(int) internally.

package de.scrum_master.app;

public class Foo {
    public void doSomethingFooish() {
        fooTwo(22);
    }

    public void fooOne(Bar bar) {
        bar.doSomethingBarish();
        fooTwo(11);
    }

    public String fooTwo(int number) {
        return fooThree("xxx");
    }

    public String fooThree(String text) {
        return text + " " + text + " " + text;
    }
}
package de.scrum_master.app;

public class Bar {
    public void doSomethingBarish() {
        barTwo(22);
    }

    public void barOne(Foo foo) {
        foo.doSomethingFooish();
        barTwo(11);
    }

    public String barTwo(int number) {
        return barThree("xxx");
    }

    public String barThree(String text) {
        return text + " " + text + " " + text;
    }
}

Driver application with main method:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        Foo foo = new Foo();
        Bar bar = new Bar();

        foo.fooOne(bar);
        bar.barOne(foo);
    }
}

Sample aspect including internal calls:

This is the usual way to write aspects. It reproduces your problem. I am using a call() pointcut here instead of execution() in order to have access to both caller (JoinPoint.EnclosingStaticPart) and callee (JoinPoint) joinpoints and be able to print them for illustration. In an execution() pointcut both values would be identical.

package de.scrum_master.aspect;

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

@Aspect
public class SampleAspect {
    @Pointcut("call(public * de.scrum_master..*(..)) && !within(SampleAspect)")
    public static void publicMethodCalls() {}

    @Before("publicMethodCalls()")
    public void myPointcut(
        JoinPoint thisJoinPoint,
        JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart
    ) {
        System.out.println(thisEnclosingJoinPointStaticPart + " -> " + thisJoinPoint);
    }
}

Console output:

Here you can see nicely how

  • Application calls both Foo and Bar methods,
  • Foo calls a Bar method, but also its own ones internally,
  • Bar calls a Foo method, but also its own ones internally.
execution(void de.scrum_master.app.Application.main(String[])) -> call(void de.scrum_master.app.Foo.fooOne(Bar))
execution(void de.scrum_master.app.Foo.fooOne(Bar)) -> call(void de.scrum_master.app.Bar.doSomethingBarish())
execution(void de.scrum_master.app.Bar.doSomethingBarish()) -> call(String de.scrum_master.app.Bar.barTwo(int))
execution(String de.scrum_master.app.Bar.barTwo(int)) -> call(String de.scrum_master.app.Bar.barThree(String))
execution(void de.scrum_master.app.Foo.fooOne(Bar)) -> call(String de.scrum_master.app.Foo.fooTwo(int))
execution(String de.scrum_master.app.Foo.fooTwo(int)) -> call(String de.scrum_master.app.Foo.fooThree(String))
execution(void de.scrum_master.app.Application.main(String[])) -> call(void de.scrum_master.app.Bar.barOne(Foo))
execution(void de.scrum_master.app.Bar.barOne(Foo)) -> call(void de.scrum_master.app.Foo.doSomethingFooish())
execution(void de.scrum_master.app.Foo.doSomethingFooish()) -> call(String de.scrum_master.app.Foo.fooTwo(int))
execution(String de.scrum_master.app.Foo.fooTwo(int)) -> call(String de.scrum_master.app.Foo.fooThree(String))
execution(void de.scrum_master.app.Bar.barOne(Foo)) -> call(String de.scrum_master.app.Bar.barTwo(int))
execution(String de.scrum_master.app.Bar.barTwo(int)) -> call(String de.scrum_master.app.Bar.barThree(String))

Improved aspect dynamically excluding internal calls:

Now we need to compare if the caller (this() pointcut in native aspectJ syntax) is identical to the callee (target() pointcut). If so, we want to skip advice execution. There are two ways to get caller/callee references in AspectJ:

  • binding them to parameters in the poinctut via this() and/or target(). There is one caveat here, though: If this() or target() are null the poinctut will not match, i.e. static methods as callers or callees are ruled out. In my example I want to see the calls by Application.main(..) though, so I will only bind the target/callee in the pointcut, but not the caller/this object.
  • determining them dynamically from within an executing advice via JoinPoint.getThis() and/or JoinPoint.getTarget(). This works nicely, but the caveat here is that it is probably a bit slower and that the advice will execute even in cases in which you would like to exclude static callers/callees right away.

Here we choose a mixed approach, including static callers, but excluding static callees in order to demonstrate both variants:

package de.scrum_master.aspect;

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

@Aspect
public class SampleAspect {
    @Pointcut("call(public * de.scrum_master..*(..)) && !within(SampleAspect)")
    public static void publicMethodCalls() {}

    @Before("publicMethodCalls() && target(callee)")
    public void myPointcut(
        Object callee,
        JoinPoint thisJoinPoint,
        JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart
    ) {
        Object caller = thisJoinPoint.getThis();
        if (caller == callee)
            return;
        System.out.println(thisEnclosingJoinPointStaticPart + " -> " + thisJoinPoint);
        System.out.println("  caller = " + caller);
        System.out.println("  callee = " + callee);
    }
}

Console output:

As you can see, we have reduced the output to only the calls we are interested in. If you also want to exclude the static caller Application.main(..), just bind this() directly.

execution(void de.scrum_master.app.Application.main(String[])) -> call(void de.scrum_master.app.Foo.fooOne(Bar))
  caller = null
  callee = de.scrum_master.app.Foo@6a5c2445
execution(void de.scrum_master.app.Foo.fooOne(Bar)) -> call(void de.scrum_master.app.Bar.doSomethingBarish())
  caller = de.scrum_master.app.Foo@6a5c2445
  callee = de.scrum_master.app.Bar@47516490
execution(void de.scrum_master.app.Application.main(String[])) -> call(void de.scrum_master.app.Bar.barOne(Foo))
  caller = null
  callee = de.scrum_master.app.Bar@47516490
execution(void de.scrum_master.app.Bar.barOne(Foo)) -> call(void de.scrum_master.app.Foo.doSomethingFooish())
  caller = de.scrum_master.app.Bar@47516490
  callee = de.scrum_master.app.Foo@6a5c2445

If in special cases you know the exact class name targeted by an advice, you might be able to use cflow() in order to exclude internal calls without ugly if constructs, but I have not thought it through and not tried either. It does not work in general cases anyway.


Update 1:

I played around some more. Here is an alternative using execution() instead of call(). Thus, it cannot rely on an enclosing joinpoint but needs to analyse the current callstack. I have not benchmarked the performance against the solution described above, but it will definitely weave fewer joinpoints. Furthermore, it uses if() right within its pointcut instead of using an if statement inside the advice. The condition is still determined dynamically during runtime, not statically while weaving the code, but I guess that is impossible here anyway because it depends on the control flow.

Just for the fun of it I am presenting the solution in both native and annotation-based syntax. I personally prefer native syntax because it it more expressive IMHO).

Alternative solution in native AspectJ syntax:

package de.scrum_master.aspect;

public aspect DemoAspect {
    pointcut publicMethodCalls() :
        execution(public !static * de.scrum_master..*(..)) &&
        if(Thread.currentThread().getStackTrace()[3].getClassName() != thisJoinPointStaticPart.getSignature().getDeclaringTypeName()); 

    before() : publicMethodCalls() {
        System.out.println(thisJoinPoint);
    }
}

Alternative solution in @AspectJ syntax:

package de.scrum_master.aspect;

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

@Aspect
public class SampleAspect {
    @Pointcut("execution(public !static * de.scrum_master..*(..)) && if()")
    public static boolean publicMethodCalls(JoinPoint thisJoinPoint) {
        return Thread.currentThread().getStackTrace()[3].getClassName() != thisJoinPoint.getSignature().getDeclaringTypeName();
    }

    @Before("publicMethodCalls(thisJoinPoint)")
    public void myPointcut(JoinPoint thisJoinPoint) {
        System.out.println(thisJoinPoint);
    }
}

Console output for alternative solution (identical for both syntax variants):

execution(void de.scrum_master.app.Foo.fooOne(Bar))
execution(void de.scrum_master.app.Bar.doSomethingBarish())
execution(void de.scrum_master.app.Bar.barOne(Foo))
execution(void de.scrum_master.app.Foo.doSomethingFooish())

Update 2:

Here is another variant using execution() plus some reflection via Class.isAssignableFrom(Class) which should also work with class hierarchies and interfaces:

package de.scrum_master.aspect;

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

@Aspect
public class SampleAspect {
    @Pointcut("execution(public !static * de.scrum_master..*(..)) && target(callee) && if()")
    public static boolean publicMethodCalls(Object callee, JoinPoint thisJoinPoint) {
        Class<?> callerClass;
        try {
            callerClass = Class.forName(
                Thread.currentThread().getStackTrace()[3].getClassName()
            );
        } catch (Exception e) {
            throw new SoftException(e);
        }
        Class<?> calleeClass = callee.getClass();
        return !callerClass.isAssignableFrom(calleeClass);
    }

    @Before("publicMethodCalls(callee, thisJoinPoint)")
    public void myPointcut(Object callee, JoinPoint thisJoinPoint) {
        System.out.println(thisJoinPoint);
    }
}

Question:

/* We are using Aspect to do AOP on some existing application and we also used threadlocal to store GUId. we are using @Around annotation. At the start of the transaction we are setting the GUID in transaction with initialValue() method.

Issue is as we know when we are using threadlocal we should also take care about removing the data from threadlocal otherwise it may result i outofmemory execption. if i am removing it at the last of the aspect it is corrupting the code and changing the UUID value.

Please suggest how we can achieve it without outofmemory.

Code :- */

@Aspect
public class DemoAspect {

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

    private static ThreadLocal<String> id = new ThreadLocal<String>() {
        @Override
        protected String initialValue(){
            return UUID.randomUUID().toString();
        } 
    };

    @Around("logging()")
    public Object tracing(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        String methodSignature=thisJoinPoint.getSignature().toString();
        if(id.get().toString()==null || id.get().toString().length()==0)
        id.set(UUID.randomUUID().toString());
        System.out.println("Entering into "+methodSignature);
        Object ret = thisJoinPoint.proceed();
        System.out.println(id.get().toString());
        System.out.println("Exiting into "+methodSignature);
        //id.remove();
        return ret;
     }
}

Answer:

Before we start a little hint: If you write @Around("logging()") your pointcut method should be renamed from loggingResponseTime() to actually logging(), otherwise the aspect will not work.

Now as for your real problem: You are making a typical beginners' mistake by advising code too broadly, i.e. you are intercepting all method executions (outside the JDK). If you use Eclipse and AJDT and you put your cursor into the tracing() advice you will see something like this in the AspectJ "cross reference" window using your current pointcut:

You can immediately see your problem: Your pointcut captures code in your anonymous ThreadLocal subclass. This leads to endless recursion and finally to the StackOverflowError as you can see in your own callstack if you inspect it.

Now here is some sample code demonstrating the problem for other people's reference:

Driver application:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        System.out.println(bar(foo()));
    }

    public static String bar(String text) {
        return text + "bar";
    }

    private static String foo() {
        return "foo";
    }
}

Aspect:

package de.scrum_master.aspect;

import java.util.UUID;

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 DemoAspect {
    private static ThreadLocal<String> id = new ThreadLocal<String>() {
        @Override
        protected String initialValue() {
            return UUID.randomUUID().toString();
        }
    };

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

    @Around("logging()")
    public Object tracing(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        String methodSignature = thisJoinPoint.getSignature().toString();
        if (id.get().toString() == null || id.get().toString().length() == 0)
            id.set(UUID.randomUUID().toString());
        System.out.println("Entering into " + methodSignature);
        Object ret = thisJoinPoint.proceed();
        System.out.println(id.get().toString());
        System.out.println("Exiting from " + methodSignature);
        id.remove();
        return ret;
    }
}

Console output:

Exception in thread "main" java.lang.StackOverflowError
    at org.aspectj.runtime.reflect.SignatureImpl$CacheImpl.get(SignatureImpl.java:217)
    at org.aspectj.runtime.reflect.SignatureImpl.toString(SignatureImpl.java:50)
    at org.aspectj.runtime.reflect.SignatureImpl.toString(SignatureImpl.java:62)
    at de.scrum_master.aspect.DemoAspect$1.initialValue_aroundBody1$advice(DemoAspect.aj:29)
    at de.scrum_master.aspect.DemoAspect$1.initialValue(DemoAspect.aj:1)
    at de.scrum_master.aspect.DemoAspect$1.initialValue(DemoAspect.aj:1)
    at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:160)
    at java.lang.ThreadLocal.get(ThreadLocal.java:150)
    at de.scrum_master.aspect.DemoAspect$1.initialValue_aroundBody1$advice(DemoAspect.aj:30)
    at de.scrum_master.aspect.DemoAspect$1.initialValue(DemoAspect.aj:1)
    at de.scrum_master.aspect.DemoAspect$1.initialValue(DemoAspect.aj:1)
    at java.lang.ThreadLocal.setInitialValue(ThreadLocal.java:160)
    at java.lang.ThreadLocal.get(ThreadLocal.java:150)
    (...)

So what can you do? It is actually quite simple: Just exclude the joinpoints you do not really want to intercept from your pointcut. For that you have several options. I am just naming a few:

A) Put your aspects into a specific package and exclude all (aspect) classes in that package:

@Pointcut("execution(* *(..)) && !within(de.scrum_master.aspect..*)")

B) Exclude all classes annotated by @Aspect:

@Pointcut("execution(* *(..)) && !within(@org.aspectj.lang.annotation.Aspect *)")

C) Exclude all (aspect) classes matching a certain naming scheme like *Aspect:

@Pointcut("execution(* *(..)) && !within(*..*Aspect)")

D) Exclude code from all ThreadLocal subclasses (+ syntax):

@Pointcut("execution(* *(..)) && !within(ThreadLocal+)")

In each case the result will be the same:

Entering into void de.scrum_master.app.Application.main(String[])
Entering into String de.scrum_master.app.Application.foo()
d2b83f5f-7282-4c06-9b81-6601c8e0499d
Exiting from String de.scrum_master.app.Application.foo()
Entering into String de.scrum_master.app.Application.bar(String)
0d1c9463-4bbd-427d-9d64-c7f3967756cf
Exiting from String de.scrum_master.app.Application.bar(String)
foobar
aa96bbbd-a1a1-450f-ae6e-77ab204c5fb2
Exiting from void de.scrum_master.app.Application.main(String[])

By the way: I have strong doubts about your usage of UUIDs because I see no value in creating expensive objects here. How about just logging timestamps? Why do you need globally unique IDs for logging? They tell you nothing. Furthermore, not only are you creating one ID per thread, but if you use the uncommented id.remove() you even create one per call! Sorry, but this is bloat, it slows down your code and creates lots of unnecessary objects. I do not think this is wise.


Update:

I forgot to explain the reason for the endless recursion: Your advice calls ThreadLocal.get(), assuming it could be null. Actually it cannot be because if the value has not been initialised, get() does so by utilising initialValue(). Even if you manually call remove(), the next time you call get() it will again initialise the value again and so forth. This is documented behaviour:

Returns the value in the current thread's copy of this thread-local variable. If the variable has no value for the current thread, it is first initialized to the value returned by an invocation of the initialValue() method.

So what happens, step by step?

  • A method is called.
  • Your around advice kicks in.
  • You call id.get() from the advice.
  • ThreadLocal.get() checks if a value is set, notices that there is none and calls your overridden initialValue() method.
  • Because the overridden initialValue() method is captured by your match-all pointcut execution(* *(..)), again your advice kicks in before the initial value has been set. The end result is that the loop starts again and so forth - endless recursion, quod erat demonstrandum.

So actually your problem boils down to calling get() on an uninitialised ThreadLocal subclass from an advice while simultaneously targetting its user-defined initialValue() method with the same advice. This is what creates the endless recursion and ultimately makes your stack overflow.

My recommendation is to exclude your aspect from the pointcut, see example pointcuts above. You should also get rid of the null check for the ThreadLocal value because it is superfluous. Last but not least, I assume you want one ThreadLocal value per thread and not one per method call. So you can do without any set() or remove() calls altogether.

Modified driver class, creating an additional thread:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(bar(foo()));
            }
        }).start();
        Thread.sleep(200);
    }

    public static String bar(String text) {
        return text + "bar";
    }

    private static String foo() {
        return "foo";
    }
}

Improved aspect:

package de.scrum_master.aspect;

import java.util.UUID;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class DemoAspect {
    private static ThreadLocal<UUID> id = new ThreadLocal<UUID>() {
        @Override
        protected UUID initialValue() {
            return UUID.randomUUID();
        }
    };

    @Pointcut("execution(* *(..)) && !within(DemoAspect)")
    public void logging() {}

    @Around("logging()")
    public Object tracing(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        Signature methodSignature = thisJoinPoint.getSignature();
        System.out.println(
            "Thread " + Thread.currentThread().getId() +
            "[" + id.get() +
            "] >>> " + methodSignature
        );
        Object result = thisJoinPoint.proceed();
        System.out.println(
            "Thread " + Thread.currentThread().getId() +
            "[" + id.get() +
            "] <<< " + methodSignature
        );
        return result;
    }
}

Console output:

Thread 1[549d0856-0a92-4031-9331-a1317d6a43c4] >>> void de.scrum_master.app.Application.main(String[])
Thread 9[32c8444c-0f1f-4023-9b97-69d5beda3b4c] >>> void de.scrum_master.app.Application.1.run()
Thread 9[32c8444c-0f1f-4023-9b97-69d5beda3b4c] >>> String de.scrum_master.app.Application.access$0()
Thread 9[32c8444c-0f1f-4023-9b97-69d5beda3b4c] >>> String de.scrum_master.app.Application.foo()
Thread 9[32c8444c-0f1f-4023-9b97-69d5beda3b4c] <<< String de.scrum_master.app.Application.foo()
Thread 9[32c8444c-0f1f-4023-9b97-69d5beda3b4c] <<< String de.scrum_master.app.Application.access$0()
Thread 9[32c8444c-0f1f-4023-9b97-69d5beda3b4c] >>> String de.scrum_master.app.Application.bar(String)
Thread 9[32c8444c-0f1f-4023-9b97-69d5beda3b4c] <<< String de.scrum_master.app.Application.bar(String)
foobar
Thread 9[32c8444c-0f1f-4023-9b97-69d5beda3b4c] <<< void de.scrum_master.app.Application.1.run()
Thread 1[549d0856-0a92-4031-9331-a1317d6a43c4] <<< void de.scrum_master.app.Application.main(String[])

As you can see, threads already have unique IDs, so maybe you want consider implementing your aspect without any UUIDs altogether.

Question:

I have a Spring boot application, and I want to log some info what happens when a Controller method id invoked.

For some reason, my Aspect is not working.

Here is my @Component class annotated with @Aspect:

@Pointcut("within(@org.springframework.stereotype.Controller *)")
public void controller() {
}

@Pointcut("execution(* *.*(..))")
protected void allMethod() {
}

@Before("controller()&& allMethod()")
public void logBefore(JoinPoint joinPoint) {
}

The logBefore method is not called, when any Controller method is called with REST.


Answer:

Important: As you've stated you are using a Spring Boot setup, my assumption is that you've implemented the Spring AOP module instead of the "actual" AspectJ library. The difference is significant, as the implementation of AOP differs between them. Spring uses the AspectJ annotations to apply proxying, while AspectJ "weaves" the code into your application. In short, Spring AOP might be easier to implement, while AspectJ offers more fine-grained functionality (such as compile-time weaving). A comparison can be found here.

I have tried out the configuration from the code snippet you provided in your post. The advice was invoked after I added several annotations:

@SpringBootApplication
// Be sure to add EnableAspectJAutoProxy and set proxyTargetClass to true
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class DemoApplication {
  ...
}
// Be sure to add @Aspect and @Component
@Component
@Aspect
public class DemoAop {

  private static Logger logger = LoggerFactory.getLogger(DemoAop.class);

  @Pointcut("within(@org.springframework.stereotype.Controller *)")
  public void controller() {
  }

  @Pointcut("execution(* *.*(..))")
  protected void allMethod() {
  }

  @Before("controller()&& allMethod()")
  public void logBefore(JoinPoint joinPoint) {
    logger.info("TEST");
  }

}

Question:

I'm using aspectJ 1.8.10. In my code I have a bean with ScheduledExecutorService:

@Bean
public ScheduledExecutorService backgroundTaskExecutor() {
    return Executors.newSingleThreadScheduledExecutor();
}

When bean instantiated, proxy class throws:

.AopConfigException: Could not generate CGLIB subclass of class [class java.util.concurrent.Executors$DelegatedScheduledExecutorService]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: No visible constructors in class java.util.concurrent.Executors$DelegatedScheduledExecutorService

I know, that ScheduledExecutorService haven't constructor, is the root cause. But I need to configure my aspect's pointcut to exclude FinalType classes. Like this:

@Before("!within(is(FinalType)) && execution(* your_method_name(..)) ")

But, as I mentioned, aspectJ version 1.8.10 is not recognize is(..) syntax. (Intellij IDEA warning Cannot resolve symbol 'is'). Application starts without AOP issues, but fails with

java.lang.IllegalArgumentException: No visible constructors in class java.util.concurrent.Executors$DelegatedScheduledExecutorService

What I'm doing wrong? Is there any changes is aspectj > 1.8.4? (is(..) syntax)


Answer:

You have Spring AOP configured to force creation of CGLIB proxies even for interface types like ScheduledExecutorService, probably via

@EnableAspectJAutoProxy(proxyTargetClass = true)

Just remove the proxyTargetClass = true part or set to false, then your aspect will work. You do not need any is(FinalType) pointcut designator, just write something like

@Before("execution(* schedule*(..))")

in order to intercept scheduler methods.


Update: Let me explain why is(FinalType) does not help you and why thinking it does not work is wrong:

Read the error messages again:

Could not generate CGLIB subclass of class
  [class java.util.concurrent.Executors$DelegatedScheduledExecutorService]:
  Common causes of this problem include using a final class or a non-visible class;
  nested exception is
    java.lang.IllegalArgumentException: No visible constructors in class
    java.util.concurrent.Executors$DelegatedScheduledExecutorService

"No visible constructors" does not mean the class is final, it means what it says: There just are no visible constructors. Actually the inner static class Executors.DelegatedScheduledExecutorService is package-protected in java.util.concurrent where Executors resides. If you look at the source code you see:

static class DelegatedScheduledExecutorService
        extends DelegatedExecutorService
        implements ScheduledExecutorService {

    private final ScheduledExecutorService e;

    DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
        super(executor);
        e = executor;
    }

    // (...)
}

See? No final class here. The actual problem is that CGLIB just cannot create a subclass due to JVM limitations: You cannot subclass something that is in another package if it is not public.

This is why I told you to let Spring use a JDK dynamic proxy and take advantage of the fact that in this case subclassing is not necessary but implementing an interface is enough.

Question:

The Spring AspectJ loadtime weaving configuration is building and loading server without any errors, but the aspect is not getting invoked.

Here is the list of configuration 1) JDK 8 2) Server Jetty

@Configuration
@ComponentScan(basePackages = {..})
@EnableSpringConfigured
@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
@PropertySource(...)
@ImportResource(value = { "classpath:META-INF/aop.xml", ..})
class config {
...
}

aop.xml

<aspectj>     
      <weaver options="-Xlint:ignore -Xset:weaveJavaPackages=true -Xset:weaveJavaxPackages=true">
        <include within="com.proj.*"/>
        <include within="java.*"/>
        <include within="javax.*"/>
        <include within="org.springframework.*"/>
        <include within="org.aspectj.*"/>
    </weaver>
    <aspects>
        <aspect name="com.proj.SampleAspect"/>
    </aspects>
</aspectj>

Have also tried with options in aop.xml

options="-XnoInline -verbose -showWeaveInfo -debug -Xlint:ignore -Xset:weaveJavaPackages=true -Xset:weaveJavaxPackages=true"

Aspect

@Component
@Aspect
public class SampleAspect {
    @Autowired
    private RequestContextFilter interceptRequestContext;

    @Around("@annotation(ExecuteByContext)")
    public Object interceptByContext(final ProceedingJoinPoint pjp) throws Throwable {
        if(SampleUtil.applyForRequest(interceptRequestContext.getRequestContext()) {
            LOGGER.info(String.format("Intercept context for method %s", pjp.getSignature().getName()));
            return null;
        }
        return pjp.proceed();
    }
}

Annotation

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExecuteByContext {

}

@Component
@Configurable
class TestClass implements ISomeInterface{

  ...
  @ExecuteByContext
  public void method() {
    ..
  }

  @ExecuteByContext
  private void method1() {
    ..
  }
}

Jetty server is started with MAVEN_OPTS setting

-javaagent:/path_to/.m2/repository/org/springframework/spring-instrument/4.2.0.RELEASE/spring-instrument-4.2.0.RELEASE.jar

I have the following dependency in my maven

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.2.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-instrument</artifactId>
</dependency>

The SampleAspect is not getting invoked. I have couple of methods (public, private and protected) annotated with @ExecuteByContext.


Answer:

Probably your target classes are not directly in package com.proj but in a subpackage. The syntax for including subpackages is ..*, not simply .*, i.e. in your aop.xml you should have

<include within="com.proj..*"/>

et cetera.

Question:

I have functions that include different javax Query annotations like : @QueryParam , @Context , @PathParam etc..

is there a way to exclude these parameters when calling joinPoint.getArgs()?

Example:

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("{pathParam}/v1/{pathParam2}/")
    @MyAnnotation
    public Response update(@PathParam("pathParam") String p1, @PathParam("pathParam2") int p2, MyObject x);



    @Before("@annotation(MyAnnotation)")
        public void doSomething(JoinPoint joinPoint){
            Object[] objects = joinPoint.getArgs(); // HERE - is there a way to get only MyObject and not other params..?
    }

The reason I want to do it is that I have several urls, while marking ~10% as persistent. It means that I want the input data to be saved in some persistent service. The Query & Context params are not important to me, but the input data itself is.


Answer:

Assuming you really use full AspectJ and not Spring AOP like so many others, you should be aware of the fact that in full AspectJ @annotation(XY) potentially matches not just execution() joinpoints but also call(), i.e. your advice will be triggered twice. Even worse, if other places than method executions are also annotated - e.g. classes, fields, constructors, parameters - the pointcut will also match and your try to cast to MethodSignature will cause an exception as a consequence.

Furthermore, please note that in @AspectJ syntax you need to provide the fully qualified class name of the annotation you want to match against, i.e. don't forget to also prepend the package name. Otherwise there will be no match at all. So before doing anything else you want to change your pointcut to:

@annotation(de.scrum_master.app.MyAnnotation) && execution(* *(..))

Now here is a fully self-consistent example, an SSCCE producing repeatable results, as requested by me in the comment under your question:

Annotation:

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

Driver application:

As you can see, the test method has parameters with different types of annotations:

  1. only javax annotation
  2. javax + own annotation
  3. only your own annotation
  4. no annotation

We want to ignore #1/2 and only print #3/4.

package de.scrum_master.app;

import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;

public class Application {
  public static void main(String[] args) {
    new Application().update("foo", 11, "bar", 22);
  }

  @MyAnnotation
  public Response update(
    @PathParam("pathParam") String p1,
    @PathParam("pathParam2") @MyAnnotation int p2,
    @MyAnnotation String text,
    int number
  ) {
    return null;
  }
}

Aspect:

Just as user Andre Paschoal started to show in his code fragment, you need to iterate over both the arguments and annotations arrays in order to pull off the filtering trick. I think it is quite ugly and possibly slow just for logging's sake (and I assume this is what you want to do), but for what it is worth, here is your solution:

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;

@Aspect
public class ParameterFilterAspect {
  @Before("@annotation(de.scrum_master.app.MyAnnotation) && execution(* *(..))")
  public void doSomething(JoinPoint joinPoint) {
    Object[] args = joinPoint.getArgs();
    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations();
    for (int i = 0; i < args.length; i++) {
      boolean hasJavaxAnnotation = false;
      for (Annotation annotation : annotationMatrix[i]) {
        if (annotation.annotationType().getPackage().getName().startsWith("javax.")) {
          hasJavaxAnnotation = true;
          break;
        }
      }
      if (!hasJavaxAnnotation)
        System.out.println(args[i]);
    }
  }
}

Console log:

bar
22

Tadaa! :-)

Question:

Is there a way to get the MethodSignature from a ProceedingJoinPoint without downcasting?

    private String toEventString(ProceedingJoinPoint pjp) {
    MethodSignature methodSignature = ((MethodSignature)pjp.getSignature());

    StringBuilder sb = new StringBuilder();

    String[] paramNames = methodSignature.getParameterNames();
    Class[] paramTypes = methodSignature.getParameterTypes();

    sb.append(methodSignature.getName()).append('(');

    for(int i = 0; i < paramNames.length; i++) {
        sb
            .append(paramTypes[i].getSimpleName())
            .append(" ")
            .append(paramNames[i]);
        if(i < paramNames.length - 1) {
            sb.append(", ");
        }
    }

    return sb.append(" )").toString();

}

Answer:

Simple question, simple answer: no.

Update: Maybe you wonder why you need to cast. Are there other signature types other than method signatures? Oh yes, there are. E.g. if you use within(SomeClass) you could encounter any of the following signature types:

  • method
  • constructor
  • class initializer
  • field
  • advice execution
  • catch clause
  • lock / unlock (a rather special case, capturing synchronized blocks if aspects are compiled with -Xjoinpoints:synchronization)

Here is a little example:

Driver application:

package de.scrum_master.app;

public class Application {
  private String name;

  public Application(String name) {
    this.name = name;
  }

  public static void main(String[] args) {
    Application application = new Application("my app");
    synchronized (application) {
      try {
        application.doSomething("foo", 11, false);
      }
      catch (RuntimeException e) {}
    }
  }

  private void doSomething(String string, int i, boolean b) {
    throw new RuntimeException("oops");
  }
}

Aspect the advice execution of which should be intercepted:

package de.scrum_master.aspect;

public aspect MyOtherAspect {
  before() : execution(* main(..)) {}
}

Aspect printing signature types:

package de.scrum_master.aspect;

import de.scrum_master.app.Application;

public aspect MyAspect {
  before() : within(Application) || within(MyOtherAspect) {
    System.out.println(thisJoinPoint);
    System.out.println("    " + thisJoinPoint.getSignature().getClass().getSimpleName());
  }
}

Console log:

staticinitialization(de.scrum_master.app.Application.<clinit>)
    InitializerSignatureImpl
staticinitialization(de.scrum_master.aspect.MyOtherAspect.<clinit>)
    InitializerSignatureImpl
preinitialization(de.scrum_master.aspect.MyOtherAspect())
    ConstructorSignatureImpl
initialization(de.scrum_master.aspect.MyOtherAspect())
    ConstructorSignatureImpl
execution(de.scrum_master.aspect.MyOtherAspect())
    ConstructorSignatureImpl
adviceexecution(void de.scrum_master.aspect.MyOtherAspect.before())
    AdviceSignatureImpl
execution(void de.scrum_master.app.Application.main(String[]))
    MethodSignatureImpl
call(de.scrum_master.app.Application(String))
    ConstructorSignatureImpl
preinitialization(de.scrum_master.app.Application(String))
    ConstructorSignatureImpl
initialization(de.scrum_master.app.Application(String))
    ConstructorSignatureImpl
execution(de.scrum_master.app.Application(String))
    ConstructorSignatureImpl
set(String de.scrum_master.app.Application.name)
    FieldSignatureImpl
lock(lock(Object))
    LockSignatureImpl
call(void de.scrum_master.app.Application.doSomething(String, int, boolean))
    MethodSignatureImpl
execution(void de.scrum_master.app.Application.doSomething(String, int, boolean))
    MethodSignatureImpl
call(java.lang.RuntimeException(String))
    ConstructorSignatureImpl
handler(catch(RuntimeException))
    CatchClauseSignatureImpl
unlock(unlock(Object))
    UnlockSignatureImpl

BTW, each of those *Impl classes implements a corresponding signature interface.

Question:

We looking for a solution to track the state of a client POJO instance in a performant manner. What we expect is: every time a change is made on a POJO this state is made by using setters. We created an OGNL-based watching / event-bus and when change is made we will send proper OgnlChangeEvent to our event-bus.

So far we looked into AspectJ / cglib / object graph Diff solution but they all occupied too much CPU time. Our current solution is based on Spring MethodInterceptor and we are creating a new Proxy instance every time a Getter method is invoked.

At this point we are starting to look at code generation solutions and we stumbled on Byte Buddy. Is this direction is the right way to do so? Can we generate a new Class that will extend our client POJO State and notify about its OGNL prefix until setter method is invoked?


Answer:

Byte Buddy is a code generation tool and it is of course possible to implement such a solution. For creating a class that intercepts a setter, you would write code like:

new ByteBuddy()
  .subclass(UserPojo.class)
  .method(ElementMatchers.isSetter())
  .intercept(MethodDelegation.to(MyInterceptor.class)
             .andThen(SuperMethodCall.INSTANCE)
  .make();

Where you would write an interceptor like this:

public class MyInterceptor {
  public static void intercept(Object value) {
    // business logic comes here
  }
}

This way, you can add some code every time a setter is invoked which is triggered before the original code. You can also overload the intercept method with all primitive types to avoid the boxing for the argument. Byte Buddy figures out what to do for you.

I am however confused what you mean by performant. The above code turns out to me the same as creating a class like:

class UserClass {
  String value;
  void setValue(String value) {
    this.value = value;
  }
}

class InstrumentedUserClass extends UserClass {
  @Override
  void setValue(String value) {
    MyInterceptor.intercept(value);
    super.setValue(value);
  }
}

The performance is mainly influenced by the performance of what you do within the intercept method.

Finally, I do not understand how cglib does not work for you but using Spring - which is build on top of cglib - does work. I suspect that there is some problem with your interception logic you should look into.

Question:

I want to do some specific actions after a non public method (bar) is called. This method is called inside another method (foo). Note that "bar" and "foo" both are defined in a third-party jar file.

I tried to do that using @before annotation in Aspect oriented programming using spring. However, I could not do that.

Could any one let me know how can I do specific thing (call a specific function) after a specific function from a jar file is called?


Answer:

As Gervasio Amy suggested, you need to use AspectJ, not Spring AOP. If you are in a Spring environment, you can use AspectJ within Spring instead of Spring AOP, this is no problem. If you are not using Spring yet, AOP is not a reason to start using it, AspectJ works in simple Java SE (or EE) versions without Spring.

What you need to to is:

  • Compile your Aspect code with the AspectJ compiler ajc. (You can also compile your whole application with it because it is also a replacement for the Java compiler javac.)
  • Create a load-time weaving configuration aop.xml so as to enable your application to weave aspect code into 3rd party libraries on the fly during class-loading. I leave it up to you to figure out how to do that, just check the LTW documentation.
  • Start your JVM or application server with the AspectJ weaving agent on the command line via -javaagent:/path/to/aspectjweaver.jar switch.

Now what would the aspect you want look like? Let us try a few variants and refine the pointcut so as to make it match. But first let us set the stage for our experiments with a few sample 3rd party classes (Foo and Bar) and a little driver application (Application):

Sample application & 3rd party code:

package my.thirdparty.application;

public class Foo {
    void blah() {
        zot();
    }

    void foo() {}

    void zot() {
        foo();
    }
}
package my.thirdparty.application;

public class Bar {
    Foo foo = new Foo();

    public void doSomething() {
        someMethod();
        bar();
        anotherMethod();
    }

    private void someMethod() {
        foo.blah();
        foo.foo();
        foo.zot();
    }

    private void bar() {
        foo.blah();
        // This is the only call we want to intercept, 'foo' called by 'bar'
        foo.foo();
        foo.zot();
        anotherMethod();
    }

    private void anotherMethod() {
        foo.blah();
        foo.foo();
        foo.zot();
    }
}
package de.scrum_master.app;

import my.thirdparty.application.Bar;

public class Application {
    public static void main(String[] args) {
        new Bar().doSomething();
    }
}

As you can see, Application.main creates a Bar object and calls a public method Bar.doSomething. This method triggers a series of other method calls, some of which end up in Foo.foo being called indirectly, but only one single direct call is being made from Bar.bar to Foo.foo (which is what we are interested in according to your question).

Aspect, part #1: intercept all calls to Foo.foo

package de.scrum_master.aspect;

import my.thirdparty.application.Foo;
import my.thirdparty.application.Bar;

public aspect MethodInterceptor {
    pointcut allCalls() :
        call(* Foo.foo(..));

    Object around(Foo fooObject) : allCalls() && target(fooObject) {
        System.out.println(thisJoinPointStaticPart + " -> caller = " + thisEnclosingJoinPointStaticPart);
        //new Exception("printing stack trace").printStackTrace(System.out);
        //System.out.println();
        return proceed(fooObject);
    }
}

Console log:

call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.someMethod())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.bar())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.anotherMethod())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.anotherMethod())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())

This is a nice start, because now we can already intercept all calls to Foo.foo. But how about limiting the interceptions to those calls which are being made from within a control flow (cflow) of Bar.bar?

Aspect, part #2: intercept calls to Foo.foo made (in-)directly by Bar.bar

package de.scrum_master.aspect;

import my.thirdparty.application.Foo;
import my.thirdparty.application.Bar;

public aspect MethodInterceptor {
    pointcut indirectCalls() :
        call(* Foo.foo(..)) && cflow(execution(* Bar.bar(..)));

    Object around(Foo fooObject) : indirectCalls() && target(fooObject) {
        System.out.println(thisJoinPointStaticPart + " -> caller = " + thisEnclosingJoinPointStaticPart);
        //new Exception("printing stack trace").printStackTrace(System.out);
        //System.out.println();
        return proceed(fooObject);
    }
}

Console log:

call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.bar())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.anotherMethod())
call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())

Now this looks much better than before, we narrowed down our previous result of intercepted 12 calls down to 6. But how does it happen that we have callers like Foo.zot and Bar.anotherMethod in the result list, even though we said we wanted to limit the control flow to Bar.bar? The answer is simple: Those two methods were also directly or indirectly called by Bar.bar and are thus within the control flow. We see this more clearly if we inspect the call stacks (just uncomment the two log statements in the code):

call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
java.lang.Exception: printing stack trace
    at my.thirdparty.application.Foo.foo_aroundBody1$advice(Foo.java:22)
    at my.thirdparty.application.Foo.zot(Foo.java:11)
    at my.thirdparty.application.Foo.blah(Foo.java:5)
    at my.thirdparty.application.Bar.bar(Bar.java:19)
    at my.thirdparty.application.Bar.doSomething(Bar.java:8)
    at de.scrum_master.app.Application.main(Application.java:7)

call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.bar())
java.lang.Exception: printing stack trace
    at my.thirdparty.application.Bar.foo_aroundBody3$advice(Bar.java:22)
    at my.thirdparty.application.Bar.bar(Bar.java:21)
    at my.thirdparty.application.Bar.doSomething(Bar.java:8)
    at de.scrum_master.app.Application.main(Application.java:7)

call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
java.lang.Exception: printing stack trace
    at my.thirdparty.application.Foo.foo_aroundBody1$advice(Foo.java:22)
    at my.thirdparty.application.Foo.zot(Foo.java:11)
    at my.thirdparty.application.Bar.bar(Bar.java:22)
    at my.thirdparty.application.Bar.doSomething(Bar.java:8)
    at de.scrum_master.app.Application.main(Application.java:7)

call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
java.lang.Exception: printing stack trace
    at my.thirdparty.application.Foo.foo_aroundBody1$advice(Foo.java:22)
    at my.thirdparty.application.Foo.zot(Foo.java:11)
    at my.thirdparty.application.Foo.blah(Foo.java:5)
    at my.thirdparty.application.Bar.anotherMethod(Bar.java:27)
    at my.thirdparty.application.Bar.bar(Bar.java:23)
    at my.thirdparty.application.Bar.doSomething(Bar.java:8)
    at de.scrum_master.app.Application.main(Application.java:7)

call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.anotherMethod())
java.lang.Exception: printing stack trace
    at my.thirdparty.application.Bar.foo_aroundBody5$advice(Bar.java:22)
    at my.thirdparty.application.Bar.anotherMethod(Bar.java:28)
    at my.thirdparty.application.Bar.bar(Bar.java:23)
    at my.thirdparty.application.Bar.doSomething(Bar.java:8)
    at de.scrum_master.app.Application.main(Application.java:7)

call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Foo.zot())
java.lang.Exception: printing stack trace
    at my.thirdparty.application.Foo.foo_aroundBody1$advice(Foo.java:22)
    at my.thirdparty.application.Foo.zot(Foo.java:11)
    at my.thirdparty.application.Bar.anotherMethod(Bar.java:29)
    at my.thirdparty.application.Bar.bar(Bar.java:23)
    at my.thirdparty.application.Bar.doSomething(Bar.java:8)
    at de.scrum_master.app.Application.main(Application.java:7)

If you inspect the 6 callstacks, you find Bar.bar in each of them. So the cflow pointcut has done just what we told it to.

Can we get even better? How about telling the aspect not just limit the callee (target) object to Foo but also the to also the caller (this) object to Bar?

Aspect, part #3: intercept calls to Foo.foo made (in-)directly by Bar.bar, but definitely from a Bar object

package de.scrum_master.aspect;

import my.thirdparty.application.Foo;
import my.thirdparty.application.Bar;

public aspect MethodInterceptor {
    pointcut callsFromBar(Bar barObject) :
        call(* Foo.foo(..)) && cflow(execution(* Bar.bar(..))) && this(barObject);

    Object around(Foo fooObject, Bar barObject) : callsFromBar(barObject) && target(fooObject) {
        System.out.println(thisJoinPointStaticPart + " -> caller = " + thisEnclosingJoinPointStaticPart);
        new Exception("printing stack trace").printStackTrace(System.out);
        System.out.println();
        return proceed(fooObject, barObject);
    }
}

Console log:

call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.bar())
java.lang.Exception: printing stack trace
    at my.thirdparty.application.Bar.foo_aroundBody3$advice(Bar.java:22)
    at my.thirdparty.application.Bar.bar(Bar.java:21)
    at my.thirdparty.application.Bar.doSomething(Bar.java:8)
    at de.scrum_master.app.Application.main(Application.java:7)

call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.anotherMethod())
java.lang.Exception: printing stack trace
    at my.thirdparty.application.Bar.foo_aroundBody5$advice(Bar.java:22)
    at my.thirdparty.application.Bar.anotherMethod(Bar.java:28)
    at my.thirdparty.application.Bar.bar(Bar.java:23)
    at my.thirdparty.application.Bar.doSomething(Bar.java:8)
    at de.scrum_master.app.Application.main(Application.java:7)

We are getting better and better: down to 2 interceptions from 6. The one from Bar.anotherMethod is still unwanted because it was only indirectly triggered by Bar.bar and our ambition is to only intercept direct calls. Okay, then let us get even more precise:

Aspect, part #4: intercept calls to Foo.foo made directly by Bar.bar, no indirection permitted

package de.scrum_master.aspect;

import my.thirdparty.application.Foo;
import my.thirdparty.application.Bar;

public aspect MethodInterceptor {
    pointcut directCalls(Bar barObject) :
        call(* Foo.foo(..)) && cflow(execution(* Bar.bar(..))) && this(barObject) &&
        if("bar".equals(thisEnclosingJoinPointStaticPart.getSignature().getName()));

    Object around(Foo fooObject, Bar barObject) : directCalls(barObject) && target(fooObject) {
        System.out.println(thisJoinPointStaticPart + " -> caller = " + thisEnclosingJoinPointStaticPart);
        new Exception("printing stack trace").printStackTrace(System.out);
        System.out.println();
        return proceed(fooObject, barObject);
    }
}

Console log:

call(void my.thirdparty.application.Foo.foo()) -> caller = execution(void my.thirdparty.application.Bar.bar())
java.lang.Exception: printing stack trace
    at my.thirdparty.application.Bar.foo_aroundBody3$advice(Bar.java:22)
    at my.thirdparty.application.Bar.bar(Bar.java:21)
    at my.thirdparty.application.Bar.doSomething(Bar.java:8)
    at de.scrum_master.app.Application.main(Application.java:7)

Et voilà! This is what we wanted in the first place. Let us recapitulate what we have just done in order to narrow down the pointcut:

  • call(* Foo.foo(..)) - only calls to Foo.foo
  • cflow(execution(* Bar.bar(..))) - only with the execution of Bar.bar in the control flow
  • this(barObject) - the caller must be a Bar object
  • target(fooObject) - the callee must be a Foo object
  • if("bar".equals(thisEnclosingJoinPointStaticPart.getSignature().getName())) - a dynamic runtime condition checks if the direct caller's method name is really bar

I hope this solves your problem and was not too verbose. I wanted to do it tutorial-style so as to enable you to understand how to solve advanced AOP problems like this one. Enjoy!

Question:

I looked at many Aspectj tutorials in web and most of them are: Aspectj config with Spring beans. Per my understanding, if I am using

javaagent:./src/main/resources/aspectjweaver.jar and if I created aop.xml, aspectj weaving will work for all classes and objects (including those managed by Spring).

Why do I need to enable weaving in Spring? (like in this tutorial). What's the benefit of doing:

<!-- this switches on the load-time weaving -->
    <context:load-time-weaver/>

Answer:

AspectJ does not require Spring. You can use aspectJ in your applications and benefit from the AOP paradigm.

Spring makes things a bit easier providing instrumentation to perform load-time-weaving easily, detecting Sun's GlassFish, Oracle's OC4J, Spring's VM agent and any ClassLoader supported by Spring's ReflectiveLoadTimeWeaver.

For example, in case of Tomcat, Spring offers TomcatInstrumentableClassLoader which adds instrumentation to loaded classes without the need to use a VM-wide agent.

On the other hand, spring provides aspectJ integration which goes beyond the scope of your question. But basically allows you to handle non managed spring beans in many ways (dependency injection, transactions...).

Question:

I want to create the following Java annotation, and process it at build time:

@Target(value = FIELD)
interface @AnnotateGetter {
    Annotation[] value();
}

If a field field is annotated with @AnnotateGetter, then all of the Annotations in the value array are added to the method getField() of the same class, if such a method exists.

What is the easiest way to do this?

  1. ApectJ, which can add an annotation to a method with a declare annotation statement, but, while I know how to select a field that is annotated with @AnnotateGetter, I don't know how to select a method that corresponds to a field that is annotated with @AnnotateGetter
  2. Some other AOP framework
  3. Writing my own javax.annotation.processing.Processor that calls some library that can add an annotation to a method. What are the best options for such a library? Would it have to manipulate bytecode after javac compiled the source file, or could I somehow hook into javac & add the annotations during compilation, before the class file has been generated?
  4. something else...

Answer:

Here is a solution using APT (annotation processing tool) via AspectJ. It adds the specified annotations to getter methods, but does not remove them from fields. So this is a "copy" action, not a "move".

Annotation processing support was added to AspectJ in version 1.8.2 and described in the release notes. Here is some self-consistent sample code. I compiled it from the command line because from Eclipse I failed to get it running according to AspectJ maintainer Andy Clement's description.

Okay, let's say we have one (Eclipse or other) project directory and the directory layout be like this:

SO_AJ_APT_MoveAnnotationsFromMemberToGetter
    compile_run.bat
    src
        de/scrum_master/app/Person.java
    src_apt
        de/scrum_master/app/AnnotatedGetterProcessor.java
        de/scrum_master/app/AnnotateGetter.java
        de/scrum_master/app/CollationType.java
        de/scrum_master/app/SortOrder.java
        de/scrum_master/app/Unique.java
        META-INF/services/javax.annotation.processing.Processor

Both src and src_apt are source directories, compile_run.bat is a Windows batch file building the project in two stages (annotation processor first, then the rest of the project) and running the final result in order to prove that it actually does what it should.

Annotations to be used for fields and later copied to getter methods:

package de.scrum_master.app;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface Unique {}
package de.scrum_master.app;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface SortOrder {
    String value() default "ascending";
}
package de.scrum_master.app;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface CollationType {
    String value() default "alphabetical";
    String language() default "EN";
}

Meta annotation designating field annotations to be copied to getter methods:

Please note that this meta annotation is only needed for annotation processing and thus has a SOURCE retention scope.

package de.scrum_master.app;

import java.lang.annotation.*;

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface AnnotateGetter {
    Class<? extends Annotation>[] value();
}

Driver application:

Things to be noted:

  • There are four fields with annotations (id, firstName, lastName, fieldWithoutGetter), but only the first three have corresponding getter methods, the last one does not. So we expect fieldWithoutGetter to be handled gracefully later, either an empty or no ITD aspect being generated later via APT.

  • The meta annotation @AnnotateGetter({ Unique.class, SortOrder.class, CollationType.class }) on class Person specifies which annotations to consider for copying them to getter methods. Later you can play around with it and see how the result changes if you remove any of them.

  • We also have some dummy methods doSomething() and doSomethingElse() which should be unaffected by any annotation copying later, i.e. they should not get any new annotations via AspectJ. (It is always good to have a negative test case.)

  • The main(..) method uses reflection to print all fields and methods including their annotations.

package de.scrum_master.app;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

@AnnotateGetter({ Unique.class, SortOrder.class, CollationType.class })
public class Person {
    @Unique
    private final int id;

    @SortOrder("descending")
    @CollationType("alphabetical")
    private final String firstName;

    @SortOrder("random")
    @CollationType(value = "alphanumeric", language = "DE")
    private final String lastName;

    @SortOrder("ascending")
    @CollationType(value = "numeric")
    private final int fieldWithoutGetter;

    public Person(int id, String firstName, String lastName, int fieldWithoutGetter) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
        this.fieldWithoutGetter = fieldWithoutGetter;
    }

    public int getId() { return id; }
    public String getFirstName() { return firstName; }
    public String getLastName() { return lastName; }
    public void doSomething() {}
    public void doSomethingElse() {}

    public static void main(String[] args) {
        System.out.println("Field annotations:");
        for (Field field : Person.class.getDeclaredFields()) {
            System.out.println("  " + field.getName());
            for (Annotation annotation : field.getAnnotations())
                System.out.println("    " + annotation);
        }
        System.out.println();
        System.out.println("Method annotations:");
        for (Method method : Person.class.getDeclaredMethods()) {
            System.out.println("  " + method.getName());
            for (Annotation annotation : method.getAnnotations())
                System.out.println("    " + annotation);
        }
    }
}

Console output without APT + AspectJ:

As you can see, the field annotations are printed, but no method annotations because we have yet to define an annotation processor (see further below).

Field annotations:
  id
    @de.scrum_master.app.Unique()
  firstName
    @de.scrum_master.app.SortOrder(value=descending)
    @de.scrum_master.app.CollationType(value=alphabetical, language=EN)
  lastName
    @de.scrum_master.app.SortOrder(value=random)
    @de.scrum_master.app.CollationType(value=alphanumeric, language=DE)
  fieldWithoutGetter
    @de.scrum_master.app.SortOrder(value=ascending)
    @de.scrum_master.app.CollationType(value=numeric, language=EN)

Method annotations:
  main
  getId
  doSomething
  doSomethingElse
  getFirstName
  getLastName

Annotation processor:

Now we need an annotation processor generating an aspect for each combination of field and annotation to be copied. Such an aspect should look like this:

package de.scrum_master.app;

public aspect AnnotateGetterAspect_Person_CollationType_lastName {
    declare @method : * Person.getLastName() : @de.scrum_master.app.CollationType(value = "alphanumeric", language = "DE");
}

Very simple, is it not? The annotation processor should generate those aspects into a directory .apt_generated. The AspectJ compiler will handle that for us, as we will see later. But first here is the annotation processor (sorry for the lenghty code, but this is what you asked for):

package de.scrum_master.app;

import java.io.*;
import java.util.*;

import javax.tools.*;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;

@SupportedAnnotationTypes(value = { "*" })
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class AnnotatedGetterProcessor extends AbstractProcessor {
    private Filer filer;

    @Override
    public void init(ProcessingEnvironment env) {
        filer = env.getFiler();
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean process(
        Set<? extends TypeElement> elements,
        RoundEnvironment env
    ) {

        // Get classes annotated with something like: @AnnotateGetter({ Foo.class, Bar.class, Zot.class })
        env.getElementsAnnotatedWith(AnnotateGetter.class)
            .stream()
            .filter(annotatedClass -> annotatedClass.getKind() == ElementKind.CLASS)

            // For each filtered class, copy designated field annotations to corresponding getter method, if present
            .forEach(annotatedClass -> {
                String packageName = annotatedClass.getEnclosingElement().toString().substring(8);
                String className = annotatedClass.getSimpleName().toString();

                /*
                 * Unfortunately when we do something like this:
                 *   AnnotateGetter annotateGetter = annotatedClass.getAnnotation(AnnotateGetter.class);
                 *   Class<? extends Annotation> annotationToBeConverted = annotateGetter.value()[0];
                 * We will get this exception:
                 *   Internal compiler error:
                 *     javax.lang.model.type.MirroredTypesException:
                 *       Attempt to access Class objects for TypeMirrors
                 *       [de.scrum_master.app.Unique, de.scrum_master.app.SortOrder, de.scrum_master.app.CollationType]
                 *       at org.aspectj.org.eclipse.jdt.internal.compiler.apt.model.AnnotationMirrorImpl.getReflectionValue
                 *
                 * Thus, we have to use annotation mirrors instead of annotation classes directly,
                 * then tediously extracting annotation values from a nested data structure. :-(
                 */

                // Find @AnnotateGetter annotation and extract its array of values from deep within
                ((List<? extends AnnotationValue>) annotatedClass.getAnnotationMirrors()
                    .stream()
                    .filter(annotationMirror -> annotationMirror.getAnnotationType().toString().equals(AnnotateGetter.class.getName()))
                    .map(AnnotationMirror::getElementValues)
                    .map(Map::values)
                    .findFirst()
                    .get()
                    .stream()
                    .map(AnnotationValue::getValue)
                    .findFirst()
                    .get()
                )
                    .stream()
                    .map(annotationValueToBeCopied -> (TypeElement) ((DeclaredType) annotationValueToBeCopied.getValue()).asElement())
                    // For each annotation to be copied, get all correspondingly annotated fields
                    .forEach(annotationTypeElementToBeCopied -> {
                        env.getElementsAnnotatedWith(annotationTypeElementToBeCopied)
                            .stream()
                            .filter(annotatedField -> ((Element) annotatedField).getKind() == ElementKind.FIELD)
                            // For each annotated field create an ITD aspect
                            .forEach(annotatedField -> {
                                String fieldName = annotatedField.getSimpleName().toString();
                                String aspectName =
                                    "AnnotateGetterAspect_" + className + "_" +
                                    annotationTypeElementToBeCopied.getSimpleName() + "_" + fieldName;

                                StringBuilder annotationDeclaration = new StringBuilder()
                                    .append("@" + annotationTypeElementToBeCopied.getQualifiedName() + "(");

                                annotatedField.getAnnotationMirrors()
                                    .stream()
                                    .filter(annotationMirror -> annotationMirror.getAnnotationType().toString().equals(annotationTypeElementToBeCopied.getQualifiedName().toString()))
                                    .map(AnnotationMirror::getElementValues)
                                    .forEach(annotationParameters -> {
                                        annotationParameters.entrySet()
                                            .stream()
                                            .forEach(annotationParameter -> {
                                                ExecutableElement annotationParameterType = annotationParameter.getKey();
                                                AnnotationValue annotationParameterValue = annotationParameter.getValue();
                                                annotationDeclaration.append(annotationParameterType.getSimpleName() + " = ");
                                                if (annotationParameterType.getReturnType().toString().equals("java.lang.String"))
                                                    annotationDeclaration.append("\"" + annotationParameterValue + "\"");
                                                else
                                                    annotationDeclaration.append(annotationParameterValue);
                                                annotationDeclaration.append(", ");
                                            });
                                        if (!annotationParameters.entrySet().isEmpty())
                                            annotationDeclaration.setLength(annotationDeclaration.length() - 2);
                                        annotationDeclaration.append(")");
                                    });

                                // For each field with the current annotation, create an ITD aspect
                                // adding the same annotation to the member's getter method
                                String aspectSource = createAspectSource(
                                    annotatedClass, packageName, className,
                                    annotationDeclaration.toString(), fieldName, aspectName
                                );
                                writeAspectSourceToDisk(packageName, aspectName, aspectSource);
                            });
                    });
            });
        return true;
    }

    private String createAspectSource(
        Element parentElement,
        String packageName,
        String className,
        String annotationDeclaration,
        String fieldName,
        String aspectName
    ) {
        String getterMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);

        StringBuilder aspectSource = new StringBuilder()
            .append("package " + packageName + ";\n\n")
            .append("public aspect " + aspectName + " {\n");

        for (Element childElement : parentElement.getEnclosedElements()) {
            // Search for methods
            if (childElement.getKind() != ElementKind.METHOD)
                continue;
            ExecutableElement method = (ExecutableElement) childElement;

            // Search for correct getter method name
            if (!method.getSimpleName().toString().equals(getterMethodName))
                continue;
            // Parameter list for a getter method must be empty
            if (!method.getParameters().isEmpty())
                continue;
            // Getter method must be public
            if (!method.getModifiers().contains(Modifier.PUBLIC))
                continue;
            // Getter method must be non-static
            if (method.getModifiers().contains(Modifier.STATIC))
                continue;

            // Add call to found method
            aspectSource.append(
                "    declare @method : * " + className + "." + getterMethodName + "() : " +
                annotationDeclaration + ";\n"
            );
        }

        aspectSource.append("}\n");

        return aspectSource.toString();
    }

    private void writeAspectSourceToDisk(
        String packageName,
        String aspectName,
        String aspectSource
    ) {
        try {
            JavaFileObject file = filer.createSourceFile(packageName + "." + aspectName);
            file.openWriter().append(aspectSource).close();
            System.out.println("Generated aspect " + packageName + "." + aspectName);
        } catch (IOException ioe) {
            // Message "already created" can appear if processor runs more than once
            if (!ioe.getMessage().contains("already created"))
                ioe.printStackTrace();
        }
    }
}

I am not going to say much about the annotation processor, please read it carefully. I also added some source code comments, hopefully they are good enough to be understood.

src_apt/META-INF/services/javax.annotation.processing.Processor:

We need this file for the annotation processor to work later in connection with the AspectJ compiler (ajc).

de.scrum_master.app.AnnotatedGetterProcessor

Batch file building and running the project:

Sorry if this is platform-specific, but I guess you can easily convert it into a UNIX/Linux shell script, it is quite straightforward.

@echo off

set SRC_PATH=C:\Users\Alexander\Documents\java-src
set ASPECTJ_HOME=C:\Program Files\Java\AspectJ

echo Building annotation processor
cd "%SRC_PATH%\SO_AJ_APT_MoveAnnotationsFromMemberToGetter"
rmdir /s /q bin
del /q processor.jar
call "%ASPECTJ_HOME%\bin\ajc.bat" -1.8 -sourceroots src_apt -d bin -cp "%ASPECTJ_HOME%\lib\aspectjrt.jar"
jar -cvf processor.jar -C src_apt META-INF -C bin .

echo.
echo Generating aspects and building project
rmdir /s /q bin .apt_generated
call "%ASPECTJ_HOME%\bin\ajc.bat" -1.8 -sourceroots src -d bin -s .apt_generated -inpath processor.jar -cp "%ASPECTJ_HOME%\lib\aspectjrt.jar";processor.jar -showWeaveInfo

echo.
echo Running de.scrum_master.app.Person
java -cp bin;"%ASPECTJ_HOME%\lib\aspectjrt.jar" de.scrum_master.app.Person

Console log for build + run process:

Building the processor + annotation classes, then packaging them into a processor.jar:

Building annotation processor
Manifest wurde hinzugefügt
Eintrag META-INF/ wird ignoriert
META-INF/services/ wird hinzugefügt(ein = 0) (aus = 0)(0 % gespeichert)
META-INF/services/javax.annotation.processing.Processor wird hinzugefügt(ein = 45) (aus = 46)(-2 % verkleinert)
de/ wird hinzugefügt(ein = 0) (aus = 0)(0 % gespeichert)
de/scrum_master/ wird hinzugefügt(ein = 0) (aus = 0)(0 % gespeichert)
de/scrum_master/app/ wird hinzugefügt(ein = 0) (aus = 0)(0 % gespeichert)
de/scrum_master/app/AnnotatedGetterProcessor.class wird hinzugefügt(ein = 8065) (aus = 3495)(56 % verkleinert)
de/scrum_master/app/AnnotateGetter.class wird hinzugefügt(ein = 508) (aus = 287)(43 % verkleinert)
de/scrum_master/app/CollationType.class wird hinzugefügt(ein = 520) (aus = 316)(39 % verkleinert)
de/scrum_master/app/SortOrder.class wird hinzugefügt(ein = 476) (aus = 296)(37 % verkleinert)
de/scrum_master/app/Unique.class wird hinzugefügt(ein = 398) (aus = 248)(37 % verkleinert)

Aspect generation + project build (done with just one AspectJ compiler call because of its built-in annotation processing support):

Generating aspects and building project
Generated aspect de.scrum_master.app.AnnotateGetterAspect_Person_Unique_id
Generated aspect de.scrum_master.app.AnnotateGetterAspect_Person_SortOrder_fieldWithoutGetter
Generated aspect de.scrum_master.app.AnnotateGetterAspect_Person_SortOrder_firstName
Generated aspect de.scrum_master.app.AnnotateGetterAspect_Person_SortOrder_lastName
Generated aspect de.scrum_master.app.AnnotateGetterAspect_Person_CollationType_fieldWithoutGetter
Generated aspect de.scrum_master.app.AnnotateGetterAspect_Person_CollationType_firstName
Generated aspect de.scrum_master.app.AnnotateGetterAspect_Person_CollationType_lastName
'public int de.scrum_master.app.Person.getId()' (Person.java:31) is annotated with @de.scrum_master.app.Unique method annotation from 'de.scrum_master.app.AnnotateGetterAspect_Person_Unique_id' (AnnotateGetterAspect_Person_Unique_id.java:4)

'public java.lang.String de.scrum_master.app.Person.getFirstName()' (Person.java:32) is annotated with @de.scrum_master.app.SortOrder method annotation from 'de.scrum_master.app.AnnotateGetterAspect_Person_SortOrder_firstName' (AnnotateGetterAspect_Person_SortOrder_firstName.java:4)

'public java.lang.String de.scrum_master.app.Person.getFirstName()' (Person.java:32) is annotated with @de.scrum_master.app.CollationType method annotation from 'de.scrum_master.app.AnnotateGetterAspect_Person_CollationType_firstName' (AnnotateGetterAspect_Person_CollationType_firstName.java:4)

'public java.lang.String de.scrum_master.app.Person.getLastName()' (Person.java:33) is annotated with @de.scrum_master.app.CollationType method annotation from 'de.scrum_master.app.AnnotateGetterAspect_Person_CollationType_lastName' (AnnotateGetterAspect_Person_CollationType_lastName.java:4)

'public java.lang.String de.scrum_master.app.Person.getLastName()' (Person.java:33) is annotated with @de.scrum_master.app.SortOrder method annotation from 'de.scrum_master.app.AnnotateGetterAspect_Person_SortOrder_lastName' (AnnotateGetterAspect_Person_SortOrder_lastName.java:4)

Last, but not least, we run the driver application again. This time we should see the annotations copied from the annotated fields to the corresponding getter methods (if such methods exist):

Running de.scrum_master.app.Person
Field annotations:
  id
    @de.scrum_master.app.Unique()
  firstName
    @de.scrum_master.app.SortOrder(value=descending)
    @de.scrum_master.app.CollationType(value=alphabetical, language=EN)
  lastName
    @de.scrum_master.app.SortOrder(value=random)
    @de.scrum_master.app.CollationType(value=alphanumeric, language=DE)
  fieldWithoutGetter
    @de.scrum_master.app.SortOrder(value=ascending)
    @de.scrum_master.app.CollationType(value=numeric, language=EN)

Method annotations:
  main
  getId
    @de.scrum_master.app.Unique()
  doSomethingElse
  getLastName
    @de.scrum_master.app.CollationType(value=alphanumeric, language=DE)
    @de.scrum_master.app.SortOrder(value=random)
  getFirstName
    @de.scrum_master.app.SortOrder(value=descending)
    @de.scrum_master.app.CollationType(value=alphabetical, language=EN)
  doSomething

Voilà! Enjoy and feel free to ask questions. :-)

Update (2015-05-03): Attention, in my annotation processor code I initially forgot to also copy the annotation parameter values, thus only the default values were created for each annotation. I have just fixed that, making the annotation processor code even more lengthy. Because I wanted to make it worthwhile refactoring the code and learn something from it, even though you have already accepted the original answer and solved your problem in another way anyway, I played around with Java 8 stuff like lambdas, streams, filters, maps. This is not particularly readable if the concept is new to you, especially for nested forEach loops, but I wanted to try and see how far I can get with it. ;-)

Question:

I am creating an aspect to register my application using org.springframework.web.bind.annotation.RestController like @Pointcut, this works perfectly when my class responds normally, but when an exception occurs for some reason, the returned httpStatus is always 200, even If my http response returns 500 when an error occurs, I think this is because RestController does not set the http status, but delegates it to the exception handler, how do I fix this and still have traceability on top of the restcontroller?

Follow my rest controller

@Slf4j
@RestController
@RequestMapping("/api/conta")
public class ContaResourceHTTP {


    @JetpackMethod("Pagamento de conta")
    @PostMapping("/pagamento")
    public void realizarPagamento(@RequestBody DTOPagamento dtoPagamento) throws InterruptedException
    {

    }

    @JetpackMethod("Transferência entre bancos")
    @PostMapping("/ted")
    public void realizarTED(@RequestBody DTOPagamento dtoPagamento) throws java.lang.Exception
    {
        if(true)
            throw new Exception("XXX");
        //log.info(dtoPagamento.toString());
    }

}

my AOP implementation:

@Aspect
@Component
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Slf4j
public class MetricsAspect {

    //@Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    @Pointcut("execution(* javax.servlet.http.HttpServlet.*(..)) *)")
    public void springBeanPointcut() {
    }

    @Autowired
    Tracer tracer;

    @Around("springBeanPointcut()")
    public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getRequest();

        long inicioProcesso = System.currentTimeMillis();

        joinPoint.proceed();

        long finalProcesso = System.currentTimeMillis();

        long duracaoProcesso = finalProcesso - inicioProcesso;

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getResponse();

        Metrics metricas = new Metrics();

        metricas.setDuracaoMs(duracaoProcesso);
        metricas.setDataHoraRequisicao(milissegundosToStringDate(inicioProcesso));
        metricas.setDataHoraResposta(milissegundosToStringDate(finalProcesso));
        metricas.setServidorOrigem(request.getRemoteAddr());
        metricas.setPortaOrigem(request.getRemotePort());
        metricas.setDominioAcesso(request.getLocalName());
        metricas.setPortaAcesso(request.getLocalPort());
        metricas.setUrlPath(request.getRequestURI());
        metricas.setMetodoHttp(request.getMethod());
        metricas.setIdTransacao(tracer.currentSpan().context().traceIdString());
        metricas.setIdSpan(tracer.currentSpan().context().spanIdString());
        metricas.setStatusHttp(response.getStatus());

        log.info(JSONConversor.toJSON(metricas));

    }

    public String milissegundosToStringDate(long ms) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

        Date dataInicial = new Date(ms);

        return dateFormat.format(dataInicial);
    }
}

My exception handler:

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ExceptionControllerAdvice {


    @ExceptionHandler({ Throwable.class })
    public ResponseEntity<ApiError> handlerValidationException2(Throwable e) {
        return new ResponseEntity<>(new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, e, traceRespostaAPI),
                HttpStatus.INTERNAL_SERVER_ERROR);
    }


}

Answer:

After a while I was able to solve the problem with a solution that may not be the most elegant for the problem, basically I used two pointcuts, one in the restcontroller to intercept the @JetpackMethod annotation value and add it to the http response header with advice before and another around HttpServlet that really is the one who really gets back with the modified http status.

Here's the code below that solved my problem.

This class intercepts annotation and adds its value to the header.

@Aspect
@Component
public class InterceptRestAnnotationAspect {

    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    public void restControllerExecution() {}


    @Before("restControllerExecution()")
    public void setMetodoHttpHeader(JoinPoint joinPoint) throws Throwable {

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getResponse();

        String origem = VerificadorOrigem.processarOrigem(joinPoint);

        response.setHeader("nomeMetodo", origem);

    }

}

This other class logs the servlet metrics I needed and can retrieve the value entered in the header earlier.

@Aspect
@Component
@Slf4j
public class MetricsAspect {

    @Pointcut("execution(* javax.servlet.http.HttpServlet.*(..)) *)")
    public void servletService() {
    }

    @Autowired
    Tracer tracer;

    @Around("servletService()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getRequest();

        long inicioProcesso = System.currentTimeMillis();

        Object result = joinPoint.proceed();

        long finalProcesso = System.currentTimeMillis();

        long duracaoProcesso = finalProcesso - inicioProcesso;

        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getResponse();

        Metrics metricas = new Metrics();

        String funcionalidade = response.getHeader("nomeMetodo") == null ? "Indeterminada"
                : response.getHeader("nomeMetodo");

        metricas.setNivelLog("INFO");
        metricas.setFuncionalidade(funcionalidade);
        metricas.setDuracaoMs(duracaoProcesso);
        metricas.setDataHoraRequisicao(ManipulaData.milissegundosToStringDate(inicioProcesso));
        metricas.setDataHoraResposta(ManipulaData.milissegundosToStringDate(finalProcesso));
        metricas.setServidorOrigem(request.getRemoteAddr());
        metricas.setPortaOrigem(request.getRemotePort());
        metricas.setDominioAcesso(request.getLocalName());
        metricas.setPortaAcesso(request.getLocalPort());
        metricas.setUrlPath(request.getRequestURI());
        metricas.setMetodoHttp(request.getMethod());
        metricas.setIdTransacao(tracer.currentSpan().context().traceIdString());
        metricas.setIdSpan(tracer.currentSpan().context().spanIdString());
        metricas.setStatusHttp(response.getStatus());

        log.info(JSONConversor.toJSON(metricas));

        return result;

    }
}

Question:

I'm trying to create a custom annotation for my project. Here it is -

DataSourcePicker (annotation):

   import java.lang.annotation.ElementType;
   import java.lang.annotation.Retention;
   import java.lang.annotation.RetentionPolicy;
   import java.lang.annotation.Target;

   @Target({ElementType.METHOD, ElementType.TYPE})
   @Retention(RetentionPolicy.RUNTIME)
       public @interface DataSourcePicker {

   }

I've implemented the DataSourcePicker annotation using AOP like this -

DataSourcePickerAspect:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DataSourcePickerAspect implements Ordered {

    private int order;

    @Value("10")
    public void setOrder(int order) {
        this.order = order;
    }

    @Override
    public int getOrder() {
        return order;
    }

    @Pointcut(value="execution(public * *(..))")
    public void anyPublicMethod() { }


    @Around("@annotation(dataSourcePicker)")
    public Object pickDataSource(ProceedingJoinPoint pjp, 
    DataSourcePicker dataSourcePicker) throws Throwable {
        //some code...
    }
}  

With having these above all set up when I try to annotate my service class like this -

(Good Approach):

   @Service
   @DataSourcePiceker
   public SomeServiceClass{     
       pubic void method1(){}
       pubic int method2(List<Integer> list){}
       pubic String method3(String a, String b){}
   }

The above code (SomeServiceClass) compiles fine. But neither of the methods are affected by the aspect(DataSourcePicker) I've written. But when I annotate my methods with DataSourcePicker it works as expected - all methods are intercepted by the DataSourcePickerAspect's @Around advice -

(Not So Good Approach, I guess):

   @Service
   @DataSourcePiceker
   public SomeServiceClass{
       @DataSourcePiceker     
       pubic void method1(){}

       @DataSourcePiceker
       pubic int method2(List<Integer> list){}

       @DataSourcePiceker
       pubic String method3(String a, String b){}
   }  

Can someone help me how to can I achieve the Good Approach? All I want to create an annotation and annotate a class with it while all methods of the class will be affected.

Thanks in advance


Answer:

With @annotation(my.fancy.Annotation) you intercept annotated methods, while @within(my.fancy.Annotation) matches annotated classes, as documented in the Spring manual. Maybe you want to read it before using Spring AOP via trial & error.

Question:

I need to log whenever a RESTendpoint gets called. I'm trying to do this with spring AOP.

Among other things I need to long what endpoint was called. I.e I need to read out the value of the Mapping annotation.

I want to solve this in a generic way. I.e "Give me the value of the Mapping whatever the exact mapping is".

So what I was doing for now is basically what was proposed in this answer: https://stackoverflow.com/a/26945251/2995907

@Pointcut("@annotation(getMapping)")
    public void getMappingAnnotations(GetMapping getMapping){ }

Then I pass getMapping to my advice and get out the value of that.

To be able to select whatever mapping I encounter I was following the accepted answer from this question: Spring Aspectj @Before all rest method

@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) " +
    "|| @annotation(org.springframework.web.bind.annotation.GetMapping)" +
    "|| @annotation(org.springframework.web.bind.annotation.PostMapping)" +
    "|| @annotation(org.springframework.web.bind.annotation.PathVariable)" +
    "|| @annotation(org.springframework.web.bind.annotation.PutMapping)" +
    "|| @annotation(org.springframework.web.bind.annotation.DeleteMapping)"
)
public void mappingAnnotations() {}

I'd like to just write something like

public void mappingAnnotations(RequestMapping requestMapping) {}

and then get the value out of it, since all the Mappings are aliases for RequestMapping. Unfortunately, this did not work. Until now it looks like I have to do a separate pointcut for every kind of mapping and then having a method for each of them (which would be very similar - not very DRY) or quite an ugly if-else-block (maybe I could make it a switch with some fiddeling).

So the question is how I could solve this in a clean way. I just want to log any kind of mapping and get the corresponding path-argument which the annotation carries.


Answer:

I would have given the same answer as Nándor under usual circumstances. AspectJ bindings to parameters from different branches of || are ambiguous because both branches could match, so this is a no-go.

With regard to @RequestMapping, all the other @*Mapping annotations are syntactic sugar and documented to be composed annotations acting as shortcuts, see e.g. @GetMapping:

Specifically, @GetMapping is a composed annotation that acts as a shortcut for @RequestMapping(method = RequestMethod.GET).

I.e. the type GetMapping itself is annotated by @RequestMapping(method = RequestMethod.GET). The same applies to the other composed (syntactic sugar) annotations. We can utilise this circumstance for our aspect.

AspectJ has a syntax for finding an annotated annotation (also nested), see e.g. my answer here. We can use that syntax in this case in order to generically match all annotations annotated by @RequestMapping.

This still leaves us with two cases, i.e. direct annotation and syntactic sugar annotation, but it simplifies the code a bit anyway. I came up with this pure Java + AspectJ sample application, only imported the spring-web JAR in order to have access to the annotations. I do not use Spring otherwise, but the pointcuts and advice would look the same in Spring AOP, you can even eliminate the && execution(* *(..)) part from the first pointcut because Spring AOP does not know anything but execution pointcuts anyway (but AspectJ does and would also match call(), for instance).

Driver application:

package de.scrum_master.app;

import org.springframework.web.bind.annotation.*;
import static org.springframework.web.bind.annotation.RequestMethod.*;

public class Application {
  @GetMapping public void get() {}
  @PostMapping public void post() {}
  @RequestMapping(method = HEAD) public void head() {}
  @RequestMapping(method = OPTIONS) public void options() {}
  @PutMapping public void put() {}
  @PatchMapping public void patch() {}
  @DeleteMapping @Deprecated public void delete() {}
  @RequestMapping(method = TRACE) public void trace() {}
  @RequestMapping(method = { GET, POST, HEAD}) public void mixed() {}

  public static void main(String[] args) {
    Application application = new Application();
    application.get();
    application.post();
    application.head();
    application.options();
    application.put();
    application.patch();
    application.delete();
    application.trace();
    application.mixed();
  }
}

Please note how I mixed different annotation types and how I also added another annotation @Deprecated to one method in order to have a negative test case for an annotation we are not interested in.

Aspect:

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Aspect
public class RequestMappingAspect {

  @Before("@annotation(requestMapping) && execution(* *(..))")
  public void genericMapping(JoinPoint thisJoinPoint, RequestMapping requestMapping) {
    System.out.println(thisJoinPoint);
    for (RequestMethod method : requestMapping.method())
      System.out.println("  " + method);
  }

  @Before("execution(@(@org.springframework.web.bind.annotation.RequestMapping *) * *(..))")
  public void metaMapping(JoinPoint thisJoinPoint) {
    System.out.println(thisJoinPoint);
    for (Annotation annotation : ((MethodSignature) thisJoinPoint.getSignature()).getMethod().getAnnotations()) {
      RequestMapping requestMapping = annotation.annotationType().getAnnotation(RequestMapping.class);
      if (requestMapping == null)
        continue;
      for (RequestMethod method : requestMapping.method())
        System.out.println("  " + method);
    }
  }

}

Console log:

execution(void de.scrum_master.app.Application.get())
  GET
execution(void de.scrum_master.app.Application.post())
  POST
execution(void de.scrum_master.app.Application.head())
  HEAD
execution(void de.scrum_master.app.Application.options())
  OPTIONS
execution(void de.scrum_master.app.Application.put())
  PUT
execution(void de.scrum_master.app.Application.patch())
  PATCH
execution(void de.scrum_master.app.Application.delete())
  DELETE
execution(void de.scrum_master.app.Application.trace())
  TRACE
execution(void de.scrum_master.app.Application.mixed())
  GET
  POST
  HEAD

It is not perfect with regard to DRY, but we can only go as far as possible. I still think it is compact, readable and maintainable without having to list every single annotation type to be matched.

What do you think?


Update:

If you want to get the values for "syntactic sugar" request mapping annotations, the whole code looks like this:

package de.scrum_master.app;

import org.springframework.web.bind.annotation.*;
import static org.springframework.web.bind.annotation.RequestMethod.*;

public class Application {
  @GetMapping public void get() {}
  @PostMapping(value = "foo") public void post() {}
  @RequestMapping(value = {"foo", "bar"}, method = HEAD) public void head() {}
  @RequestMapping(value = "foo", method = OPTIONS) public void options() {}
  @PutMapping(value = "foo") public void put() {}
  @PatchMapping(value = "foo") public void patch() {}
  @DeleteMapping(value = {"foo", "bar"}) @Deprecated public void delete() {}
  @RequestMapping(value = "foo", method = TRACE) public void trace() {}
  @RequestMapping(value = "foo", method = { GET, POST, HEAD}) public void mixed() {}

  public static void main(String[] args) {
    Application application = new Application();
    application.get();
    application.post();
    application.head();
    application.options();
    application.put();
    application.patch();
    application.delete();
    application.trace();
    application.mixed();
  }
}
package de.scrum_master.aspect;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Aspect
public class RequestMappingAspect {

  @Before("@annotation(requestMapping) && execution(* *(..))")
  public void genericMapping(JoinPoint thisJoinPoint, RequestMapping requestMapping) {
    System.out.println(thisJoinPoint);
    for (String value : requestMapping.value())
      System.out.println("  value = " + value);
    for (RequestMethod method : requestMapping.method())
      System.out.println("  method = " + method);
  }

  @Before("execution(@(@org.springframework.web.bind.annotation.RequestMapping *) * *(..))")
  public void metaMapping(JoinPoint thisJoinPoint) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
    System.out.println(thisJoinPoint);
    for (Annotation annotation : ((MethodSignature) thisJoinPoint.getSignature()).getMethod().getAnnotations()) {
      RequestMapping requestMapping = annotation.annotationType().getAnnotation(RequestMapping.class);
      if (requestMapping == null)
        continue;
      for (String value : (String[]) annotation.annotationType().getDeclaredMethod("value").invoke(annotation))
        System.out.println("  value = " + value);
      for (RequestMethod method : requestMapping.method())
        System.out.println("  method = " + method);
    }
  }

}

The console log then looks like this:

execution(void de.scrum_master.app.Application.get())
  method = GET
execution(void de.scrum_master.app.Application.post())
  value = foo
  method = POST
execution(void de.scrum_master.app.Application.head())
  value = foo
  value = bar
  method = HEAD
execution(void de.scrum_master.app.Application.options())
  value = foo
  method = OPTIONS
execution(void de.scrum_master.app.Application.put())
  value = foo
  method = PUT
execution(void de.scrum_master.app.Application.patch())
  value = foo
  method = PATCH
execution(void de.scrum_master.app.Application.delete())
  value = foo
  value = bar
  method = DELETE
execution(void de.scrum_master.app.Application.trace())
  value = foo
  method = TRACE
execution(void de.scrum_master.app.Application.mixed())
  value = foo
  method = GET
  method = POST
  method = HEAD

Update 2:

If you want to hide the reflection stuff by using Spring's AnnotatedElementUtils and AnnotationAttributes as originally suggested by @M. Prokhorov, you can utilise the fact that with getMergedAnnotationAttributes you can actually get one-stop shopping for both the original RequestMapping annotation and syntax sugar ones like GetMapping, getting both method and value information in a single, merged attribute object. This even enables you to eliminate the two different cases for getting the information and thus merge the two advices into one like this:

package de.scrum_master.aspect;

import static org.springframework.core.annotation.AnnotatedElementUtils.getMergedAnnotationAttributes;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * See https://stackoverflow.com/a/53892842/1082681
 */
@Aspect
public class RequestMappingAspect {
  @Before(
    "execution(@org.springframework.web.bind.annotation.RequestMapping * *(..)) ||" +
    "execution(@(@org.springframework.web.bind.annotation.RequestMapping *) * *(..))"
  )
  public void metaMapping(JoinPoint thisJoinPoint) {
    System.out.println(thisJoinPoint);
      AnnotationAttributes annotationAttributes = getMergedAnnotationAttributes(
        ((MethodSignature) thisJoinPoint.getSignature()).getMethod(),
        RequestMapping.class
      );
      for (String value : (String[]) annotationAttributes.get("value"))
        System.out.println("  value = " + value);
      for (RequestMethod method : (RequestMethod[]) annotationAttributes.get("method"))
        System.out.println("  method = " + method);
  }
}

There you have it: DRY as you originally wished for, fairly readable and maintainable aspect code and access to all (meta) annotation information in an easy way.

Question:

I'm trying to write an aspect, which will intercept all method calls if system property has some specific value. However I don't need any method from advice control flow to be intercepted.

I'm using !cflow(adviceexecution()) expression to achieve this, but it doesn't seem to work in conjunction with if() expression. As a result I'm getting StackOverflowError because of infinite recursion.

Aspect code:

@Aspect
public class SomeAspect {

    @Pointcut("execution(* *.*(..)) && if()")
    public static boolean allMethodCalls() {
        return PropertyReader.hasSpecificProperty();
    }

    @Pointcut("cflow(adviceexecution())")
    public void aspectCalls() {
    }

    @Before("allMethodCalls() && !aspectCalls()")
    public void logSomething() {
        // logging behavior
    }
}

PropertyReader code:

public class PropertyReader {
    public static boolean hasSpecificProperty() {
        return System.getProperty("specificProperty") != null;
    }
}

Answer:

adviceexecution() will not match because your dynamic if() pointcut gets evaluated before the advice gets executed. After all, that is what if() is all about: to decide if an advice should be executed or not.

Let us say, the situation is like this:

package de.scrum_master.app;

public class PropertyReader {
  public static boolean hasSpecificProperty() {
    return System.getProperty("specificProperty") != null;
  }

  public void doSomething(String info) {
    System.out.println("Doing something " + info);
    hasSpecificProperty();
  }

  public static void main(String[] args) {
    System.clearProperty("specificProperty");
    new PropertyReader().doSomething("with inactive property");
    System.setProperty("specificProperty", "true");
    new PropertyReader().doSomething("with active property");
    System.clearProperty("specificProperty");
  }
}

Now the simplest solution would be to pull the hasSpecificProperty() logic right into the aspect itself because it is trivial. You can either define a local static method or just inline it into the if() pointcut:

package de.scrum_master.app;

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

@Aspect
public class SomeAspect {
  @Pointcut("execution(* *(..)) && if()")
  public static boolean allMethodCalls() {
    return System.getProperty("specificProperty") != null;
  }

  @Pointcut("cflow(adviceexecution())")
  public void aspectCalls() {}

  @Before("allMethodCalls() && !aspectCalls()")
  public void logSomething(JoinPoint thisJoinPoint) {
    System.out.println(thisJoinPoint);
    PropertyReader.hasSpecificProperty();
  }
}

This will yield the following console log:

Doing something with inactive property
execution(void de.scrum_master.app.PropertyReader.doSomething(String))
Doing something with active property
execution(boolean de.scrum_master.app.PropertyReader.hasSpecificProperty())

As you can see, there is no problem in calling hasSpecificProperty() from the application or even from the aspect's advice because in the one problematic place there is it is inlined.

If you want to avoid inlining or copying the method into the aspect, you need to do manual bookkeeping within the aspect, I am afraid:

package de.scrum_master.app;

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

@Aspect
public class SomeAspect {
  private static ThreadLocal<Boolean> isInPointcut = new ThreadLocal<Boolean>() {
    @Override protected Boolean initialValue() { return false; }
  };

  @Pointcut("execution(* *(..)) && if()")
  public static boolean allMethodCalls() {
    if (isInPointcut.get())
      return false;
    isInPointcut.set(true);
    boolean result = PropertyReader.hasSpecificProperty();
    isInPointcut.set(false);
    return result;
  }

  @Pointcut("cflow(adviceexecution()) || within(SomeAspect)")
  public void aspectCalls() {}

  @Before("allMethodCalls() && !aspectCalls()")
  public void logSomething(JoinPoint thisJoinPoint) {
    System.out.println(thisJoinPoint);
    PropertyReader.hasSpecificProperty();
  }
}

The console log is identical. Please note that || within(SomeAspect) is necessary so as to avoid capturing the anonymous ThreadLocal class.


Update: This follow-up question was just asked:

I don't quite understand why do we need ThreadLocal instead of simple boolean flag. Could you please explain?

The short answer is: in order to make the aspect thread-safe. If several threads read and write the static member isInPointcut concurrently

  • either you need to synchronise access, making this a performance bottleneck because all threads would have to wait for the aspect to perform its many dynamic checks,
  • or you use a ThreadLocal variable, providing an independent instance of the flag to each thread, thus enabling the threads to proceed concurrently.

If you do neither, your aspect will break, reading wrong values of the flag set by other threads. I will demonstrate it to you. Let's change the demo application as follows:

package de.scrum_master.app;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class PropertyReader {
  private static int callCounter = 0;
  private static final Random RANDOM = new Random();

  public static boolean hasSpecificProperty() {
    synchronized (RANDOM) {
      callCounter++;
    }
    try {
      Thread.sleep(25);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return System.getProperty("specificProperty") != null;
  }

  public void doSomething(String info) {
    System.out.println("Doing something " + info);
    hasSpecificProperty();
  }

  public static int doStuff(final int numThreads, final boolean specificPropertyState) throws InterruptedException {
    if (specificPropertyState)
      System.setProperty("specificProperty", "true");
    else
      System.clearProperty("specificProperty");

    List<Thread> threads = new ArrayList<>();
    long startTime = System.currentTimeMillis();
    callCounter = 0;

    for (int i = 0; i < numThreads; i++) {
      Thread newThread = new Thread(() -> {
        new PropertyReader().doSomething("with active property");
      });
      threads.add(newThread);
      newThread.start();
    }

    for (Thread thread : threads)
      thread.join();

    System.clearProperty("specificProperty");
    System.out.println("Call counter = " + callCounter);
    System.out.println("Duration = " + (System.currentTimeMillis() - startTime) + " ms");
    return callCounter;
  }

  public static void main(String[] args) throws InterruptedException {
    final int NUM_THREADS = 10;
    int callCounterInactiveProperty = doStuff(NUM_THREADS, false);
    int callCounterActiveProperty = doStuff(NUM_THREADS, true);
    int callCounterDelta = callCounterActiveProperty - callCounterInactiveProperty;
    if (callCounterDelta != 3 * NUM_THREADS)
      throw new RuntimeException("Call counter delta should be " + 3 * NUM_THREADS + ", not " + callCounterDelta);
  }
}

You may need a while to understand this code. Basically I do the following:

  • Introduce a new member static int callCounter the purpose of which is that method static boolean hasSpecificProperty() can use it to count how often it was called.
  • Introduce some helper object static final Random RANDOM (could also be any other object type) to synchronise callCounter upon because we cannot synchronise on callCounter itself, even if we make it an Integer instead of an int, because when incrementing the counter we would always have to create a new Integer instance different from the one synchronised upon. I tried, sometimes it counts wrong. Trust me, I tried.
  • Make hasSpecificProperty() slower by adding a Thread.sleep(25) to it, provoking concurrency problems. You said by yourself that your version of that method is more complex than the one you showed in your question.
  • Introduce a new method static int doStuff(final int numThreads, final boolean specificPropertyState) which creates a user-defined number of threads and runs them concurrently with system property specificProperty either set or unset depending on how the user calls doStuff(..). The method then waits until all threads are finished, prints the duration and returns the current value of callCounter. If the aspect works correctly this return value should always be the same for the same method parameters.
  • main(..) now calls doStuff(..) twice, first with inactive system property, then with active one. There should be a difference (delta) between both variants because hasSpecificProperty() gets executed more often if the property is active because from within the aspect advice logSomething(..) it gets called and this advice will only be executed if the system property is active as determined by the if() pointcut.

Now if we run the program the console log says (shortened a bit):

Doing something with active property
Doing something with active property
(...)
Doing something with active property
Doing something with active property
Call counter = 40
Duration = 151 ms
execution(void de.scrum_master.app.PropertyReader.lambda$0())
execution(void de.scrum_master.app.PropertyReader.lambda$0())
(...)
execution(void de.scrum_master.app.PropertyReader.lambda$0())
execution(void de.scrum_master.app.PropertyReader.lambda$0())
execution(void de.scrum_master.app.PropertyReader.doSomething(String))
execution(void de.scrum_master.app.PropertyReader.doSomething(String))
(...)
execution(void de.scrum_master.app.PropertyReader.doSomething(String))
execution(void de.scrum_master.app.PropertyReader.doSomething(String))
Doing something with active property
Doing something with active property
(...)
Doing something with active property
Doing something with active property
execution(boolean de.scrum_master.app.PropertyReader.hasSpecificProperty())
execution(boolean de.scrum_master.app.PropertyReader.hasSpecificProperty())
(...)
execution(boolean de.scrum_master.app.PropertyReader.hasSpecificProperty())
execution(boolean de.scrum_master.app.PropertyReader.hasSpecificProperty())
Call counter = 70
Duration = 180 ms

The call counters always differ by 3 * NUM_THREADS because with active system property three method executions will be intercepted per thread, thus the advice runs 3 times and calls hasSpecificProperty() each time as well.

Now if we "simplify" (thus break) the aspect like this:

package de.scrum_master.app;

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

@Aspect
public class SomeAspect {
  private static boolean isInPointcut = false;

  @Pointcut("execution(* *(..)) && if()")
  public static boolean allMethodCalls() {
    if (isInPointcut)
      return false;
    isInPointcut = true;
    boolean result = PropertyReader.hasSpecificProperty();
    isInPointcut = false;
    return result;
  }

  @Pointcut("cflow(adviceexecution()) || within(SomeAspect)")
  public void aspectCalls() {}

  @Before("allMethodCalls() && !aspectCalls()")
  public void logSomething(JoinPoint thisJoinPoint) {
    System.out.println(thisJoinPoint);
    PropertyReader.hasSpecificProperty();
  }
}

The console log changes to:

Doing something with active property
Doing something with active property
(...)
Doing something with active property
Doing something with active property
Call counter = 13
Duration = 161 ms
Doing something with active property
Doing something with active property
(...)
execution(void de.scrum_master.app.PropertyReader.lambda$0())
execution(void de.scrum_master.app.PropertyReader.doSomething(String))
Doing something with active property
execution(boolean de.scrum_master.app.PropertyReader.hasSpecificProperty())
Call counter = 16
Duration = 190 ms
Exception in thread "main" java.lang.RuntimeException: Call counter delta should be 30, not 3
    at de.scrum_master.app.PropertyReader.main(PropertyReader.java:61)

Uh-oh! The count differs in an unexpected way and you also see that the advice runs only once, afterwards the flag's state is messed up. So your logging, tracing or whatever else the aspect is supposed to do would fail.

Now we could quickly fix that by making the if() pointcut method synchronized:

public static synchronized boolean allMethodCalls(JoinPoint thisJoinPoint)

This works, but the runtime for each call of doStuff(..) increases from ~190 ms to ~800 ms, i.e. 4 times slower than before:

Doing something with active property
(...)
Doing something with active property
Call counter = 40
Duration = 821 ms
execution(void de.scrum_master.app.PropertyReader.lambda$0())
(...)
execution(boolean de.scrum_master.app.PropertyReader.hasSpecificProperty())
Call counter = 70
Duration = 802 ms

Try for yourself if you like. Now after this long explanation I think you agree that a ThreadLocal is better than a simple boolean even if the latter can be made to work by synchronising the pointcut method. But only boolean without synchronisation would break the aspect, making it thread-unsafe.

Question:

As you know with AspectJ 5 you can write aspects inside *.java files. I.e.: public aspect Aspects {} now can be written as following: @Aspect public class Aspects {}.

Is there any way to write the code below inside Java file? Code:

public aspect AnnotationInheritor { 
    declare @method : void ItemRepository+.getById(..) : @MyAnnotation;
}

P.S. I found @DeclareAnnotation that appears at version 1.5.3, but looks like it haven't been implemented yet.

@DeclareAnnotation("void ItemRepository+.getById(..)")
@MyAnnotation void inEmptyListMethod() {}

Answer:

No, there is not way as of today. Even if there was, you would still need the AspectJ compiler or a load-time weaving agent in order to make it work. Where is the benefit in using clunky annotation syntax, putting everything inside a string? IMO the native syntax is much more clear and elegant. If you want to use AspectJ, learn its syntax. ;-)

Question:

I am trying to use AspectJ in a simple project without using Spring, and while I have seen similar questions and my code seems to be correct, I don't understand why it's not working. I'm using Eclipse Oxygen 4.7.3 (not using AJDT tools), JDK 7, maven 3.5.2, and my code is as follows:

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>com</groupId>
  <artifactId>aspect-tutorial</artifactId>
  <version>0.0.1-SNAPSHOT</version>


<properties>
    <maven.compiler.plugin.version>3.5.1</maven.compiler.plugin.version>
</properties>

<dependencies>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.7</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.8</version>
    </dependency>
</dependencies>


<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.8</version>
            <configuration>
                <complianceLevel>1.7</complianceLevel>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>

        </plugin>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven.compiler.plugin.version}</version>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
        </plugin>

    </plugins>
</build>
</project>

MainApp.java

package com.pkg;

public class MainApp {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        HelloWorld a = new HelloWorld();
        a.printHello();
    }
}

HelloWorld.java

package com.pkg;

public class HelloWorld {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public void printHello() {
        System.out.println("Print Hello...");
   }

}

TestAspect.java

package com.pkg;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;


@Aspect
public class TestAspect {       

    @Before("execution(* com.pkg.HelloWorld.printHello(..))")
    public void testBefore2(){
        System.out.println("Yeeha");
    }


}

Running mvn clean install is successful, but the output only prints the "Print Hello..." part. Should I use a different approach? (Maybe use a .aj file instead, or try load-time-weaving) Any help appreciated.


Answer:

The problem is the configuration of both AspectJ Maven and Maven Compiler. My POMs for AspectJ usually look a bit different than yours (a few more settings), but here is yours with minimal changes in order to make it work:

<?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>com</groupId>
  <artifactId>aspect-tutorial</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <properties>
    <maven.compiler.plugin.version>3.5.1</maven.compiler.plugin.version>
  </properties>

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

  <build>
    <plugins>

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.11</version>
        <configuration>
          <complianceLevel>1.7</complianceLevel>
          <source>1.7</source>
          <target>1.7</target>
        </configuration>
        <executions>
          <execution>
            <!-- IMPORTANT -->
            <phase>process-sources</phase>
            <goals>
              <goal>compile</goal>
              <goal>test-compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${maven.compiler.plugin.version}</version>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
          <!-- IMPORTANT -->
          <useIncrementalCompilation>false</useIncrementalCompilation>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.4.0</version>
        <configuration>
          <mainClass>com.pkg.MainApp</mainClass>
        </configuration>
      </plugin>

    </plugins>
  </build>
</project>

See how I set incremental compilation to false for Maven compiler? This is due to an old bug (still unfixed) which actually inverts the switch, so in order to make incremental compilation work you have to "deactivate" it. Very weird.

You also need to define executions for the process-sources phase for AspectJ Maven.

Besides, I upgraded to AspectJ Maven 1.11 and thus also to AspectJ runtime 1.8.13.

I also added Maven Exec plugin in order to easily prove that it is working now. Just call mvn clean compile exec:java and check the output:

(...)
[INFO] --- aspectj-maven-plugin:1.11:compile (default) @ aspect-tutorial ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[INFO] 
[INFO] --- maven-compiler-plugin:3.5.1:compile (default-compile) @ aspect-tutorial ---
[INFO] Nothing to compile - all classes are up to date
(...)
[INFO] --- exec-maven-plugin:1.4.0:java (default-cli) @ aspect-tutorial ---
Yeeha
Print Hello...
(...)

Otherwise I support what Nándor said: Make sure you use AspectJ plugins for Eclipse or IDEA if you also want to run your aspect-enhanced Java code from an IDE.

Question:

I have an aspect that currently works to capture all public method executions within my package.

I would like to modify that to exclude both setters and getters, so I tried that and these are the variants I tried:

This one works, but does obviously does not do anything for setters or getters.

@Around("execution(public * *(..)) && !within(com.walterjwhite.logging..*)")

This does not compile:

@Around("execution(public * *(..)) && !within(* set*(..))")

This compiles, but doesn't prevent capturing setters/getters:

@Around("execution(public * *(..)) && !execution(* set*(..))")

I also came across this post as a reference, but that didn't work. I get compilation errors when trying to compile the aspect.

How can I exclude getters and setters in aspectJ?


Answer:

The second one does not compile because within() needs a type signature, not a method signature. The answer you are referring to is just plain wrong, I have no idea why it was accepted. I just wrote a new one in order to correct that false information.

Your last try is basically right, but only ignores setters, not getters. Try this:

Driver application:

package de.scrum_master.app;

public class Application {
  private int id;
  private String name;

  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public void doSomething() {
    System.out.println("Doing something");
  }

  public static void main(String[] args) {
    Application application = new Application();
    application.setId(11);
    application.setName("John Doe");
    application.doSomething();
    System.out.println(application.getId() + " - " + application.getName());
  }
}

Aspect:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MyAspect {
  @Around("execution(public * *(..)) && !execution(void set*(*)) && !execution(!void get*())")
  public Object myAdvice(ProceedingJoinPoint thisJoinPoint) throws Throwable {
    System.out.println(thisJoinPoint);
    return thisJoinPoint.proceed();
  }
}

Console log:

execution(void de.scrum_master.app.Application.main(String[]))
execution(void de.scrum_master.app.Application.doSomething())
Doing something
11 - John Doe

Please note that

  • if you have getters for boolean values like isActive() and also want to ignore them, you have to extend the pointcut by && !execution(boolean is*()).
  • those kinds of pointcuts with name patterns are always just heuristics, so beware of method names such as getaway, settleConflict, isolate. They would also be ignored.

Question:

I am new to AOP and currently trying to implement an aspect for controller methods annotated with a custom annotation. I allways get a NullPointerException on repository when myFunction is invoked. It seems that i have two instances of of the controller. One of them is instantiated without autowiring the repository. When i remove @MyAnnotation everything works as expected.

Can you give me any hint on how to force Spring/AspectJ to use my constructor?

My controller looks like:

@RestController
@RequestMapping(value = "/api")
public class MyController {
    private Repository repository;

    public MyController(Repository repository) {
        this.repository = repository;
    }

    @RequestMapping(value = "/{variable1}", method = GET)
    @MyAnnotation
    public final FeatureCollection myFunction(
        final @PathVariable(required = true) long variable1
    ) {
        repository.findById(variable1);
        (...)
    }
}

The aspect:

@Aspect
public class MyAspect {
    @Around("@annotation(MyAnnotation)")
    public Object any(ProceedingJoinPoint pjp) throws Throwable {
        return pjp.proceed();
    }
}

The configuration:

@Configuration
@EnableAspectJAutoProxy
public class WebConfig {
    @Bean
    public MyAspect myAspect() {
        return new MyAspect();
    }
}

Answer:

It comes from the fact that the annotated method is final.

If you can remove the final keyword, it'll work.

If you google something like "spring aop final methods", you'll find more info, but basically, when Spring creates the proxy, it generates a subclass from your original class, to wrap the call to super with your aspect. The problem is that a final method cannot be inherited by the subclass, so that makes it hard for the proxy to work. Therefore, a lot of limitations come from that, and AOP doesn't work that much with final stuff.

This limitation is mentioned in the docs, I don't think you'll get a workaround for it:

11.6 Proxying mechanisms

...

final methods cannot be advised, as they cannot be overridden.

Hoping this will help you!

Question:

I started learing aspectJ and I wondering is it possible to create aspect in file .aj instead of annotation in .java, this is my example:

I have this aspect which modify value of parameter in method

@Around("execution(* *(..)) && @annotation(Te)")
public Object setupParam(ProceedingJoinPoint pjp) throws Throwable {
    Object[] args = pjp.getArgs();
    MethodSignature signature = (MethodSignature) pjp.getSignature();
    Method method = signature.getMethod();
    Te myAnnotation = method.getAnnotation(Te.class);
    if (args != null) 
        args[0] = (int) args[0] * myAnnotation.w();
    return pjp.proceed(args);
}

and I don't know how to create this asspect in .aj file, is it even possible?


Answer:

Yes, that is possible.

public aspect MyAspect {

    public MyAspect() {
      System.out.println("Aspect instance created");
    }

   pointcut myPointcut(ParameterType parameter)
               : ("execution(* *(..)) && @annotation(Te));

    Object around(ParameterType parameter) : myPointcut(parameter) {
       // Business logic here
       // 'thisJoinPointStaticPart' will give you access to join point
       // 'this' will give you access to advice instance itself
       // `return proceed();` will allow you to execute advised join point
    }
}

I would suggest to use Eclipse AspectJ Developer Tool, which provides many useful features, like intellisence autocomplete, javadocs and aspect visualization and etc. This might help you to learn faster.

Question:

I have a bunch of classes inside a Spring 4.2 project. I'd like to have all of them annotated with @Xyz annotation. According to AspectJ documentation it could be done by

declare @type : x.y.z.* : @Xyz;

instruction. But I have no clue where to place it.


Answer:

I did some testing on my side and after some struggling, I looked for the concrete implementation. Sadly, @DeclareAnnotation exists but is not implemented.

We can see it here. https://github.com/eclipse/org.aspectj/blob/V1_8_9/docs/adk15ProgGuideDB/ataspectj.xml#L1017

I thought it would be implemented sinced the annotation appeared in version 1.5.3. My bad.


Original answer (not working, AspectJ v1.8.9).

First you need to enable AspectJ in your configuration. For example, Java configuration :

@Configuration
@EnableAspectJAutoProxy
public class AopConfiguration {}

Then you create a new aspect with the @DeclareAnnotation annotation :

@Aspect
public class XyzAspect {

    @DeclareAnnotation("x.y.z.*")
    @Xyz class XyzClass {}

    @DeclareAnnotation("x.y.z.MyClass.*(..)")
    @Xyz void xyzMethod() {}
}

Question:

I've written a pointcut that will call an around advice on the execution of a certain method.

However, I'd like to understand exactly why the final pattern I used works, but the initial pattern didn't.

The initial pattern that I used (which didn't work) was:

pointcut timeIt() : execution(* *.AuthFilter.filter(..));

The pattern that works is:

 pointcut timeIt() : execution(* *..*.AuthFilter.filter(..));

Trying to Google the difference between *. and *..*. has proved somewhat challenging. If someone could provide either an explanation or a resource that explains the difference I would be very grateful.


Answer:

It is explained by the documentation:

AspectJ Type Patterns

An embedded * in an identifier matches any sequence of characters, but does not match the package (or inner-type) separator ".".

An embedded .. in an identifier matches any sequence of characters that starts and ends with the package (or inner-type) separator ".".

Basically, when used at the package level, .. means any sub-packages.

Your first expression only matches if AuthFilter is in the second level, for example, org.AuthFilter, but it would not match org.security.AuthFilter, in this case you would need *.*.AuthFilter.

Your second expression is matching AuthFilter wherever it is. It does not matter the package and sub package it is in.

@AspectJ cheat sheet

Question:

I have a working project on Spring Roo 2 M3. I realized that i needed a new finder apart from the ones that i created when i was bootstraping the project. I generated the finder in the roo console:

finder add --entity ~.domain.Usuario --name findByUsername

It created the right annotation in the java repository

@RooFinder("findByUsername")

and the method in the repository aspect

public abstract Page<Usuario> UsuarioRepository.findByUsername(String username, Pageable pageable);

but it didn't generate that finder in the service neither the service implementation like the other finders that i previously generated.

I googled it for some days and tried to fix it my self but i made no progress.


note: this already happened to me on other spring roo 2 M3 project some months ago. I had the same problem for like a week and then after many random tampering with the code finally the roo console triggered the changes but i couldn't figured out why it worked.


EDIT: log.roo

// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-06 18:32:01
project setup --topLevelPackage ar.edu.um.ingsoftware --projectName "umbook"
jpa setup --database MYSQL --provider HIBERNATE --hostName 127.0.0.1 --databaseName umbook --userName root
entity jpa --class ~.reference.Persona --abstract
field string --fieldName username --notNull 
field string --fieldName password --notNull
entity jpa --class ~.domain.Usuario  --extends ~.reference.Persona
field string --fieldName email --notNull
field string --fieldName nombre --notNull 
field string --fieldName apellido --notNull
field date --fieldName fechaNacimiento --type java.util.Calendar --past
entity jpa --class ~.domain.Administrador  --extends ~.reference.Persona
entity jpa --class ~.domain.Comentario
field string --fieldName contenido --notNull
field reference --fieldName autor --type ~.domain.Usuario
field date --fieldName timestmp --type java.util.Calendar
repository jpa --all
finder add --name findByEmailEquals --entity ~.domain.Usuario
finder add --name findByNombreLike --entity ~.domain.Usuario
finder add --name findByApellidoLike --entity ~.domain.Usuario
service --all
web mvc setup
web mvc view setup --type THYMELEAF
web mvc controller --all --responseType THYMELEAF
// script --file script_roo
exit
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-06 18:32:26
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-06 18:57:39
web mvc finder --all --responseType THYMELEAF --pathPrefix 'find'
web mvc language --code es --useAsDefault 
web mvc templates setup --type THYMELEAF 
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-06 19:23:08
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-06 19:23:31
focus --class ~.domain.Usuario
field list --fieldName comentarios --type ~.domain.Comentario --mappedBy listaDeComentarios --cardinality ONE_TO_MANY 
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-06 19:41:26
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-06 19:41:37
exit
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-06 19:42:18
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-06 19:42:36
focus --class ~.domain.Comentario 
focus --class ~.domain.Usuario
// [failed] field list --fieldName comentariosHechos --type ~.domain.Comentario --mappedBy autor  --cardinality ONE_TO_MANY 
// [failed] field list --fieldName comentarios --type ~.domain.Comentario
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-06 19:53:59
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-06 19:54:16
focus --class ~.domain.Usuario
field list --fieldName comentarios --type ~.domain.Comentario
focus --class ~.domain.Comentario
focus --class ~.domain.Usuario
field list --fieldName comentarios --type ~.domain.Comentario --cardinality MANY_TO_MANY 
field list --fieldName comentarios --type ~.domain.Comentario
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-06 19:58:35
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-06 19:58:50
// [failed] field list --fieldName comentariosHechos --type ~.domain.Comentario --mappedBy autor
focus --class ~.domain.Usuario
field list --fieldName comentariosHechos --type ~.domain.Comentario --mappedBy autor
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-06 23:36:33
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-16 18:03:39
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-19 04:51:01
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-24 20:40:34
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-24 20:42:02
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-24 20:42:15
help
project scan now
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-25 00:49:54
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-25 00:50:07
project scan status
project scan now
finder add --entity ~.domain.Usuario --name findByUsername
project scan now
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-26 04:59:57
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-26 05:00:09
project scan now
project scan now
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-26 05:12:02
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-26 05:12:13
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-26 05:15:11
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-26 05:16:30
project scan status
project scan status
project scan now
help
metadata status
help
version
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-26 05:36:24
// Spring Roo 2.0.0.M3 [rev 20a0f71] log opened at 2017-02-26 19:59:43
// Spring Roo 2.0.0.M3 [rev 20a0f71] log closed at 2017-02-26 20:59:20

EDIT2: Added UsuarioRepository.java after the push-in

package ar.edu.um.ingsoftware.repository;
import ar.edu.um.ingsoftware.domain.Usuario;
import org.springframework.roo.addon.layers.repository.jpa.annotations.RooJpaRepository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.roo.addon.layers.repository.jpa.annotations.RooFinder;

@Transactional(readOnly = true)
/**
 * = UsuarioRepository
 *
 * TODO Auto-generated class documentation
 *
 */
@RooJpaRepository(entity = Usuario.class, finders = { @RooFinder("findByEmailEquals"), @RooFinder("findByNombreLike"), @RooFinder("findByApellidoLike"), @RooFinder("findByUsername") })
public interface UsuarioRepository extends JpaRepository<Usuario, Long>, UsuarioRepositoryCustom {

    /**
     * TODO Auto-generated method documentation
     * 
     * @param email
     * @param pageable
     * @return Page
     */
    public abstract Page<Usuario> findByEmailEquals(String email, Pageable pageable);


    /**
     * TODO Auto-generated method documentation
     * 
     * @param email
     * @return Long
     */
    public abstract long countByEmailEquals(String email);


    /**
     * TODO Auto-generated method documentation
     * 
     * @param nombre
     * @param pageable
     * @return Page
     */
    public abstract Page<Usuario> findByNombreLike(String nombre, Pageable pageable);


    /**
     * TODO Auto-generated method documentation
     * 
     * @param nombre
     * @return Long
     */
    public abstract long countByNombreLike(String nombre);


    /**
     * TODO Auto-generated method documentation
     * 
     * @param apellido
     * @param pageable
     * @return Page
     */
    public abstract Page<Usuario> findByApellidoLike(String apellido, Pageable pageable);


    /**
     * TODO Auto-generated method documentation
     * 
     * @param apellido
     * @return Long
     */
    public abstract long countByApellidoLike(String apellido);


    /**
     * TODO Auto-generated method documentation
     * 
     * @param username
     * @param pageable
     * @return Page
     */
    public abstract Page<Usuario> findByUsername(String username, Pageable pageable);


    /**
     * TODO Auto-generated method documentation
     * 
     * @param username
     * @return Long
     */
    public abstract long countByUsername(String username);

}

Answer:

After analyze your issue, seems like some problem with the Spring Roo 2.0.0.M3 metadata listeners affects to the service generation when a new finder is included.

This problem has been fixed in Spring Roo 2.0.0.RC1 and it will be published really soon.

Anyway, if you make push-in of the findByUsername method, the service interface and the service implementation must include it.

Let me know if you have any problem with that!

Hope it helps,

Question:

I'd like to incorporate AspectJ in my app to understand how it works. I d like not to use Spring AOP, but "pure" aspectj.

Here's what I have:

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

And:

package tmp;

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

@Aspect
public class LoggingAspect {

    @Pointcut("execution(* *.*(..))")
    void anyMethodCall() {
    }

    @Before("anyMethodCall()")
    public void beforeMethod() {
        System.out.println("Aspect Before Method");
    }
}

When I execute my App, the message is not printed.

The way I understand it, beforeMethod should be called before any method of any class in the entire project.

I'm guessing I' forgetting something but I haven't found a good tutorial yet where it was clear to me how it works.

Where do I go form here?


Answer:

In Eclipse project type must be changed to aspectj project (right mouse on project->AspectJ)

You need in pom.xml

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
    </dependency>
</dependencies>
<build>
    <pluginManagement>
        <plugins>
            <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <configuration>
                <complianceLevel>1.7</complianceLevel>
                <source>1.7</source>
                <target>1.7</target>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
            </plugin>
            <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
            <plugin>
                <groupId>org.eclipse.m2e</groupId>
                <artifactId>lifecycle-mapping</artifactId>
                <version>1.0.0</version>
                <configuration>
                    <lifecycleMappingMetadata>
                        <pluginExecutions>
                            <pluginExecution>
                                <pluginExecutionFilter>
                                    <groupId>
                                        org.codehaus.mojo
                                    </groupId>
                                    <artifactId>
                                        aspectj-maven-plugin
                                    </artifactId>
                                    <versionRange>
                                        [1.7,)
                                    </versionRange>
                                    <goals>
                                        <goal>compile</goal>
                                        <goal>test-compile</goal>
                                    </goals>
                                </pluginExecutionFilter>
                                <action>
                                    <ignore></ignore>
                                </action>
                            </pluginExecution>
                        </pluginExecutions>
                    </lifecycleMappingMetadata>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>

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

Change your pointcut to "!within(tmp.LoggingAspect) && execution(* .(..))" for avoid catch him self.

Question:

I have an external library which is not an spring application. It defines few Aspectj functions/PointCuts but it is not getting called when i am using this library in an spring boot application. When i define the pointcuts in spring boot application itself it is working fine. I guess something is wrong with my configuration like @EnableAspectJAutoProxy not working or something.

Code of service-:

@EnableAspectJAutoProxy
@Service
public class LtRequest {
    RestTemplate restTemplate;

    public LtRequest() {
        restTemplate = new RestTemplate();
        restTemplate.setErrorHandler( new LtResponseErrorHandler());
    }

    public Object request(String url, LtRequestType type, Class clz){
        return null;
    }
    public RestResponseDTO getObject(String url,Class clz){
        RestResponseDTO restResponseDTO =restTemplate.getForObject(url,RestResponseDTO.class);
        //LtUtil.parseRequest(restResponseDTO);
        return restResponseDTO;
    }

    private  void postObject(String url,Object obj){
        RestResponseDTO restResponseDTO =restTemplate.postForObject(url,obj,RestResponseDTO.class);

    }




}

Code of aspectj pointcut

@Aspect
@Component
public class ParseRequestAspect {
    static final Logger logger = LogManager.getLogger(ParseRequestAspect.class);
    @Around("execution(* com.limetray.helper.utils.LtRequest.getObject(..))")
    public Object parseRequestAfterReturn(ProceedingJoinPoint joinPoint) {
        logger.info("calling after return aspect function..");
        try{
            RestResponseDTO response = (RestResponseDTO) joinPoint.proceed();
            LtUtil.parseRequest(response);
            return response.getResult();
        }
        catch (Throwable e){
            throw new LtException("Exception occured while parsing request response..");

        }


    }
    @After("execution(* com.limetray.helper.utils.LtRequest.getObject(..))")
    public void parseRequestAfterReturn(JoinPoint joinPoint) {
        logger.info("calling after return aspect function..new");
        try{
            /*RestResponseDTO response = (RestResponseDTO) joinPoint.proceed();
            LtUtil.parseRequest(response);
            return response.getResult();*/
        }
        catch (Throwable e){
            throw new LtException("Exception occured while parsing request response..");

        }


    }
}

Both of these classes are in my external library but its not working as expected. Please help.


Answer:

If you want to use native AspectJ aspects from within a Spring application and not proxy-based Spring AOP, you need to configure your application to use LTW (load-time weaving) via @EnableLoadTimeWeaving or <context:load-time-weaver/>, respectively. See the Spring manual for more information.

Question:

If I use IDE to run the code, everything works fine.

But when i use ant to compile the code, Aspectj's proxy doesn't work. My ant target

   <property name="ajc.adapter" value="org.aspectj.tools.ant.taskdefs.Ajc11CompilerAdapter"/> 
   <target name="compile" description="compile all files">
    <mkdir dir="WebContent/WEB-INF/classes" />
       <javac
           debug="true"
           srcdir="src"
           destdir="WebContent/WEB-INF/classes"
           classpathref="classpath"
           deprecation="true"
           source="1.6"
           target="1.6"
           optimize="true">
           <include name="**/*.java" />
           <compilerarg compiler="${ajc.adapter}" line="-verbose -Xlint -proceedOnError"/>
           <compilerarg compiler="${ajc.adapter}" value="-classpath"/>
           <!--<compilerarg value="-Xlint:deprecation"/>-->
           <!--<compilerarg value="-Xlint:unchecked"/>-->
       </javac>
    <!-- Copy the properties files. -->
    <copy todir="WebContent/WEB-INF/classes">
        <fileset dir="src">
            <include name="**/*.properties" />
        </fileset>
    </copy>
    <!-- Copy the XML files -->
    <copy todir="WebContent/WEB-INF/classes">
        <fileset dir="src">
            <include name="**/*.xml" />
        </fileset>
    </copy>
</target>

Java code :

    @Around("execution(* *.*(..)) && @annotation(com.xyz.MonitorMethod)")
public Object check(ProceedingJoinPoint  pjp) throws Throwable {
    try {
        return pjp.proceed();
    } finally {
        System.out.println("======================222");
    }
}

Is any issue in this target? THX. I want use Ajc11CompilerAdapter (javac)


Answer:

You are not running ajc at all in your ant target, just standard javac.

Please refer to ajc ant task documentation

EDIT: (listing the rough steps from the page above):

  • add aspectjtools.jar into ant's lib directory
  • modify your javac target using following for guidance guidance:

     <property name="ajc"
         value="org.aspectj.tools.ant.taskdefs.Ajc11CompilerAdapter"/>
    
     <javac srcdir="src" includes="org/aspectj/**/*.java" destdir="dest" >
         <compilerarg compiler="${ajc}" line="-argfile src/args.lst"/>
     <javac/>
    
  • run your build script passing the build.compiler property with value of fully qualified name of the adapter class:Ant -Dbuild.compiler=org.aspectj.tools.ant.taskdefs.Ajc11CompilerAdapter

(I can't tell why you would pass it as command line argument AND define it as property within the script either)

Question:

I'm learning Java and somehow I got into AspectJ. I tried to execute this code from tutorial book:

    pointcut adviceExecutionPointcut( ) : adviceexecution( );

   // Advice declaration
   before( ) : adviceExecutionPointcut( )
      && !within(AdviceExecutionRecipe +)
   {
      System.out.println(
         "------------------- Aspect Advice Logic --------------------");
      System.out.println("In the advice picked by ExecutionRecipe");
      System.out.println(
         "Signature: "
            + thisJoinPoint.getStaticPart( ).getSignature( ));
      System.out.println(
         "Source Line: "
            + thisJoinPoint.getStaticPart( ).getSourceLocation( ));
      System.out.println(
         "------------------------------------------------------------");
   }
}

And it somehow gave me an error like this.

Exception in thread "main" java.lang.StackOverflowError
    at helloWorld.ajc$before$helloWorld$2$5e65e204(helloWorld.aj)
    at helloWorld.ajc$before$helloWorld$2$5e65e204(helloWorld.aj)
    at helloWorld.ajc$before$helloWorld$2$5e65e204(helloWorld.aj)
    at helloWorld.ajc$before$helloWorld$2$5e65e204(helloWorld.aj)
    at helloWorld.ajc$before$helloWorld$2$5e65e204(helloWorld.aj)

For reference this is the example code and the advice code.

public class myClass {

    public void foo(int number, String name){
        System.out.println("Inside foo(int, String)");
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
    myClass myObject = new myClass();
    myObject.foo(1, "ican");

    }


public aspect helloWorld {
    public int a;
    long startTime;


    pointcut callPointcut(int value, String name) :
        call(* myClass.foo(int, String)) && args(value,name);

     before(int value, String name) : callPointcut(value,name)
       {
         startTime = System.nanoTime();
          System.out.println("Start Time in ns :" + startTime);
       }

Any help would be appreciated. Thanks


Answer:

I don't see the type declaration for the aspect containing the adviceexecution pointcut? I suspect you dropped that advice block into your helloWorld aspect. The reason you are getting the recursive stackoverflow is because the advice is applying to itself. The guard !within(AdviceExecutionRecipe +) is meant to stop the advice applying to itself. However, you can't just change that from AdviceExecutionRecipe to helloWorld because then it won't apply to any of your advice. So I would keep that advice block in a separate aspect and call it AdviceExecutionRecipe. With that in place, it works for me:

$ ajc -1.8 *.java -showWeaveInfo

Join point 'adviceexecution(void helloWorld.ajc$before$helloWorld$1$68d3c671(int, java.lang.String))' in Type 'helloWorld' (helloWorld.java:9) advised by before advice from 'AdviceExecutionRecipe' (AdviceExecutionRecipe.java:5)

Join point 'method-call(void myClass.foo(int, java.lang.String))' in Type 'myClass' (myClass.java:10) advised by before advice from 'helloWorld' (helloWorld.java:9)

$ java myClass

------------------- Aspect Advice Logic --------------------
In the advice picked by ExecutionRecipe
Signature: void helloWorld.before(int, String)
Source Line: helloWorld.java:9
------------------------------------------------------------
Start Time in ns :216368803494701
Inside foo(int, String)

Question:

For example I have following methods:

public void method1(@MyAnnotation Object a, Object b..) {
   ...
}

public void method1(Object a, Object b..., @MyAnnotation Object n, ...) {
   ...
}

What is AspectJ pointcut that targets only methods that have parameters annotated with @MyAnnotation?

This annotation can be applied for ANY argument of the method.


Answer:

The following pointcut should match the execution of methods in your question. I also provided a second pointcut which is only a slight modification of the first one, but you might find it useful if you need to match specific types annotated with an annotation.

public aspect AnnotatedMethodParameterMatchingAspect  {

    /**
     * Matches the execution of any method having a parameter annotated with the
     * {@link MyAnnotation} annotation.
     */
    pointcut executionOfMethodWithAnnotatedParameter(): 
        execution(* *(.., @MyAnnotation (*), ..));

    /**
     * Matches the execution of any method having a parameter annotated with the
     * {@link MyAnnotation} annotation where the parameter type is a {@link MyType}
     * (or a subtype).
     */
    pointcut executionOfMethodWithAnnotatedTypeRestrictedParameter(): 
        execution(* *(.., @MyAnnotation (MyType+), ..));

}

Question:

I am writing my first AOP. I have pasted the code below which isnt getting intercepted on the method call. I am not sure what could be the reason.

On the console it only prints:

addCustomerAround() is running, args : dummy

and none of the AOP advice code is printed.

Can somebody help?

Interface:

package com.test.model;

import org.springframework.beans.factory.annotation.Autowired;

public interface AopInterface {


    @Autowired
    void addCustomerAround(String name);
}

Class:

package com.test.model;

import com.test.model.AopInterface;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;

@Component
public class AopClass implements AopInterface {

    public void addCustomerAround(String name){
        System.out.println("addCustomerAround() is running, args : " + name);
    }
}

AOP:

package com.test.model;

import java.util.Arrays;

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 TestAdvice{


     @Around("execution(* com.test.model.AopInterface.addCustomerAround(..))")
       public void testAdvice(ProceedingJoinPoint joinPoint) throws Throwable {

        System.out.println("testAdvice() is running!");
        System.out.println("hijacked method : " + joinPoint.getSignature().getName());
        System.out.println("hijacked arguments : " + Arrays.toString(joinPoint.getArgs()));

        System.out.println("Around before is running!");
        joinPoint.proceed(); 
        System.out.println("Around after is running!");

        System.out.println("******");

       }
}

appcontext.xml:

<!-- Aspect -->
    <aop:aspectj-autoproxy />
    <bean id="AopClass" class="com.test.model.AopClass" />
    <bean id="TestAdvice" class="com.test.model.TestAdvice" />

POM:

<!-- AOP -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

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

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.11</version>
        </dependency>

Method call:

aoptest.addCustomerAround("dummy");

Answer:

I don't see any error here. I've just tried your code and it works well. My test class:

public class App {
    public static void main(String[] args) throws Exception {

        ApplicationContext appContext = new ClassPathXmlApplicationContext("appcontext.xml");

        //-------------------------
        AopClass aopClass = (AopClass) appContext.getBean("AopClass");
        aopClass.addCustomerAround("dummy");
    }
}

Result

Can you retry to build your maven project?! And try again?!

Question:

I have a very weird situation, that has happened in several systems already. I am using Spring Boot and AspectJ CTW to @Autowired dependencies in some entities (instanciated outside the container).

The class that receives dependencies (an abstract entity) some times receive the dependency without applying the profile (configured by @ActiveProfile in my test class). It is not deterministic, since by changing how tests are executed different outputs can happen. To illustrate the situation with code:

The entity

@Configurable
public class AbstractMongoDocument<T> implements Persistable<T> {
    @Transient
    private transient MongoTemplate mongoTemplate;
//entity stuff
}

One of the failing tests

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = LOVApplication.class)
@ActiveProfiles("local-test")
public class MyCrazyIntegrationTest {

    @Test
    public void filterByFieldsFullMatchShouldReturnResult() throws Exception {
        //Given
        Location l1 = new Location("name","code",new GeoJsonPoint(11,10));
        l1.save(); //Hence the need of autowiring there.

        //When: whatever
        //Then: Some assertions
    }
}

There are some facts that I find very disturbing here:

  1. The dependency is always injected, but some times it apparently comes from an AppCtx with the default profile.
  2. If it fails for 1 test in 1 class, it behaves the same for all the tests in that particular class.
  3. It may or may not happen depending on how you execute that class (At the moment it fails only if I run all the tests, but succeed if I run that class in isolation, it also behaves differently in maven).
  4. If I debug it, I can see that the dependency injected didn't get the proper profile. (I discovered that by injecting ApplicationContext and surprisingly discovering that it was a different object than the one I received in my tests).
  5. What worries me the most, is that now I am not sure if this situation could also happen for non-test environments with for example a Production profile, which would imply a catastrophe.

I have tried to look for open bugs in Jira and I found nothing, so I don't discard I am misconfiguring something. Any help or ideas would be very much appreciated.


Answer:

The behavior you are experiencing typically should not happen in a production deployment; however, it is a known issue with integration test suites that load multiple ApplicationContexts utilizing @Configurable and AspectJ load-time weaving.

For details, see the following issues in Spring's issue tracker:

Question:

New to aspect oriented development.

Two part question coming up.

  1. Do you have any good sites that contain tutorial and code that runs? So far i have seen many tutorials but with fragmented code and there is nothing that i can piece together so that it works locally.

  2. Im trying to create a framework with an aspect and a aspectj class that should intercept all the method calls that are annotated with the aspect. It works great in my local project but when i try to use the aspect in another project it does not seem to be working.

Code example: Aspect interceptor

@Aspect
public class InterceptCallAspect {
    @Around("execution(* *(@InterceptCall (*)));")
    public void record(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //Before
        System.out.println("Before");
        proceedingJoinPoint.proceed();
        System.out.println("After");
        //After
    }
}

The Aspect

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface InterceptAspectAnnotation {
}

So when i annotate my testcase in my project i get the sysout in the right places. But when i create my jar and bundle it in another project it don't do anything.

My pom file:

<?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>InterceptCall</artifactId>
<groupId>testing</groupId>
<packaging>jar</packaging>
<version>0.0.2-SNAPSHOT</version>    
<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.7</version>
            <configuration>
                <complianceLevel>1.8</complianceLevel>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>


Answer:

I can only address your second question, so I will leave the first for others.

If you supply the aspect via an external library (like your built jar), you need to tell the aspectj-maven-plugin where to find the aspects to use for weaving. The configuration-tag needs to contain a tag called aspectLibraries with aspectLibrary-tags for each lib to use:

        <aspectLibraries>
           <aspectLibrary>
              <groupId>com.your.example.util</groupId>
              <artifactId>tracing-aspect</artifactId>
           </aspectLibrary>
        </aspectLibraries>

Question:

I would like Aspectj to bind my method arguments using args.

Something like this:

    @Before("@annotation(authorized) && args(java.util.String)")
    public void authorize(JoinPoint joinPoint, Authorized authorized, String str)

However, I can not count on the String argument being present. I want the advice to be applied to all methods using that annotation, not only the methods with a String argument.

If the advised method does not have a String argument, I'd like to have str filled with a null value. Is this possible? Or is the only option to use joinPoint.getArgs()?


Answer:

I have an answer to the question you asked in the comment to Andy's answer:

Would it be possible to advice methods with unknown amount of arguments, but not ending with an argument of a specific type?

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Authorized {}
package de.scrum_master.app;

public class Application {
    @Authorized static void bla(String string, int i, int j) {}
    @Authorized static void baz(String string, int i, Integer integer) {}
    @Authorized static void zot(String string) {}
    @Authorized static void bar(Integer integer) {}
    @Authorized static void foo() {}

    public static void main(String[] args) {
        foo();
        bar(new Integer(11));
        zot("xxx");
        baz("yyy", 123, new Integer(22));
        bla("zzz", 123, 456);
    }
}
package de.scrum_master.aspect;

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

import de.scrum_master.app.Authorized;

@Aspect
public class MyAspect {
    @Before("@annotation(authorized) && execution(* *(..)) && !execution(* *(.., Integer))")
    public void authorize(JoinPoint joinPoint, Authorized authorized) {
        System.out.println(joinPoint);
    }
}

Console output:

execution(void de.scrum_master.app.Application.foo())
execution(void de.scrum_master.app.Application.zot(String))
execution(void de.scrum_master.app.Application.bla(String, int, int))

As you can see, the two methods baz and bar not ending with a certain type - Integer in this example - are excluded from matching.

Question:

I am using Spring 4 AOP and the aspect that i create is never being called and i cannot figure it out why is that. Look, i have this client class:

package com.example.aspects;

public class Client {


    public void talk(){

    }
}

And my aspect: package com.example.aspects;

import org.aspectj.lang.JoinPoint;
@Aspect
public class AspectTest {

    @Before("execution(* com.example.aspects.Client.talk(..))") 
    public void doBefore(JoinPoint joinPoint) {
        System.out.println("***AspectJ*** DoBefore() is running!! intercepted : " + joinPoint.getSignature().getName());
    }

}

My configuration file:

package com.example.aspects;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class Config {

    @Bean
    public Client client(){
        return new Client();
    }

}

And finally, de app

public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext(
                Config.class);
        Client client = (Client) appContext.getBean("client");
        client.talk();
    }
}

By this way, i never get "intercepted" by AspectTest doBefore() method. have you any idea about what is going on ? Regards


Answer:

You never registered your @Aspect. Add a corresponding bean

@Bean
public AspectTest aspect() {
    return new AspectTest();
}

You can also make your type a @Component and add an appropriate @ComponentScan in your @Configuration class.

Question:

I have a pointcut which listens to access to an field in DBRow and all subclasses

before(DBRow targ) throws DBException: get(@InDB * DBRow+.*) && target(targ) {
    targ.load();
}

I now need to determine the value of the accesed field, that is specified by the get pointcut. Is this possible in AspectJ?


Answer:

For set() pointcuts you can bind the value via args(), but not for get() pointcuts. So in order to get the value without any hacky reflection tricks, just use an around() advice instead of before(). This way you can get the field value as a return value of proceed():

Object around(DBRow dbRow) : get(@InDB * DBRow+.*) && target(dbRow) {
    Object value = proceed(dbRow);
    System.out.println(thisJoinPoint);
    System.out.println("  " + dbRow + " -> " + value);
    dbRow.load();
    return value;
}

Question:

I have a class which defines row access for a database.

public abstract class DBRow {
    int index;

    DBConnection connection;

    public DBRow(DBConnection con, int id) {
        connection = con;
        index = id;
    }

    public DBRow(DBConnection con) {
        this(con, -1);
    }

    public abstract String getTableName();

    private static String getFieldName(Field field) {
        ...
    }

    public void save() {
        ... (Reads all fields that are annotated with @InDB and saves them
    }

    public void load() {
        ... (Will load a row from the database or create a new one if index == -1)
    }
}

A specific row in the database extends this DBRow class. For example:

public class Test extends DBRow {
    @InDB
    public String vct;

    @InDB
    public int intt;

    public Test(DBConnection con, int id) {
        super(con, id);     

        vct = "test";
        intt = 123;
    }

    @Override
    public String getTableName() {
        return "test";
    }
}

After the constructor was called "load" should be called, so the row gets loaded from the database or will be created and saved properly.

public aspect DBRowLoadSave {
    pointcut load() : execution(DBRow.new(*, *));

    after() : load() {
        ((DBRow)thisJoinPoint.getThis()).load();
    }
}

My problem is, that at this point the fields will not be initialized, because the pointcut listens to the constructor call in the mother class of Test, not in Test itself. Is there a way I can listen to all constructors of child classes, or is there another way I can execute the load method after the complete initilization of the class?


Answer:

execution(DBRow+.new(..)) matches all subclass constructors, but includes the base class. So you need to exclude it via !execution(DBRow.new(..)).

Furthermore you can bind the created object directly to a variable via this(), avoiding the getThis() call and the cast within the advice.

public aspect DBRowLoadSave {
    pointcut load(DBRow dbRow) :
        execution(DBRow+.new(..)) &&
        !execution(DBRow.new(..)) &&
        this(dbRow);

    after(DBRow dbRow) : load(dbRow) {
        System.out.println(thisJoinPoint);
        dbRow.load();
    }
}

Question:

I'm trying to log a Sting before every single method is run.

Stack: AspectJ, GWT, Java 7, Eclipse Luna's built in Jetty web server

What doesn't work My advice is not capturing the overridden onModuleLoad() method in my EntryPoint class or any methods it calls.

What does work It does capture methods executed after submitting the page to the server.

pointcut everything() : execution(* *.*(..));

before() : everything()
{
    System.out.println("Calling a method " + thisJoinPoint.getSignature());
}

Answer:

The onModuleLoad method is compiled by the GWT compiler into JavaScript - it is not run on the server at all, but in the client's browser. AspectJ cannot work on GWT code (since it cannot work on JavaScript), so this is not going to work.

Question:

i want to log all method call i make in my code except the ones within the logger, using AspectJ.

@Aspect
public class Logger
{
    // Point Cuts
    //-----------
    @Pointcut("execution(* org.myDomain.*..*.*(..))")
    public void selectAll(){}

    @Pointcut("within(Logger) && call(* *(..))")
    public void codeWithinAspect(){}

    // Advices
    //-----------
    @Before("selectAll()")
    public void adviceThatWorksFine(JoinPoint joinPoint)
    {
        System.out.print(joinPoint.getSignature().toString());
        //Utils.printToConsole(joinPoint.getSignature().toString());    
    }

    @Before("selectAll() && !codeWithinAspect")
    public void adviceWithInfiniteLoop(JoinPoint joinPoint)
    {
        //System.out.print(joinPoint.getSignature().toString());
        Utils.printToConsole(joinPoint.getSignature().toString());  
    }
}

the first advice in the class works fine (it writes every method call to the console), the second advice causes an infinite loop when calling org.myDomain.utils.Utils.printToConsole() method, which is advised by the calling advice.

I have found it is a common problem as described in the link http://www.eclipse.org/aspectj/doc/released/faq.php#q:infiniterecursion but i could not understand how to write the pointcut so an infinite loop would not be created.

plaes help


Answer:

There are several problems in your code:

  • !codeWithinAspect needs parentheses: !codeWithinAspect()
  • adviceWithInfiniteLoop() combines execution() and call() pointcuts in this way: execution(foo) && !call(bar). Because a call joinpoint can never be an execution joinpoint the second part of the condition is always true and has no effect. Thus, it does not avoid the infinite loop.
  • You do not just want to exclude joinpoints within aspect Logger but also those within the control flow (cflow()) of that aspect's methods, i.e. stuff directly or indirectly called by them.

The solution is as follows:

Utility class for log output:

package org.myDomain.app;

public class Utils {
    public static void printToConsole(Object object) {
        System.out.println(object);
    }
}

Driver application:

package org.myDomain.app;

public class Application {
    public  static void sayHelloTo(String counterpart) {
        Utils.printToConsole("Hello " + counterpart + "!");
    }

    public static void main(String[] args) {
        sayHelloTo("world");
    }
}

Logger aspect:

package org.myDomain.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.myDomain.app.Utils;

@Aspect
public class Logger {
    @Pointcut("execution(* org.myDomain..*(..))")
    public void selectAll() {}

    @Pointcut("cflow(within(Logger))")
    public void codeWithinAspect() {}

    @Before("selectAll() && !codeWithinAspect()")
    public void advice(JoinPoint joinPoint) {
        Utils.printToConsole(joinPoint);
    }
}

Console output:

execution(void org.myDomain.app.Application.main(String[]))
execution(void org.myDomain.app.Application.sayHelloTo(String))
execution(void org.myDomain.app.Utils.printToConsole(Object))
Hello world!

Enjoy!

Update: If you want to exclude all advice execution control flows you can also use this pointcut:

@Pointcut("cflow(adviceexecution())")
public void codeWithinAspect() {}

Question:

I have a java file as follows

package sample;
    public class Profile

    {


    public static String myName(String name)
    {
        myhobby("Football");
        return name;
    }
        public static String myhobby(String hobby)
    {


        return hobby;
    }

    }

I build this file and added the jar file into the below code...

import sample.Profile;

  public class Hello

    {

        public static String sayHello(String name)
        {

            String enter=Test.myName("Ganguly");
            return name;
        }

        public static void main(String[] args)
        {
        String next =   sayHello("Company");

        }
    }

And I wrote aspect as follows...

pointcut printMessage(String name) : call(public static String myhobby(..)) && args (name));
     before(String name) : printMessage(name) {
            System.out.println("value is: "+ name);

     }

But when I run the program...it doesn't printed the parameter value of the function hobby... can any one correct me if I am wrong... Thanks in advance...


Answer:

By default, AspectJ IDE only weave current project with aspects of same project, we need add In-Path or Aspect-Path for the project for other scenarios.

From Properties dialog of the second project (your testing project) > 'AspectJ Build' page > InPath , add your jar to the list (the jar is added to Java Build Path library automatically at same time).

Question:

Consider following class with a static method:

public class Vector2D {      
    /* ... */
    public static Vector2D sum(Vector2D first, Vector2D second) {
        return new Vector2D(first.x + second.x, first.y + second.y);
    }
}

This method can be also added as an inter-type declaration in AspectJ:

public aspect Vector2DMath {
    public static Vector2D Vector2D.sum(Vector2D first, Vector2D second) {
        return new Vector2D(first.x + second.x, first.y + second.y);
    }
}

Which approach is more correct in terms of aspect-oriented programming?

Personally, I think that first approach is better (less code), but if so, then when inter-type declarations of static method can be useful?


Answer:

It does not make sense to compare apples and pears. There is no "better" or "worse" here, only situative decisions:

  • Whenever you have access to the source code of the class and the method you want to add implements a core concern, use OOP (edit: fix typo, earlier I had written "AOP").
  • If you do not have access to the source code and inheritance is not a good or even viable solution for implementing a core concern, use AOP as a workaround.
  • If you want to implement a cross-cutting concern across many classes or even throughout the whole system, always use AOP not matter whether you have source code access or not because that is where AOP helps you to write better and cleaner, more modular and more maintainable code.

Having said that and looking at your example, it seems that Vector2D.sum is pretty much addressing a core concern, so if you do not necessarily need AOP to work around the "no source code" problem, use OOP and just edit the class. In other cases the decision might be different. ITD for (non-)static methods is a useful AOP tool.

Edit: I forgot to mention that static methods are usually "bad" because it is hard to mock-test them. Not always, but often they are a bit old-school C-style. In this concrete example, why create a static method to add up two instances of the same class? Why not a regular sum method taking one argument?

Question:

In spring, it express the arg-names like this :

@Before(
value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)",
argNames="bean,auditable")
public void audit(JoinPoint jp, Object bean, Auditable auditable) {
    AuditCode code = auditable.value();
// ... use code, bean, and jp
}

In the doc , it says you may leave out the name of the parameter from the value of the "argNames" attribute. How can spring get argNames("bean,auditable") from anyPublicMethod?

Did java provide some api to get the parameter names?

I think it use the aspectJ to parse the expression, did aspectJ provide the feature?


Answer:

In Java 8 we can use reflection to get parameter name, see http://docs.oracle.com/javase/tutorial/reflect/member/methodparameterreflection.html. Though argument names will be present if the classes have been compiled with -g:vars.

In earlier versions we need to use some tool, like Javassist:

public static void main(String[] args) throws Exception {
    ClassPool pool = ClassPool.getDefault();
    CtClass c = pool.get("test.Test");
    CtMethod m = c.getDeclaredMethod("main");
    MethodInfo methodInfo = m.getMethodInfo();
    LocalVariableAttribute t = (LocalVariableAttribute) methodInfo.getCodeAttribute().getAttribute(javassist.bytecode.LocalVariableAttribute.tag);
    int i = t.nameIndex(0); 
    String v = methodInfo.getConstPool().getUtf8Info(i);
    System.out.println(v); 
}

prints

args

Question:

I have java classes like this :

@Data
public class Lead {
    private A a;
    ...
}

@Data
public class A {
    private B b;
    private String c;
    private List<Integer> d;
}

@Data 
public class B {
    private String e;
    private String f;
}

I have a mapper method with annotation like this :

@FieldPermissionAnnotation("a")
public A fetchA(//Some DB Entities) {
    A a = new A();
    ...
    a.setB(fetchB());
    ...
    a.setC(fetchC());
    ...
    a.setD(fetchD());
}

My FieldPermissionAspect fetches the permission-field mapping from db for a user and sets field to null if user does not have permission for given field.

I get a list of string field hierarchy like this :

["a-b-e", "a-b-f", "a-c", "a-d"]

I want to set b, c, d to null using @Around around their respective setters inside the fetchA() method. Is it feasible using AspectJ and spring? How do I access the setters for b, c, d inside the fetchA() method?


Answer:

I want to set b, c, d to null using @Around around their respective setters inside the fetchA() method. Is it feasible using AspectJ and spring? How do I access the setters for b, c, d inside the fetchA() method?

As I said in my comment, your question is unclear and I have to guess what you want to do because there is no aspect code. My assumption is that you want to intercept setter methods if (and only if) they are being called from inside a certain other method. I.e. you need a control-flow-dependent pointcut like cflow() or cflowbelow(). According to the Spring manual these pointcuts are not supported by Spring AOP, but you can configure Spring to use full AspectJ with LTW (load-time weaving) instead.

For more details I suggest you show me yours (MCVE, ideally on GitHub with Maven build), then I show you mine (concrete solution).

Question:

I am trying to avoid dao call from controller class . If the call is done from service package then dao call should be succesfull else I will throw an exception . I dont want to write this logic in each method of dao class so planned to use aspectj to intercept the dao call . How can I prevent dao from controller and allow it from service class only . Shall I use any other api/approach . Any suggetion

package com;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DaoAspect {

    @Before(value = "execution(* com.dao.*.*(..))")
    public void beforeAdvice( JoinPoint joinPoint) {
        // here I want to know the caller package/class
        // if its com.service allow ,if com.controller reject

    }
}

Answer:

Disclaimer: I am not a Spring user. Maybe there is an easier on-board means to achieve this via interceptors, Spring Security or what have you. But you asked for an AOP solution.

We first have to differentiate between

  • AspectJ (fast, efficient, no proxies, more powerful) and
  • Spring AOP (proxy-based, delegation pattern, "AOP light", only method interception).
Compile-time checks on calling code with @DeclareError

When using AspectJ and just recompiling your legacy library with the AspectJ compiler (drop-in replacement for Java compiler with AOP enhancements), you can use @DeclareError in order to make compilation fail if a call from the wrong class or package pattern(s) is found. This way you would not need any expensive runtime checks, reflection or other tricks. For your Maven build you can use AspectJ Maven plugin. See my answers here for further information about @DeclareError:

  • https://stackoverflow.com/a/41700647/1082681
  • https://stackoverflow.com/a/27312472/1082681
  • https://stackoverflow.com/a/57831250/1082681
  • https://stackoverflow.com/a/50126576/1082681

This is what I recommend: Detect the invalid calls at build time, fix the code in order to make it compile and be sorrow-free during runtime.

Run-time checks using AspectJ load-time weaving (LTW) with call() pointcut

If however you either don't want to use the AspectJ compiler (even though you tagged the question aspectj and not spring-aop) or have no compile-time influence on the calling code, you can still use AspectJ load-time weaving (LTW) from Spring. Spring AOP is definitely not enough if you want to avoid creating Exceptions for the sole purpose of analysing their callstacks in order to find the caller. Instead, in full AspectJ there is a pointcut named call() which is unavailable in Spring AOP. You can weave into the calling code via LTW and then use EnclosingStaticPart in order to find the caller. The only caveat is that in Spring you might use proxies instead of direct calls, which might mess up the caller by indirection, but you can give it a try.

Here is an MCVE in plain Java + AspectJ (no Spring involved):

DAO, service, controller:

package com.dao.ddd;

public class MyDao {
  public void doSomething() {
    System.out.println("Doing something in DAO");
  }
}
package com.service.sss;

import com.dao.ddd.MyDao;

public class MyService {
  public void doSomething() {
    System.out.println("Doing something in service");
    new MyDao().doSomething();
  }
}
package com.controller.ccc;

import com.dao.ddd.MyDao;

public class MyController {
  public void doSomething() {
    System.out.println("Doing something in controller");
    new MyDao().doSomething();
  }
}
package de.scrum_master.app;

import com.controller.ccc.MyController;
import com.service.sss.MyService;

public class Application {
  public static void main(String[] args) {
    // Allowed
    new MyService().doSomething();
    // Forbidden
    new MyController().doSomething();
  }
}

Driver application:

package de.scrum_master.app;

import com.controller.ccc.MyController;
import com.service.sss.MyService;

public class Application {
  public static void main(String[] args) {
    // Allowed
    new MyService().doSomething();
    // Forbidden
    new MyController().doSomething();
  }
}

Console log without aspect:

Doing something in service
Doing something in DAO
Doing something in controller
Doing something in DAO

Actually the list line should not be printed because a call from the controller to the DAO is forbidden.

Aspect:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.JoinPoint.EnclosingStaticPart;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class ContractEnforcerAspect {
  @Before("call(* com.dao..*(..))")
  public void beforeAdvice(JoinPoint joinPoint, EnclosingStaticPart enclosingStaticPart) {
    System.out.println("  Callee = " + joinPoint.getSignature());
    System.out.println("  Caller = " + enclosingStaticPart.getSignature());
    if (enclosingStaticPart.getSignature().getDeclaringType().getPackageName().startsWith("com.controller"))
      throw new RuntimeException("DAO must not be called from controller");
  }
}

Console log with aspect:

Doing something in service
  Callee = void com.dao.ddd.MyDao.doSomething()
  Caller = void com.service.sss.MyService.doSomething()
Doing something in DAO
Doing something in controller
  Callee = void com.dao.ddd.MyDao.doSomething()
  Caller = void com.controller.ccc.MyController.doSomething()
Exception in thread "main" java.lang.RuntimeException: DAO must not be called from controller
    at de.scrum_master.aspect.ContractEnforcerAspect.beforeAdvice(ContractEnforcerAspect.aj:17)
    at com.controller.ccc.MyController.doSomething(MyController.java:8)
    at de.scrum_master.app.Application.main(Application.java:11)

Question:

I am defining a JobProcess with a method Object process( JobContext jobContext ); with an impl called JobProcessImpl. Whenever this JobProcessImpl.process method is executed, I want to spy with more than one subclass. I want all this subclasses to be executed.

The spy class is defined as base class Task to look for JobProcessImpl.process invocation.

In the output, I always see that only log from AnnotationTask and not from ReviewTask.

Please let me know, if it is possible and what is the issue.

I tried for 2 days on solving this by following various posts.

package com.spring.aspect.dynamicflow.activity;

import com.spring.aspect.dynamicflow.entity.JobContext;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@Aspect
public abstract class Task {

    private static final Logger log = LoggerFactory.getLogger( Task.class );

    @Around ( "execution(public java.lang.Object com.spring.aspect.dynamicflow.process.JobProcessImpl.process(..)) " + "&& args(context)" )
    public Object task( JobContext context ) {
        log.info( "This is the base task and needs to overridden by the derived task for the job id: {} ", context.getJobId() );

        return  context;
    }
}

Base Classes: AnnotationTask

package com.spring.aspect.dynamicflow.activity;

import com.spring.aspect.dynamicflow.entity.JobContext;
import com.spring.aspect.dynamicflow.entity.TaskStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class AnnotationTask extends Task {

    private static final Logger log = LoggerFactory.getLogger( AnnotationTask.class );

    @Override
    public Object task( JobContext context ) {
        log.info( "AnnotationTask's task" );

        /*
         * do some validation if annotation is completed or not
         */

        log.info( "Setting that the annotation is done." );
        context.setAnnotationTaskStatus( TaskStatus.COMPLETED );
        return "AnnotationTask Completed";
    }

ReviewTask

package com.spring.aspect.dynamicflow.activity;

import com.spring.aspect.dynamicflow.entity.JobContext;
import com.spring.aspect.dynamicflow.entity.TaskStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class ReviewTask extends Task {

    private static final Logger log = LoggerFactory.getLogger( ReviewTask.class );

    @Override
    public Object task( JobContext context ) {
        log.info( "ReviewTask's task" );

        /*
         * do some validation if annotation is completed or not
         */
        log.info( "not completing the review task due to some reason" );
        context.setReviewTaskStatus( TaskStatus.IN_PROGRESS );
        return "ReviewTask Not Completed";
    }
}

I want these task execution by spying on them with TaskAspects.

package com.spring.aspect.dynamicflow.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class TaskAspects {

    private static final Logger log = LoggerFactory.getLogger( TaskAspects.class );

    @Around( "within(com.spring.aspect.dynamicflow.activity.Task+) ")
    public Object handleTask( ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        log.info( "Handling the task aspects." );
        log.info( "" + proceedingJoinPoint.getThis() );

        return proceedingJoinPoint.proceed();
    }

}

I have an enum classes as well (giving for the code completion)

package com.spring.aspect.dynamicflow.entity;

public enum TaskStatus {
    IN_PROGRESS, COMPLETED
}

JobProcess

package com.spring.aspect.dynamicflow.process;

import com.spring.aspect.dynamicflow.entity.JobContext;

public interface JobProcess {

    Object process( JobContext jobContext );
}

JobProcessImpl

package com.spring.aspect.dynamicflow.process;

import com.spring.aspect.dynamicflow.entity.JobContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class JobProcessImpl implements JobProcess {

    Logger logger = LoggerFactory.getLogger( JobProcessImpl.class );
    @Override
    public Object process( JobContext jobContext ) {
        logger.info( "Shouldn't get printed Processing the job with jobid {}", jobContext.getJobId() );
        return null;
    }
}


Answer:

As soon as I posted this, I tried to change the ReviewTask and AnnotationTask with

@Override
    public Object task( ProceedingJoinPoint proceedingJoinPoint, JobContext context ) throws Throwable {
        log.info( "ReviewTask's task" );

        /*
         * do some validation if annotation is completed or not
         */
        log.info( "not completing the review task due to some reason" );
        context.setReviewTaskStatus( TaskStatus.IN_PROGRESS );
        return proceedingJoinPoint.proceed();
    }

and that solved my issue.

Question:

I want to intercept all java.sql.DataSource.getConnection methods with aspectj, I used this pointcut:

"execution(public java.sql.Connection javax.sql.DataSource+.getConnection(..))"

it works fine. but i encounter some classes ,for example org.apache.tomcat.jdbc.pool.DataSource that are implemented in a class hierarchy that this pointcut doesn't work, where the DataSource methods are in a class in the hierarchy that does not implement DataSource,only the top most class implements DataSource:

class BaseDataSource {

    public Connection getConnection() throws SQLException {
        return null;
    }


    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

   implements all DataSource Methods...
}

class MyDataSource extends BaseDataSource implements java.sql.DataSource{
           //does not implement DataSource methods
}

BaseDataSource does not implement DataSource but has all the DataSource methods implementation.

the only pointcut i found that works is this:

execution(public java.sql.Connection *.getConnection(..)) && target(javax.sql.DataSource)

my question if there is a better way and if this pointcut might be worst with performance?


Answer:

I replicated your situation in an MCVE as follows:

Base class implementing DataSource methods, but not the interface:

package de.scrum_master.app;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

public class BaseClass {
  public PrintWriter getLogWriter() throws SQLException { return null; }
  public void setLogWriter(PrintWriter out) throws SQLException {}
  public void setLoginTimeout(int seconds) throws SQLException {}
  public int getLoginTimeout() throws SQLException { return 0; }
  public Logger getParentLogger() throws SQLFeatureNotSupportedException { return null; }
  public <T> T unwrap(Class<T> iface) throws SQLException { return null; }
  public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; }
  public Connection getConnection() throws SQLException { return null; }
  public Connection getConnection(String username, String password) throws SQLException { return null; }
}

Subclass implementing interface DataSource, inheriting methods from base class:

package de.scrum_master.app;

import javax.sql.DataSource;

public class SubClass extends BaseClass implements DataSource {}

Driver application:

package de.scrum_master.app;

import java.sql.SQLException;

public class Application {
  public static void main(String[] args) throws SQLException {
    System.out.println("Aspect should not kick in");
    new BaseClass().getConnection();
    new BaseClass().getConnection("user", "pw");

    System.out.println("Aspect should kick in");
    new SubClass().getConnection();
    new SubClass().getConnection("user", "pw");
  }
}

Aspect:

This aspect uses the pointcut you are currently using.

package de.scrum_master.aspect;

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

@Aspect
public class DataSourceConnectionAspect {
  @Before("execution(public java.sql.Connection *.getConnection(..)) && target(javax.sql.DataSource)")
  public void myAdvice(JoinPoint thisJoinPoint) {
    System.out.println(thisJoinPoint);
  }
}

Console log:

Aspect should not kick in
Aspect should kick in
execution(Connection de.scrum_master.app.BaseClass.getConnection())
execution(Connection de.scrum_master.app.BaseClass.getConnection(String, String))

No surprises here, everything works as expected. In my opinion this is an efficient way to do it. Of course the aspect code will be woven into each method matching public java.sql.Connection *.getConnection(..)) and there will be a runtime check if target(javax.sql.DataSource) really applies, see also the javap output:

Compiled from "BaseClass.java"
public class de.scrum_master.app.BaseClass {
  (...)

  public java.sql.Connection getConnection() throws java.sql.SQLException;
    Code:
       0: aload_0
       1: instanceof    #76                 // class javax/sql/DataSource
       4: ifeq          21
       7: invokestatic  #70                 // Method de/scrum_master/aspect/DataSourceConnectionAspect.aspectOf:()Lde/scrum_master/aspect/DataSourceConnectionAspect;
      10: getstatic     #58                 // Field ajc$tjp_0:Lorg/aspectj/lang/JoinPoint$StaticPart;
      13: aload_0
      14: aload_0
      15: invokestatic  #64                 // Method org/aspectj/runtime/reflect/Factory.makeJP:(Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint;
      18: invokevirtual #74                 // Method de/scrum_master/aspect/DataSourceConnectionAspect.myAdvice:(Lorg/aspectj/lang/JoinPoint;)V
      21: aconst_null
      22: areturn

  public java.sql.Connection getConnection(java.lang.String, java.lang.String) throws java.sql.SQLException;
    Code:
       0: aload_1
       1: astore        4
       3: aload_2
       4: astore        5
       6: aload_0
       7: instanceof    #76                 // class javax/sql/DataSource
      10: ifeq          31
      13: invokestatic  #70                 // Method de/scrum_master/aspect/DataSourceConnectionAspect.aspectOf:()Lde/scrum_master/aspect/DataSourceConnectionAspect;
      16: getstatic     #79                 // Field ajc$tjp_1:Lorg/aspectj/lang/JoinPoint$StaticPart;
      19: aload_0
      20: aload_0
      21: aload         4
      23: aload         5
      25: invokestatic  #82                 // Method org/aspectj/runtime/reflect/Factory.makeJP:(Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint;
      28: invokevirtual #74                 // Method de/scrum_master/aspect/DataSourceConnectionAspect.myAdvice:(Lorg/aspectj/lang/JoinPoint;)V
      31: aconst_null
      32: areturn

  (...)
}

I.e. the runtime check also occurs for classes happening to implement these very special method pattern if the current instance is not a DataSource. But that should be rare.

There is one alternative involving ITD (inter-type declaration): You can make the base class directly implement the interface and then return to using your more efficient original pointcut. In annotation-based syntax this would like this:

package de.scrum_master.aspect;

import javax.sql.DataSource;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.DeclareParents;

@Aspect
public class DataSourceConnectionAspect {
  @DeclareParents("de.scrum_master.app.BaseClass")
  private DataSource dataSource;

  @Before("execution(public java.sql.Connection javax.sql.DataSource+.getConnection(..))")
  public void myAdvice(JoinPoint thisJoinPoint) {
    System.out.println(thisJoinPoint);
  }
}

Unfortunately, with the AspectJ version I used to test this, the AspectJ compiler throws an exception. That might be a bug, I will look into it later and report to the maintainer. Update: I created AspectJ bug ticket #550494 for this problem. Update 2: The bug was fixed in AspectJ 1.9.5.

But if you just use native AspectJ syntax it works. The only bad news is that if you use javac + LTW and rely on the AspectJ weaver to finish the aspect during class-loading, this will no longer work. You have to compile an aspect in native syntax with the AspectJ compiler ajc.

package de.scrum_master.aspect;

import javax.sql.DataSource;

import de.scrum_master.app.BaseClass;

public aspect DataSourceConnectionAspect {
  declare parents: BaseClass implements DataSource;

  before() : execution(public java.sql.Connection javax.sql.DataSource+.getConnection(..)) {
    System.out.println(thisJoinPoint);
  }
}

Now the console log changes to:

Aspect should not kick in
execution(Connection de.scrum_master.app.BaseClass.getConnection())
execution(Connection de.scrum_master.app.BaseClass.getConnection(String, String))
Aspect should kick in
execution(Connection de.scrum_master.app.BaseClass.getConnection())
execution(Connection de.scrum_master.app.BaseClass.getConnection(String, String))

Of course "Aspect should not kick in" no longer applies here because now we do expect it to kick in, of course, as BaseClass now directly implements the DataSource interface.

A little disclaimer: This approach only works if all the interface methods are really present in the base class, which fortunately is the case for org.apache.tomcat.jdbc.pool.DataSourceProxy, i.e. you can adapt my aspect accordingly. If the base class would only implement part of the expected interface methods, you could also add them via ITD in native syntax, but I am not going to elaborate on that here, my answer is quite long already.

Last, but not least, this is what the byte code looks like with the new approach:

Compiled from "BaseClass.java"
public class de.scrum_master.app.BaseClass implements javax.sql.DataSource {
  (...)

  public java.sql.Connection getConnection() throws java.sql.SQLException;
    Code:
       0: getstatic     #58                 // Field ajc$tjp_0:Lorg/aspectj/lang/JoinPoint$StaticPart;
       3: aload_0
       4: aload_0
       5: invokestatic  #64                 // Method org/aspectj/runtime/reflect/Factory.makeJP:(Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint;
       8: astore_1
       9: invokestatic  #70                 // Method de/scrum_master/aspect/DataSourceConnectionAspect.aspectOf:()Lde/scrum_master/aspect/DataSourceConnectionAspect;
      12: aload_1
      13: invokevirtual #74                 // Method de/scrum_master/aspect/DataSourceConnectionAspect.ajc$before$de_scrum_master_aspect_DataSourceConnectionAspect$1$19879111:(Lorg/aspectj/lang/JoinPoint;)V
      16: aconst_null
      17: areturn

  public java.sql.Connection getConnection(java.lang.String, java.lang.String) throws java.sql.SQLException;
    Code:
       0: aload_1
       1: astore        4
       3: aload_2
       4: astore        5
       6: getstatic     #77                 // Field ajc$tjp_1:Lorg/aspectj/lang/JoinPoint$StaticPart;
       9: aload_0
      10: aload_0
      11: aload         4
      13: aload         5
      15: invokestatic  #80                 // Method org/aspectj/runtime/reflect/Factory.makeJP:(Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint;
      18: astore_3
      19: invokestatic  #70                 // Method de/scrum_master/aspect/DataSourceConnectionAspect.aspectOf:()Lde/scrum_master/aspect/DataSourceConnectionAspect;
      22: aload_3
      23: invokevirtual #74                 // Method de/scrum_master/aspect/DataSourceConnectionAspect.ajc$before$de_scrum_master_aspect_DataSourceConnectionAspect$1$19879111:(Lorg/aspectj/lang/JoinPoint;)V
      26: aconst_null
      27: areturn

  (...)
}

If you compare the two javap logs you will not only notice that now it says implements javax.sql.DataSource but also that in the old version there were 22/32 bytecode instructions for the two methods, whereas the in new version there are just 17/27. For instance, in the old version you see instanceof #76 // class javax/sql/DataSource. In the new version the instanceof check is no longer necessary.

You can decide by yourself if this makes it worth for you to use ITD and native syntax. I personally use native syntax and ajc anyway, so I would do it. If you never used the AspectJ compiler before and exclusively use LTW, the decision might be different. If there even would be a measurable performance gain is yet another question. I assume that in scenarios involving SQL database calls, probably not AspectJ is what eats up your performance. ;-) I was just curious to find out and answer your question.


Update: Alternative solution without ITD

According to your comment you want to avoid ITD, even though I think it is a clean and elegant solution. But there is also a way to optimise pointcut matching and performance like this:

package de.scrum_master.aspect;

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

@Aspect
public class AlternativeSolutionAspect {
  @Pointcut("execution(public java.sql.Connection getConnection(..))")
  private static void getConnection() {}

  @Pointcut("within(javax.sql.DataSource+)")
  private static void withinDataSource() {}

  @Pointcut("target(javax.sql.DataSource)")
  private static void targetDataSource() {}

  @Before("withinDataSource() && getConnection()")
  public void interceptStatically(JoinPoint thisJoinPoint) {
    System.out.println("[static] " + thisJoinPoint);
  }

  @Before("!withinDataSource() && getConnection() && targetDataSource()")
  public void interceptDynamically(JoinPoint thisJoinPoint) {
    System.out.println("[dynamic] " + thisJoinPoint);
  }
}

Explanation:

  • Advice interceptStatically takes care of finding all method executions for "normal" cases, i.e. (base) classes both implementing the interface and the corresponding methods.
  • Advice interceptDynamically takes care of the (exotic) rest, i.e. method executions where the actual instance implements the interface, but the method was defined in a (base) class not implementing the interface. The difference to your own purely dynamic solution is that here I am explicitly excluding the cases which can be determined statically.

Now what does that mean if we compare my DataSourceConnectionAspect to this AlternativeSolutionAspect? First let me add another sample class in order to make it clearer:

package de.scrum_master.app;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

public class SubClassOverridingMethods extends BaseClass implements DataSource {
  @Override
  public Connection getConnection() throws SQLException {
    return super.getConnection();
//    return null;
  }

  @Override
  public Connection getConnection(String username, String password) throws SQLException {
    return super.getConnection(username, password);
//    return null;
  }
}

Now we extend the driver application by additional method calls:

package de.scrum_master.app;

import java.sql.SQLException;

public class Application {
  public static void main(String[] args) throws SQLException {
    System.out.println("Aspect should not kick in without ITD, but should with ITD");
    new BaseClass().getConnection();
    new BaseClass().getConnection("user", "pw");

    System.out.println("Aspect should kick in");
    new SubClass().getConnection();
    new SubClass().getConnection("user", "pw");

    System.out.println("Aspect should kick in");
    new SubClassOverridingMethods().getConnection();
    new SubClassOverridingMethods().getConnection("user", "pw");
  }
}

The rest remains like in my example above.

Console log for DataSourceConnectionAspect:

Aspect should not kick in without ITD, but should with ITD
execution(Connection de.scrum_master.app.BaseClass.getConnection())
execution(Connection de.scrum_master.app.BaseClass.getConnection(String, String))
Aspect should kick in
execution(Connection de.scrum_master.app.BaseClass.getConnection())
execution(Connection de.scrum_master.app.BaseClass.getConnection(String, String))
Aspect should kick in
execution(Connection de.scrum_master.app.SubClassOverridingMethods.getConnection())
execution(Connection de.scrum_master.app.BaseClass.getConnection())
execution(Connection de.scrum_master.app.SubClassOverridingMethods.getConnection(String, String))
execution(Connection de.scrum_master.app.BaseClass.getConnection(String, String))

In case 3 you see 4 lines of log output for 2 method calls because the overriding methods call super.getConnection(..). If they would just do something without using super calls, there would only be one log line per method call, of course.

Console log for AlternativeSolutionAspect:

Aspect should not kick in without ITD, but should with ITD
Aspect should kick in
[dynamic] execution(Connection de.scrum_master.app.BaseClass.getConnection())
[dynamic] execution(Connection de.scrum_master.app.BaseClass.getConnection(String, String))
Aspect should kick in
[static] execution(Connection de.scrum_master.app.SubClassOverridingMethods.getConnection())
[dynamic] execution(Connection de.scrum_master.app.BaseClass.getConnection())
[static] execution(Connection de.scrum_master.app.SubClassOverridingMethods.getConnection(String, String))
[dynamic] execution(Connection de.scrum_master.app.BaseClass.getConnection(String, String))

As we do not use ITD here, nothing gets intercepted for case 1. Case 2 is intercepted dynamically while in case 3 the overriding methods can be determined statically and the super method dynamically. Again, if there were no super calls, we would only have one line of log output per method call for case 3.

P.S.: Your own solution would also match twice in case of super calls, just in case you wondered. But it would match dynamically both times, making it slower.

Question:

I have a bean to report to InfluxDB. The Database have in the table INFLUX_DB_SERVER registred InfluxDBs. If you look at the code you will see that the Method reportMemory do a lot of work, it constructs a Measurement and do call reportAll, all this work is useless when there is no InfluxDB.

So the idea is to skip that work if there is no InfluxDB. Since the public-void-methods do not return a value it has no impact to the surrounding application.

What I could do is I could write a method isWorkPossible and call the method every call. That might follow KISS but that violates DRY. So I like to archivee that using AOP.

But I like to skip the execution of all public void methods if no InfluxDBs are registred.

/**
 * The reporter to notify {@link InfluxDB influxDBs} for changes.
 */
@Named
public class InfluxDBReporter {
    /**
     * Logger for reporting. For security reasons neither the username nor the
     * password should be logged above {@link Level#FINER}.
     */
    private static final Logger LOG = Logger.getLogger(InfluxDBReporter.class.getCanonicalName());

    /**
     * The entitymanager to use, never <code>null</code>.
     */
    @PersistenceContext
    private final EntityManager entityManager = null;

    /**
     * The registred {@link InfluxDBServer} in key and the URL in value.
     */
    @SkipPublicVoidMethodsIfEmpty
    private final Map<InfluxDB, URL> dbs = new LinkedHashMap<>();

    /**
     * Initializes the connections.
     */
    @PostConstruct
    private void connect() {
        for (InfluxDBServer db : FROM(囗InfluxDBServer.class).all(entityManager)) {
            try {
                URL dbUrl = new URL(db.getUrl());
                InfluxDB idb = InfluxDBFactory.connect(db.getUrl(), db.getUsername(), db.getPassword());
                idb.setDatabase(db.getDatabaseName());
                dbs.put(idb, dbUrl);
            } catch (MalformedURLException e) {
                LOG.log(Level.SEVERE, db.getUrl(), e);
            }
        }
    }

    /**
     * Closes all connections to all {@link InfluxDB}.
     */
    @PreDestroy
    private void disconnect() {
        for (InfluxDB influxDB : dbs.keySet()) {
            try {
                influxDB.close();
            } catch (Exception e) {
                // Fault barrier
                LOG.log(Level.WARNING, "InfluxDBServer URL: " + dbs.get(idb), e);
            }
        }
    }

    /**
     * Report memory statistics.
     * 
     * @param availableProcessors Amount of available processors, never negative.
     * @param totalMemory         The total memory, never negative.
     * @param maxMemory           The max memory, never negative.
     * @param freeMemory          The free memory, never negative.
     */
    public void reportMemory(int availableProcessors, long totalMemory, long maxMemory, long freeMemory) {
        reportAll(Point.measurement("jvm").addField("totalMemory", totalMemory).addField("maxMemory", maxMemory)
                .addField("freeMemory", freeMemory));
    }

    /**
     * Report a point to all connected {@link InfluxDBServer}.
     * 
     * @param builder The point to report.
     */
    private void reportAll(Builder builder) {
        Point infoPoint = builder.time(System.currentTimeMillis(), TimeUnit.MILLISECONDS).build();
        for (InfluxDB idb : dbs.keySet()) {
            new Thread(() -> {
                try {
                    idb.write(infoPoint);
                } catch (Exception e) {
                    // Fault barrier
                    LOG.log(Level.WARNING, "InfluxDBServer URL: " + dbs.get(idb), e);
                    throw e;
                }
            }).start();
        }
    }
}

This is my aspect:

@Aspect
public class MethodAnnotations {
    @Pointcut("@annotation(xxx.MethodAnnotations.SkipPublicVoidMethodsIfEmpty)")
    private void anyOldTransfer(JoinPoint jp) {
        System.out.println(jp); <----- never executed.
    }

    public @interface SkipPublicVoidMethodsIfEmpty {
    }
}

I expect the System.out.println to run when the bean is instanticated but it does not.

Any idea why?


Answer:

As JB Nizet already said, @annotation(my.package.MyAnnotation) is designed to capture annotations on methods, not on fields, which explains why your expectation for anything to happen there is wrong.

If you want to find out via AOP if a class has a member with a specific annotation, you need to use a special pointcut like hasfield(@MyAnnotation * *). But that pointcut is unavailable in Spring AOP, you need to switch to AspectJ. The same is true if you want to intercept read/write access to such fields via get(@MyAnnotation MyType *) or set(@MyAnnotation MyType *).

For more details see my other answer here.

AspectJ also provides special pointcuts

  • to intercept static initialisation of a class after class-loading -> staticinitialization()
  • to intercept constructor execution -> MyType.new()

You can use those in order to execute your aspect advice whenever it is the right time to do so. In your example you could also more easily hook into @PostConstruct methods if it is clear that all target classes have one of those.

My answer is quite generic because you do not explain in detail what exactly you want to do. So feel free to ask follow-up questions.


Update: I checked your latest question update. I don't get it, this is a very contrived solution for a very simple problem also not a good case to be solved by AOP. As much as I love AOP, I am failing to see how this situation is a cross-cutting concern:

  • It seems to affect only a single class, InfluxDBReporter.
  • You are using an annotation which exists for the sole purpose of telling an aspect what to do.
  • To make things worse, you put the annotation onto a private field, but expect an external class (an aspect in this case) to react on it. While this is technically possible with AspectJ, it is bad design because you are bleeding private information to the outside.
  • By skipping the public method from your sample class you do not save any expensive DB-related operations because iterating over an empty KeySet means that just nothing will happen, so there also will not be any DB-related errors. The only thing really happening here are the builder calls. They should be cheap.

Even assuming you have many more public methods which should be skipped, I would actually design the AOP solution like this if you do want to stick with the approach:

  • Add a method public boolean isConnectedToDB() { return !dbs.isEmpty(); } to your application class.
  • In your aspect, use an @Around advice and call the boolean method from there, only calling joinPoint.proceed() if there are any connections. Otherwise don't proceed but do nothing instead (for void methods) or return a dummy result like null (for non-void methods).

The exact solution depends on whether you have only this one class or multiple ones with similar requirements, if you only have public void methods or also non-void ones.

Besides, you are mentioning INFLUX_DB_SERVER but I have no idea what this is because I cannot see it anywhere in your code.

Last, but not least: I just noticed that you expect something to happen in a method annotated by @Pointcut. Sorry, even if the pointcut was not wrong sothing would happen there because a pointcut definition is just to be used in an actual advice method such as @Before, @After, @Around. The actions you want to be performed go into the advice, not into the pointcut. I suggest you learn AOP basics first before you try to design AOP-based solutions.

Question:

There is a lot of documentation regarding weaving into JAR files, such as the examples described in the book AspectJ in Action: Second Edition.

However, I barely see any questions regarding weaving into WAR files. Due to the popularity of WAR files and the AspectJ library, I find it hard to believe that it's not supported, and so I'm hoping for some answers.

Let's say you have a "legacy" Java project which is being packaged as a WAR file using the maven-war-plugin plugin. Keep in mind that changing it from WAR to JAR packaging is nearly impossible due to the risk involved.

Now, let's say I wanted to introduce AOP for some cross-cutting functionality. Due to the nature of our applications, my best bet is to create a separate project. So basically, the aspect classes will not be in the same project as the legacy project. It will be separate.

After this part, I'm stuck. From reading the book and the other documentation online, there seems to be two options for compile time weaving:

  1. Weave the sources directly. This can be done by creating the aspect classes directly in the legacy project, and then use aspectj-maven-plugin plugin. This is not really an option because I want my AOP logic to impact multiple projects and not just one project.
  2. Create a separate library and compile it using aspectj-maven-plugin plugin. Then create another maven project which will taken in the unwoven application and the aspect library, and weaves it together. Example taken from the book:
<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <weaveDependencies>
                    <weaveDependency>
                        <groupId>ajia.helloworld</groupId>
                        <artifactId>application-unwoven</artifactId>
                    </weaveDependency>
                </weaveDependencies>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>ajia.helloworld</groupId>
                        <artifactId>profiling-aspect-library</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
        </plugin>
    </plugins>
</build>

The problem with the second option is that <weaveDependency> requires the application to be a JAR file. Atleast, as far as I know.

I did come across a similar question on the AspectJ mailing list: http://aspectj.2085585.n4.nabble.com/Weaving-into-a-war-file-td2082924.html. In case the link expires, the answer to the question was:

you need to take it apart, weave the .jar and put it back together. You cannot directly weave the jar within the war

But is that even possible? I don't see any documentation for that either.

There are similar questions on SO which either don't have any responses at all or are wrong/outdated.

I would appreciate any help on this since I do not know what my next step should be.


Answer:

I'll try and present two distinct solutions and then you can pick/choose or mix/match how you go about implementing your solution.


Example 1: You have been asked to dump some text to stdout pre- and post-execution of the org.apache.log4j.Logger.info(Object o) method found in log4j.

(This is a very contrived example, but I'm using it because I have been asked to do something not entirely dissimilar in the past!)

I'll assume you're using a Multi-Module Maven Project.

To achieve this, we can consume the log4j jar (compiled classes), apply an Aspect to them, and spit out a new set of load-time-woven compiled classes. We do this by leveraging the weaveDependency functionality you've already called out in a module of its own. So, instead of depending on log4j in your projects, you'll depend on ltwjar-enhanced-log4j as described below.

With that in mind, create your project hierarchy thus:

ltwjar
      /ltwjar-ltwjar-enhanced-log4j
      /ltwjar-runtime

Setup your parent pom.xml to look something like this (we set a couple properties here just for convenience/consistency's sake - there are other ways to control versioning such as dependencyManagement and imported depdendencies, but that's for a different question!):

<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.example</groupId>
    <artifactId>ltwjar</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <properties>
        <aspectj.version>1.8.13</aspectj.version>
        <log4j.version>1.2.17</log4j.version>
    </properties>

    <modules>
        <module>ltwjar-enhanced-log4j</module>
        <module>ltwjar-runtime</module>
    </modules>
</project>

Set up your ltwjar-enhanced-log4j pom.xml like this:

<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>com.example</groupId>
        <artifactId>ltwjar</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>ltwjar-enhanced-log4j</artifactId>

    <dependencies>
        <!-- we need this because the post-weave classes may (will) depend on aspectj types -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>

        <!-- ATTENTION! Scope this to provided otherwise it won't work - because of transitive dependencies,
        anything that depends on this module will end up getting the _actual_ log4j classes versus the ones we are enriching! -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.11</version>
                <configuration>
                    <!-- instruct aspectj to weave the classes in the jar! -->
                    <weaveDependencies>
                        <weaveDependency>
                            <groupId>log4j</groupId>
                            <artifactId>log4j</artifactId>
                        </weaveDependency>
                    </weaveDependencies>
                    <Xlint>warning</Xlint>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

And now let's setup our stub "runtime" module to leverage the load-time-wove log4j ltw-enhanced-log4j when it logs by configuring its pom.xml thus:

<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>com.example</groupId>
    <artifactId>ltwjar</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>ltwjar-runtime</artifactId>
  <dependencies>
    <!-- Note that this module doesn't care (itself) about aspectj.
         It _does_ care that it depends on the ltwjar-enhanced-log4j module
         and not log4j, however. So let's depend on that! -->
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>ltwjar-enhanced-log4j</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
  </dependencies>
</project>

OK that's our framework setup. Now let's create a pointless aspect to demonstrate the point!

In ltwjar-enhanced-log4j create type com.example.aspect.LoggingAspect like so:

package com.example.aspect;

import org.apache.log4j.Logger;

public aspect LoggingAspect {
    // this pointcut will match "info(Object o)" method executions where the
    // target is an instanceof Logger
    pointcut logInfoWithObject(Object obj, Logger logger) :
         execution(void info(Object)) && args(obj) && target(logger);

    // here is our advice - simply sysout something before the execution
    // proceeds and after it has finished - regardless of outcome (exception
    // or not).
    void around(Object obj, Logger logger) : logInfoWithObject(obj, logger) {
        System.out.println("Before Logger.info(Object o)");

        try {
            proceed(obj, logger);
        } finally {
            System.out.println("After Logger.info(Object o)");
        }
    }
}

And finally in ltwjar-runtime, create a driver/harness that shows everything working. Type com.example.Driver:

package com.example;

import org.apache.log4j.Logger;

public class Driver {
    private static final Logger LOG = Logger.getLogger(Driver.class);

    public static void main(String[] args) {
        LOG.info("In main");
    }
}

Now from your parent project run mvn clean install and then mvn -pl ltwjar-runtime exec:java -Dexec.mainClass="com.example.Driver".

The output should be something like this (since you don't have a log4j.xml on your classpath):

Before Logger.info(Object o)
log4j:WARN No appenders could be found for logger (com.example.Driver).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
After Logger.info(Object o)

Note the first and last lines.

What's happening here:

  1. In ltwjar-enhanced-log4j we "enhance" log4j by wrapping an advice around Logger.info(Object o)
  2. We repackage log4j.jar into a new jar ltwjar-enhanced-log4j.jar that contains the woven type
  3. We depend on ltwjar-enhanced-log4j.jar instead of log4j in our application code...
  4. ...And in doing so, the advice sticks

OK so how does this fit into the warfile that was asked about originally?

Simple - don't put any code in your warfile module. If you have to put something in there, make it configuration. Instead, move all your code to a yourproject-domain or yourproject-logic or ... (insert module name here) and have your warfile depend on that module. This is good practice since it enables a Separation of Concerns: your application shouldn't know it's running under a warfile umbrella; it could just as easily be running as a Spring Boot tomcat uberwar etc. The packaging concern (war) is distinct from the business concern (domain).

I'll update with another example of shared aspect library this evening, unless someone beats me to it. Also, if some of this makes no sense, holler in comments!

Question:

I want to write an annotation in Java, which executes something before and after execution of the annotated method, similar to what can be done in Spring with aspects.

I've already tried a Spring aspect, but it only works for Beans (as this guy here mentioned) and I want to stay independent from the Spring framework.

A simple class that writes a String to the console:

public class Main {
    public static void main(String[] args) {
        say("How are you?");
    }

    @Hello
    private static void say(String s) {
        System.out.println(s);
    }
}

The associated annotation:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Hello {}

And I need something like (deduced from the Spring aspect)

public Object process(ProceedingJoinPoint proceedingJoinPoint) {
    System.out.println("Hello");
    Object proceed = null;
    try {
        proceed = proceedingJoinPoint.proceed();
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    System.out.println("world!");
    return proceed;
}

I want the following output:

Hello

How are you?

world!

Edit:

I created the following Aspect (without annotations), but it does not work

@lombok.extern.java.Log
public aspect Log {
    pointcut methodExecuted():execution(* **(..));

    void around(): methodExecuted() {
        log.info("Hello");
        proceed();
        log.info("world!");
    }
}

Where is my mistake?


Answer:

Assuming that you successfully compiled your aspect with the AspectJ compiler, it should work with the code you used, only that it would log all method executions, i.e. also main(..), so you would se the aspect's output twice before and after "How are you?". If you don't see anything probably you made a mistake in setting up your build system.

You should change the pointcut to actually limit logging to annotated methods: execution(* *(..)) && @annotation(Hello). Furthermore if your around advice has a void return type, logging will not work with non-void methods. So you should rather use a return type of Object and actually return the result of proceed().

I also strongly urge you to not just blindly wield a powerful tool like AspectJ but also study some documentation before you do. It is quite obvious that you have not done so or only very cursorily. Then you get the effect of being a not-so-capable-user with a tool. ;-)

Here is my MCVE:

package de.scrum_master.app;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(METHOD)
public @interface Hello {}
package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    say("How are you?");
  }

  @Hello
  private static void say(String s) {
    System.out.println(s);
  }
}
package de.scrum_master.aspect;

import de.scrum_master.app.Hello;

public aspect LoggingAspect {
  pointcut methodExecuted() : execution(* *(..)) && @annotation(Hello);

  Object around(): methodExecuted() {
    System.out.println("Hello");
    Object result = proceed();
    System.out.println("world!");
    return result;
  }
}

Console log:

Hello
How are you?
world!

Question:

I've added a github repo that show exactly my problem:

https://github.com/runefist/AspectJ-Stackoverflow-Q


In short, I have a project we'll call it ProjectA. ProjectA is a microprofile-REST-server. Another project, we'll call this ProjectB, is a dependency for ProjectA (and other projects).

  • ProjectA (microprofile-REST-server)
  • ProjectB (dependency of ProjectA)

ProjectB contains an Aspect:

@Aspect
public class ElasticSenderAspect {

    @After("@annotation(elasticsender)") // && execution(* *(..))
    public void after(JoinPoint joinPoint, ElasticSender elasticsender) {
         WebsiteBehaviour websiteBehaviour = new WebsiteBehaviour();  
         websiteBehaviour.setBehaviourFunc(elasticsender.behaviourFunction());
         websiteBehaviour.setBehaviourType(elasticsender.behaviourType());
         ElasticWebsiteBehaviour.sendWebsiteBehaviour(websiteBehaviour);
    }
}

In ProjectA I have a function:

@GET
@Operation(description = "Authenticate")
@ElasticSender(behaviourFunction = "Authenticate")
public Response authenticate(@HeaderParam("authorization") String authString) {
    if (authString == null) {
        return StandardResponseMessages.GENERAL_NO_AUTHENTICATION.getResponse();
    }
    WebAccount webAccount = webAccountService.find(getUsernameFromAuth(authString));
    boolean correct = false;
    //TODO: CHECK IF ACCOUNT IS VERIFIED
    if (webAccount != null) {
        if (webAccount.getUsername() != null && webAccount.getPassword() != null) {
            if (AuthenticatorUtility.basicAuthenticate(webAccount.getUsername(), webAccount.getPassword(), authString)) {
                correct = true;
            }
        }
    }
    if (correct) {
        return Response.ok(generateTokenString(webAccount)).build();
    } else {
        return StandardResponseMessages.GENERAL_WRONG_AUTHENTICATION.getResponse();
    }
}

I've tested the Aspect, which works when I use it in the SAME project, so NOT as dependency.

ProjectA - 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>com.runefist</groupId>
    <artifactId>FeestjesDoen-Server</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>

    <name>FeestjesDoen-Server</name>

    <properties>
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <repositories>
        <repository>
            <id>BendingHeroes-repo</id>
            <url>xxx</url>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>daily</updatePolicy>
            </snapshots>
        </repository>
    </repositories>

    <dependencies>
        <!-- MAIN DEPENDENCY -->
        <dependency>
            <groupId>com.runefist</groupId>
            <artifactId>WebRest-Utilities</artifactId>
            <version>1.0.0</version>
        </dependency>
        <!-- MICROPROFILE SWAGGER UI -->
        <dependency>
            <groupId>org.microprofile-ext.openapi-ext</groupId>
            <artifactId>swagger-ui</artifactId>
            <version>1.0.1</version>
            <scope>runtime</scope>
        </dependency>
        <!-- KAFKA NEEDED -->
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka-clients</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.25</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <showWeaveInfo>true</showWeaveInfo>
                    <encoding>UTF-8 </encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

ProjectB - 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>com.runefist</groupId>
    <artifactId>WebRest-Utilities</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- MICROPROFILE REPLACES JAVAEE -->
        <dependency>
            <groupId>org.eclipse.microprofile</groupId>
            <artifactId>microprofile</artifactId>
            <version>2.1</version>
            <type>pom</type>
        </dependency>
        <!-- FOR CREATING JWT TOKENS -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
            <type>jar</type>
        </dependency>
        <!-- FOR THE USE OF HIBERNATE -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>5.3.1.Final</version>
        </dependency>
        <!-- MYSQL CONNECTOR FOR HIBERNATE -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.26</version>
            <scope>compile</scope>
        </dependency>
        <!-- FOR JSON CONVERSION -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.0</version>
        </dependency>
        <!-- ElasticSearch -->
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>6.5.2</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>6.5.4</version>
            <type>jar</type>
        </dependency>
        <!-- AspectJ | to add behaviour to methods -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.2</version>
        </dependency>
        <!-- Junit - TEMP added to test -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
            <type>jar</type>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.7</version>
                <configuration>
                    <complianceLevel>1.8</complianceLevel>
                    <source>1.8</source>
                    <target>1.8</target>
                    <verbose>true</verbose>
                    <Xlint>ignore</Xlint>
                    <encoding>UTF-8</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>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <!-- put your configurations here -->
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Problem:

Aspect happens when tested in ProjectB, aspect does NOT happen when tested in ProjectA. What do I need to add to ProjectA pom to make it work, or what do I need to change to ProjectB pom to make it work?


Answer:

In project A you need to add B as an aspect library in the AspectJ Maven configuration in addition to adding it as a Maven dependency as you already did:

            <configuration>
                <!-- (...) -->
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>com.runefist</groupId>
                        <artifactId>ProjectB</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>

I cloned and tested your project, it works this way.

Question:

Suppose that I have this class

public class MyClass {
    private Logger log = LogFactory.getLogger(MyClass.class);

    public void doSomething() {
        // doing something
    }
}

Suppose that I want to write an aspect to log entry and exit:

public aspect TraceAspect {

    pointcut method(): execution(* *(..));

    before(): method(){

        log.info("entering method");
    }

    after(): method(){
        log.info("existing method");
    }
}

The problem here is that I want to access the log object inside the class with aspect, but I don't know how. I don't want to create a new logger because I want to keep all the data associated with the class logger when logging. Is there a way or a pattern to access class data?

EDIT: wanted to state that this aspect should trace all classes that have log field. That is, I might have many classes: MyClass, MyClass1, YourClass2, RepositoryClass, etc.


Answer:

What Nándor said is technically correct, but my advice is: Please avoid accessing private members or methods whenever you can because they are private for a reason. For instance, they are subject to change even when the public interface of a class does not change. So you can never rely on their existence or their naming. Furthermore, a cross-cutting concern should also comply with design principles like encapsulation as much as possible.

This specific case is about Slf4J loggers, more precisely about your wish to avoid creating redundant logger objects. Well, Slf4J is not as stupid or careless as you might think concerning object creation. All classes implementing ILoggerFactory use an internal map in order to cache existing loggers for given (class) names, see e.g.

So why don't you just relax and access the corresponding loggers from your aspect using the target class names. This even works if a target class does not have its own static logger:

Application classes:

package de.scrum_master.app;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyClassWithLogger {
  private Logger log = LoggerFactory.getLogger(MyClassWithLogger.class);

  public void doSomething() {}
}
package de.scrum_master.app;

public class MyClassWithoutLogger {
  public void doSomething() {}
}
package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    new MyClassWithLogger().doSomething();
    new MyClassWithoutLogger().doSomething();
  }
}

Aspect:

package de.scrum_master.aspect;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public aspect TraceAspect {
  pointcut executedMethods(Object targetObject) :
    execution(!static * *(..)) && target(targetObject);

  before(Object targetObject) : executedMethods(targetObject) {
    Logger log = LoggerFactory.getLogger(targetObject.getClass());
    log.info("Entering " + thisJoinPoint);
  }

  after(Object targetObject) : executedMethods(targetObject) {
    Logger log = LoggerFactory.getLogger(targetObject.getClass());
    log.info("Exiting " + thisJoinPoint);
  }
}

Console log with Slf4J configured to use simple logger:

[main] INFO de.scrum_master.app.MyClassWithLogger - Entering execution(void de.scrum_master.app.MyClassWithLogger.doSomething())
[main] INFO de.scrum_master.app.MyClassWithLogger - Exiting execution(void de.scrum_master.app.MyClassWithLogger.doSomething())
[main] INFO de.scrum_master.app.MyClassWithoutLogger - Entering execution(void de.scrum_master.app.MyClassWithoutLogger.doSomething())
[main] INFO de.scrum_master.app.MyClassWithoutLogger - Exiting execution(void de.scrum_master.app.MyClassWithoutLogger.doSomething())

Question:

I had to revive an old project that worked about a year and a half ago, but now when I do:

mvn clean install

either on the command line or via eclipse, it compiles fine but does not add the main-class in the manifest AND I do have the proper directive.

I'm using:

  • Apache Maven 3.5.4
  • JDK 10.0.2
  • eclipse 4.8.0 (Photon)

So here is the abbreviated version of the 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>com.a.b.c</groupId>
    <artifactId>JarNameHere</artifactId>
    <version>0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <log4j.version>2.4</log4j.version> 
        <http.client.version>4.5.2</http.client.version>
        <maven.compiler.source>10</maven.compiler.source>
        <maven.compiler.target>10</maven.compiler.target>
    </properties>

    <dependencies>
       <!-- DEPENDENCIES HERE, BUT REMOVED TO MAKE MORE READABLE -->
       ...
    </dependencies>
    <build>
        <pluginManagement>
            <plugins>
                <!-- Maven Assembly Plugin -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <configuration>
                        <!-- get all project dependencies -->
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                        <!-- MainClass in mainfest make a executable jar -->
                        <archive>
                            <manifest> 
                                <mainClass>com.a.b.c.MainClass</mainClass>
                            </manifest>
                        </archive>
                    </configuration>
                    <executions>
                        <execution>
                            <id>make-assembly</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <!-- AspectJ configuration -->
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>1.11</version>
                    <configuration>
                        <complianceLevel>1.11</complianceLevel>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <!--  -->
            </plugins>
        </pluginManagement>
    </build>
</project>

Answer:

You made a classical beginner's mistake: You are assuming that the plugins configured in the pluginManagement section will automatically be used during the build. In fact, they will not. Neither AspectJ Maven nor Assembly will run like this, so of course there will not be any JAR with dependencies in your target directory.

You need to add the plugins explicitly to the plugins section, too, referencing them at least by group ID and name (not version or configuration necessary there, unless you want to override what you already defined in pluginManagement).

Besides that you will notice that AspectJ Maven is still misconfigured and the build will fail as soon as the plugin is activated. But that is outside the scope of your question, so I am not going to elaborate on that here.

P.S.: I copied your settings into my own POM, fixed them and can confirm that as soon as the AspectJ plugin has the right settings, the Assembly plugin does its job as expected including manifest with the right main class.


Update: So you only provide a POM fragment without any code to compile and run, but you want to see my full POM. I find that a bit strange because actually you should provide an MCVE. But anyway, here is what I have: I just incorporated your Assembly Plugin into one of my own projects where I usually use a One-JAR Plugin (builds an executeable JAR of JARs), replaced my plugin by yours and checked if I could run the executeable with java -jar .... The test was successful. I am still on JDK 8, though, for this question I did not upgrade my whole build system. For the example I also stripped out all my other dependencies except AspectJ runtime.

<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.a.b.c</groupId>
  <artifactId>JarNameHere</artifactId>
  <version>0.1-SNAPSHOT</version>

  <properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <main-class>com.a.b.c.MainClass</main-class>
    <aspectj.version>1.8.13</aspectj.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <build>

    <pluginManagement>
      <plugins>
        <!-- Maven Assembly Plugin -->
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-assembly-plugin</artifactId>
          <configuration>
            <!-- get all project dependencies -->
            <descriptorRefs>
              <descriptorRef>jar-with-dependencies</descriptorRef>
            </descriptorRefs>
            <!-- MainClass in mainfest make a executable jar -->
            <archive>
              <manifest>
                <mainClass>${main-class}</mainClass>
              </manifest>
            </archive>
          </configuration>
          <executions>
            <execution>
              <id>make-assembly</id>
              <phase>package</phase>
              <goals>
                <goal>single</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
        <!-- AspectJ configuration -->
        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>aspectj-maven-plugin</artifactId>
          <version>1.11</version>
          <configuration>
            <!--<showWeaveInfo>true</showWeaveInfo>-->
            <source>${maven.compiler.source}</source>
            <target>${maven.compiler.target}</target>
            <Xlint>ignore</Xlint>
            <complianceLevel>${maven.compiler.target}</complianceLevel>
            <encoding>${project.build.sourceEncoding}</encoding>
            <!--<verbose>true</verbose>-->
            <!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn>-->
          </configuration>
          <executions>
            <execution>
              <phase>process-sources</phase>
              <goals>
                <goal>compile</goal>
                <goal>test-compile</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </pluginManagement>

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

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
        <scope>runtime</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

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

</project>

Question:

in my project I have a set of classes (whose names and number I don't apriori) which I want to add a public static method to.

For simplicity, let assume that I want to add a static method which returns the static logger instance of the class. The only requirement is that the static function should be called as follows:

public class Foo {
    private static final Logger LOG = LoggerFactor.getLogger(Foo.class);

    public static void main(String[] args) {
        Foo.getLogger().info("works!");
    }
}

Since I think this a cross cutting concern I think solving my issue with AspectJ here, but I didn't find any information about my scenario.

My questions are:

  • if this is even possible?
  • if so, how can you achieve it?

I'm aware of the possibility of dyamically declare the parent of my classes implementing an interface, but then I'm stuck because I cannot generate static methods on interface:

public aspect StaticMethodAspect {

    public interface HasStaticMethod {}

    declare parents: ... implements HasStaticMethod;

    public static Logger HasStaticMethod.getLogger() { //aspect error
        ...
    }

}

And I'm also aware of this solution, but it doesn't meet my requirement about the way of call the method.

Thanks for any kind reply


Answer:

If you want to declare static methods or members via ITD you need to know the class name, which is not the case for you. So you are stuck with doing things similar to what you already found, see also my answers here:

  • https://stackoverflow.com/a/29060099/1082681
  • https://stackoverflow.com/a/12127220/1082681
  • https://stackoverflow.com/a/7393364/1082681

These examples also show how to log directly from another aspect because usually logging is also a cross-cutting concern. So if you can avoid logging manually, just use my approach.

But if you definitely do want to have a static logger for each target class and indeed use it the way your sample code shows, use the AspectJ integration with annotation processing briefly described and linked to from my first answer on the above list. Feel free to ask follow-up questions in case you do not understand the sample code from both links I provided there.

Question:

How to write an aspect or annotation for a method that cannot update any instance variables?

Say for example I have the following java class

public class Foo {

    String name;
    int id;

    public getName() {
       return name;
    }
}

Now say I want to write an aspect or in general, some annotation call it say @readOnly which can enforce getName() method to not modify either name or id so if do

public class Foo {

    String name;
    int id;

    @readOnly
    public getName() {
       name = "hello world";
       id = 7564;
       return name;
    }
}

Any invocation of getName() like above should result in an error since it modifies both name and id

The class like below should be just fine since it just doing read of instance variables.

public class Foo {

    String name;
    int id;

    @readOnly
    public getName() {
       return name + "," + id;
    }
}

Answer:

How about directly throwing a compile error when there is any member write access in any get*() method?

Marker annotation:

package de.scrum_master.app;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD })
public @interface ReadOnly {}

Sample class / driver application:

package de.scrum_master.app;

public class Application {
  private int id = 1;
  private String name = "default";

  @ReadOnly
  public int getId() {
    return id;
  }

  @ReadOnly
  public String getName() {
    name = "hello world";
    id = 7564;
    return name;
  }

  public String getNameWithoutReadOnly() {
    name = "hello world";
    id = 7564;
    return name;
  }

  @ReadOnly
  public String getNameIndirectly() {
    modifyMembers();
    return name;
  }

  private void modifyMembers() {
    name = "hello world";
    id = 7564;
  }

  public static void main(String[] args) {
    Application application = new Application();
    application.getId();
    try { application.getName(); }
    catch (Exception e) { e.printStackTrace(System.out); }
    application.getNameWithoutReadOnly();
    try { application.getNameIndirectly(); }
    catch (Exception e) { e.printStackTrace(System.out); }
  }
}

Aspect declaring compile error:

The following aspect only detects @ReadOnly annotations on methods, not on classes or members. You can extend it if you also need that.

The declare error statement directly throws compile errors when compiling your application with the AspectJ compiler. In Eclipse you would see something like this:

If you also want to detect indirect write access from helper methods called by a getter, you also need the dynamic pointcut with cflow(), but that one only works at runtime, not at compile time, because it inspects the callstack. If you do not need it, just remove it.

package de.scrum_master.aspect;

import de.scrum_master.app.ReadOnly;

public aspect ReadOnlyGetterAspect {
  declare error :
    set(* *) && withincode(public * get*()) && @withincode(ReadOnly) :
      "Setting members from within a getter is forbidden";

  before() : set(* *) && cflow(execution(@ReadOnly public * get*())) {
    throw new IllegalAccessError("Setting members from within a getter is forbidden");
  }
}

BTW, if you want to see the runtime pointcut/advice in action, you need to make the code compile first. So you either need to weaken declare error into declare warning or comment out the two statements causing the compile errors in getName().

If you do the former, your log output will be:

java.lang.IllegalAccessError: Setting members from within a getter is forbidden
    at de.scrum_master.aspect.ReadOnlyGetterAspect.ajc$before$de_scrum_master_aspect_ReadOnlyGetterAspect$1$3e55e852(ReadOnlyGetterAspect.aj:11)
    at de.scrum_master.app.Application.getName(Application.java:14)
    at de.scrum_master.app.Application.main(Application.java:39)
java.lang.IllegalAccessError: Setting members from within a getter is forbidden
    at de.scrum_master.aspect.ReadOnlyGetterAspect.ajc$before$de_scrum_master_aspect_ReadOnlyGetterAspect$1$3e55e852(ReadOnlyGetterAspect.aj:11)
    at de.scrum_master.app.Application.modifyMembers(Application.java:32)
    at de.scrum_master.app.Application.getNameIndirectly(Application.java:27)
    at de.scrum_master.app.Application.main(Application.java:42)

If you do the latter (fix the code), of course you will only see the second exception.

Question:

I have created an annotation with name Validation and inject on method parameter and I have been using aspect before invocation to validate my object. It is not working

Annotation code

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Validation {}

Aop Code

@Aspect
@Component
public class ValidatorAOP {
    @Before("valditionAnnotation()")
    public void validate(final JoinPoint jp) throws Throwable {
        Validator object = (Validator) jp.getTarget();
        object.validator();
    }
    @Pointcut("@annotation(Validation)")
    public void valditionAnnotation() {
    }
}

Using annotation as public TrackingId createNewOrder(@Validation Order newOrder)


Answer:

This is called before any method that has argument annotated with @Validation, I think that's what you wanted:

@Before("execution(* *(.., @Validation (*), ..)) && args(.., toVerify)")
public void validate(final JoinPoint joinPoint, final Object toVerify) {

}

If you don't want the parameter value then just remove the && ... part and method argument.

@Before("execution(* *(.., @Validation (*), ..)) && args(.., toVerify)")
  |          |     | |  |     |         |   |    |   |    |      |
  1          2     3 4  5     6         7   8    9   10   11     12
  1. advice called before a join point
  2. matching method execution join point
  3. method visibility, matching any (public, private etc.)
  4. method name, matching any
  5. in case your argument is not the only one, it can be between other arguments (not annotated with @Validation)
  6. the annotation you are looking for
  7. types of arguments to the annotation
  8. see 5.
  9. to combine expressions
  10. making the argument available to your method
  11. as in 5 and 8, it may not be the first argument
  12. name of the argument, same as in method signature (Object toVerify)

Be careful if you have methods with multiple parameters, some annotated, some not, and other combinations - not sure it's gonna always work.

Question:

I have the following classes:

public class Population {
    private int population;

    public Population()
    {
        population = 0;
    }

    public void newYear()
    {
        population += 10;
    }

    public int getPopulation() {
        return population;
    }
}

and the following aspect

public aspect StatisticsAspect {

    private static int year = 0;

    pointcut operation(Population caller) : call(* Population.newYear());

    after(Population caller) : operation(caller)
    {
        System.out.println("New Year: " + year);
        year++;

        System.out.println("Population: " + caller.getPopulation());
    } 
}

Now I want that everytime when newYear() is called, that the "statistics" are printed to the console. Unfortunately I get the ajc: formal unbound in pointcut error.

What do I need to change to make it work?


Answer:

I refactored your code a bit because getPopulation() is a bad name and against conventions. Not the population object s returned as the name implies but the population's size.

As for your aspect, the naming caller is also bad because the object is not the caller but the callee or the target of the call. I simply renamed the parameter to population because this time it really contains a population object. Then I bound it to a target() parameter in order to make your error message go away.

I also switched from call() to execution() pointcut because it is more efficient to weave the code into the executed method instead of into every single place where the method is called.

I also made sure that the count starts at 1, not 0, after the first new year is over and the population has grown. I did this by using ++size rather than size++, i.e. pre- instead of post-increment.

Now the code looks like this:

package de.scrum_master.app;

public class Population {
  private int size;

  public Population() {
    size = 0;
  }

  public void newYear() {
    size += 10;
  }

  public int getSize() {
    return size;
  }

  public static void main(String[] args) {
    Population population1 = new Population();
    population1.newYear();
    population1.newYear();
    Population population2 = new Population();
    population2.newYear();
    population2.newYear();
  }
}
package de.scrum_master.aspect;

import de.scrum_master.app.Population;

public aspect StatisticsAspect {
  private static int year = 0;

  pointcut operation(Population population) :
    execution(* Population.newYear()) && target(population);

  after(Population population) : operation(population) {
    System.out.printf("Population for year %d = %d%n", ++year, population.getSize());
  }
}

Now look at the console log:

Population for year 1 = 10
Population for year 2 = 20
Population for year 3 = 10
Population for year 4 = 20

Can you spot the problem? You have one overall year counter, but multiple populations. Actually, you should have one year counter per population in order to get your statistics right. This can be done by using one aspect instance per target (i.e. per population) instead of a singleton aspect and of course by no longer making the year counter static:

package de.scrum_master.aspect;

import de.scrum_master.app.Population;

public aspect StatisticsAspect pertarget(execution(Population.new(..))) {
  private int year = 0;

  pointcut operation(Population population) :
    execution(* Population.newYear()) && target(population);

  after(Population population) : operation(population) {
    System.out.printf("%s size for year %d = %d%n", population, ++year, population.getSize());
  }
}

Here, pertarget(execution(Population.new(..))) means: Create one aspect instance per Population constructor execution, i.e. per created object.

Now the statistics are correct (I also changed the log message a bit in order to print the object ID so we can see which message belongs to which population):

de.scrum_master.app.Population@1d44bcfa size for year 1 = 10
de.scrum_master.app.Population@1d44bcfa size for year 2 = 20
de.scrum_master.app.Population@266474c2 size for year 1 = 10
de.scrum_master.app.Population@266474c2 size for year 2 = 20

Question:

I am trying to get aspectj to intercept annotated methods:

@Aspect
    public class InterceptMeAspect {
      @Around("execution(* *(..)) && within(@InterceptMe *)")
      public Object doIntercept(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("intercepted:");
        return proceedingJoinPoint.proceed();
      }
    }

    public class InterceptedExample {
        @InterceptMe
        public void doSomething(){

        }
    }

I removed the !within(InterceptMeAspect) for brevity, but it isn't intercepting too much anyways. If I remove the annotation constraint (within(@InterceptMe *)), it works, but intercepts everything and makes for a big problem.

The output bytecode appears to have the annotations intact, so I would expect the annotation criteria to match. I am doing or attempting to do compile-time weaving. This is important because I have another aspect that does work using the same approach above. I suspect that aspect is messing with this one, but the final bytecode shouldn't have the annotation, right?

EDIT: This is the code for the other aspect:

@Around(
      "execution(protected * *(..)) && !within(com.walterjwhite.logging..*) && !call(*.new(..)) && within(@ContextualLoggable *) && !within(@NonLoggable *)")

I have a generic logging aspect and a special contextual logging aspect. I am guessing this is incorrectly written as well and should be following the format from above.


Answer:

Instead of @Around("execution(* *(..)) && within(@InterceptMe *)"). It should be @Around("execution(* *(..)) && @annotation(your.package.InterceptMe )")

Or, if you need to access some properties from annotation:

@Around("execution(* *(..)) && @annotation(interceptMeVar)")
public Object doIntercept(ProceedingJoinPoint proceedingJoinPoint,InterceptMe interceptMeVar)

Question:

I have defined annotation with @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME)

When I use custom annotation under method which i want to aspect, and then i want to get the parameters(they are Object, not string, int ant byte) of the method signature.

is there simple way to get method parameter with custom annotation of AOP?


Answer:

A simple demo can as:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodTimer {
}

And the aspect handler:

@Aspect
@Slf4j
@Component
public class TimeCounterAspect {
    @Around("@annotation(methodTimer)")
    public Object logMethodRequests(ProceedingJoinPoint joinPoint, MethodTimer methodTimer)
            throws Throwable {
        Long start = System.currentTimeMillis();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();
        Object[] myArgs = joinPoint.getArgs();
        Object obj = null;
        try {
            obj = joinPoint.proceed();
        } catch (Exception e) {
            throw e;
        } finally {
                log.info("Retrieving timeCost: {} ms in Method: {} args: {}",
                System.currentTimeMillis() - start, methodName, Arrays.deepToString(myArgs));
        }
        return obj;
    }
}

Question:

I have made an annotation(@MethodLogger) and written an aspect over it which basically logs the timing of the method and keep storing it. So on any method on which i put that annotation it works fine But in a special use case I need to monitor an advice itself:

eg:

@MethodLogger
@Around("some function specified")
public Object method(ProceedingJoinPoint pjp) throws Throwable{


// code here

}

But this thing does not works. It never invokes my annotations aspect.


Answer:

This does not work in Spring AOP, as is documented here:

Advising aspects with other aspects?

In Spring AOP, it is not possible to have aspects themselves be the target of advice from other aspects. The @Aspect annotation on a class marks it as an aspect, and hence excludes it from auto-proxying.

If you want to do this, you need to activate full AspectJ via LTW in Spring. Then you can target advices directly if you know their method name. There even is a special pointcut designator adviceexecution() if you generally want to limit pointcut matching to advice execution or exclude the latter from matching via !adviceexecution(). For more details please check the AspectJ documentation.

Question:

I'm trying to use Openclover with a project that uses AspectJ and that instruments aspects into its code.

The pom.xml has these dependencies with relation to AspectJ:

...
<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.9</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.8.9</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
...

And these plugins:

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

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
        </plugin>

        <plugin>
            <groupId>org.openclover</groupId>
            <artifactId>clover-aspectj-compiler</artifactId>
            <version>1.0.0</version>
        </plugin>

        <plugin>
            <groupId>org.openclover</groupId>
            <artifactId>clover-maven-plugin</artifactId>
            <version>4.2.0</version>
            <executions>
                <execution>
                    <id>clover</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>instrument</goal>
                        <goal>clover</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>

I'm using two plugins to do this: clover-maven-plugin which is a code coverage tool and clover-aspectj-compiler, a wrapper for AspectJ compiler which allows code instrumentation using OpenClover.

The errors I get are the following:

[ERROR] QueryAspect.java:48:0::0 The type QueryAspect is already defined
[ERROR] LogAspect.java:35:0::0 The type LogAspect is already defined

The documentation about this is just too little (or better, none) and I can't seem to make AspectJ work with OpenClover, and there isn't much help on the web.

Thank you


Answer:

As discussed in our comments, you can just use AspectJ Maven instead of Clover AspectJ. You just need to take a few precautions in order to get it to work:

  • I like to put AspectJ Maven executions into the process-sources phase in order to make sure the AspectJ compiler kicks in before the normal Java compiler kicked off by Maven Compiler plugin. You could also deactivate Maven Compiler instead as Ajc is a full replacement for Javac. Actually that phase used to be the default in older plugin versions, but it has been changed long ago, which is also mentioned in an answer on SO.

  • There is a problem in Maven Compiler, namely the switch useIncrementalCompilation seems to have reversed logic. This is why you need to set it to false in order to make it work. Otherwise it tries to recompile stuff already compiled by AspectJ, breaking aspect weaving. See MCOMPILER-209 and MCOMPILER-194, I explained the problem and its solution there in my posts.

  • Now the only issue actually related to OpenClover (OC): AspectJ (AJ) does not know anything about OC adding source code to each method in order to enable code coverage. Unfortunately OC also does not know about AJ and also adds code to annotation-style pointcuts defined as empty methods with a @Pointcut annotation. As OC needs to do its magic before AJ compiles, the AJ compiler complains about unexpected code found in the pointcut and stops compilation with an error. There are at least two ways to avoid that:

    • You can either inline all pointcuts into the respective @Before, @After, @Around etc. advices using them, which usually works, but is not always an option in cases where you need argument binding in pointcuts in order to implement a wormhole pattern like execution(pointcutA()) && cflow(execution(pointcutB(myArgument))).

    • Or you can exclude all aspects from OC instrumentation, which is easiest if they reside in one package where there are no other Java classes which need to be instrumented. Then you can use a simple exclusion like in your case <exclude>codeaspects/**</exclude>. This is what I was doing in my pull request when fixing your project.

    • The easiest way is to just rename all aspects from *.java to *.aj, which is the canonical way of naming them anyway. I just tried in your project, and it works beautifully. AspectJ Maven looks for those files anyway, but OC will ignore them, not even calculating their lines of code for missing coverage. You can also get rid of the <exclude> mentioned above, see this commit.

Maybe all of this is automatically taken care of by Clover AspectJ, I never tried. Maybe the author of that compiler wrapper should actually explain what it does and how it works in the documentation, especially how to use it with Maven. Otherwise it does not make much sense to use it.

Question:

the exception trace is:

 Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut peformance
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:125)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:109)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:261)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
    ... 29 more
Caused by: java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut peformance
    at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:319)
    at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:207)
    at org.springframework.aop.aspectj.AspectJExpressionPointcut.checkReadyToMatch(AspectJExpressionPointcut.java:193)
    at org.springframework.aop.aspectj.AspectJExpressionPointcut.getClassFilter(AspectJExpressionPointcut.java:170)
    at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:194)
    at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:248)
    at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:280)
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:118)
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:88)
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:69)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:346)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:298)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1583)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
    ... 43 more

i read a lot of topics about this problem but i haven't solved yet... maybe i'm searching too far the solution. I have the followings classes:

i create a interface to be enhance:

public interface Performer {
    void peform();
}

the impl class:

@Component
public class PianoShow implements Performer{
    public void peform() {
        System.out.println("this is a piano show, enjoy it !!!");
    }
}

the aop class:

@Aspect
@Component
public class AspectJAudience {
    @Pointcut("execution(* org.test.spring.aop.Performer.peform(..))")
    public void performance() {

    }

    @Before("performance()")
    public void takeSeats() {
        System.out.println("The audience is taking their seats.");
    }

    @Before("performance()")
    public void turnOffCellPhones() {
        System.out.println("The audience is turning off their cellphones");
    }

    @AfterReturning("performance()")
    public void applaud() {
        System.out.println("CLAP CLAP CLAP CLAP CLAP");
    }

    @AfterThrowing("peformance()")
    public void demandRefund() {
        System.out.println("Boo! We want our money back!");
    }
}

as some topic said, i have update the jar dependency of aop:

<properties>
           <spring.version>4.2.6.RELEASE</spring.version>
           <aspect.version>1.8.13</aspect.version>
</properties>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${aspect.version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${aspect.version}</version>
</dependency>
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

and the spring configure file is:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="org.test.spring.aop"/>

    <aop:aspectj-autoproxy />
</beans>

there are some answer about this kind topic, the solution is just update the version of the aop, i have done as they said, but it doesn't work, any help? thanks!

ps:it works when i use xml configure to execute aop, but it doesn't work when i use annotation way


Answer:

This is because of the spelling mistake in the second AfterThrowing expression. I've highlighted the code needs to be corrected.

@AfterThrowing("peformance()")
public void demandRefund() {
    System.out.println("Boo! We want our money back!");
}

@AfterThrowing("peformance()")

Thanks, Prabhu

Question:

I was learning AOP and came across a scenario .

All of the classes are within package com.spring and Pointcut defines @AfterReturning type of Advice for any method in any class of package com.spring with any number of arguments.

spring.xml is well defined, in my classpath and the provided code is running

So my question is, shouldn't this advice of Aspects class run infinitely as it itself satisfies Pointcut definition?

Here's my Aspect Class

package com.spring;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class Aspects {

    @AfterReturning(pointcut = "execution(* com.spring.*.*(..))", returning= "res")
    public void logAfterExecutionAdvice(int res){
        System.out.print("Result in advice: "+res);
         System.out.print(" In After Advice ");
  }
}

My Adder Class

package com.spring;

public class Adder {
    private int a;
    private int b;
    public int add(int a,int b){
       return (a+b);
    }
    /**
     * @return the a
     */
    public int getA() {
        return a;
    }
    /**
     * @param a the a to set
     */
    public void setA(int a) {
        this.a = a;
    }
    /**
     * @return the b
     */
    public int getB() {
        return b;
    }
    /**
     * @param b the b to set
     */
    public void setB(int b) {
        this.b = b;
    }
}

And my Main Class

package com.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

public static void main(String[] args) {
    ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
    Adder adder=(Adder)ctx.getBean("adder");
    System.out.print("Result=" + adder.add(2,3));
    }

}

The OUTPUT which I get is Result in advice: 5 In After Advice Result=5


Answer:

As per the Spring's AOP documentation here -

In Spring AOP, it is not possible to have aspects themselves be the target of advice from other aspects. The @Aspect annotation on a class marks it as an aspect, and hence excludes it from auto-proxying.

The classes marks as @Aspect are excluded from the auto-proxing and pointcuts.

So, if you try something like this -

package com.spring;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class Aspects {
    @After("execution(* com.spring.Aspects.*(..))")
    public void logAfterExecutionAdvice(){
        System.out.print("In After Advice ");
    }
}

The Spring will give an error something like -

Error:(12, 0) ajc: advice defined in com.spring.Aspects has not been applied [Xlint:adviceDidNotMatch]

Question:

I have finished the configuration of global-method-security which is using @EnableGlobalMethodSecurity(prePostEnabled=true),and now I need to apply aspectj-autoproxy(@EnableAspectJAutoProxy(proxyTargetClass=true)) for some extra method like making a log.But I find these two are conflict with each other.I know the reason for their conflict, but I do not know how to solve it.All these configurations are java-based.Please tell me if you know the solution.Thank you very much!

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration{
}
---------------------------------------------------------------------------
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass=true)
@ComponentScan
public class AspectConfig {

    @Bean
    public ActionRecord record()
    {
        return new ActionRecord();
    }
}  

WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.event.internalEventListenerProcessor': BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'metaDataSourceAdvisor': Cannot resolve reference to bean 'methodSecurityMetadataSource' while setting constructor argument; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'methodSecurityConfig': Unsatisfied dependency expressed through method 'setObjectPostProcessor' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: warning no match for this type name: beike.visitorsystem.authority.controller [Xlint:invalidAbsoluteTypeName]
Jan 07, 2018 6:02:30  org.springframework.web.context.ContextLoader initWebApplicationContext
Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.event.internalEventListenerProcessor': BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'metaDataSourceAdvisor': Cannot resolve reference to bean 'methodSecurityMetadataSource' while setting constructor argument; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'methodSecurityConfig': Unsatisfied dependency expressed through method 'setObjectPostProcessor' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: warning no match for this type name: beike.visitorsystem.authority.controller [Xlint:invalidAbsoluteTypeName]

Answer:

If you want to include all classes in your package, you need to specify the following in your AspectJ config file: beike.visitorsystem.authority.controller.*

Otherwise, you can just specify beike.visitorsystem.authority.controller.AuthorityController

Question:

I don't have any experience with AspectJ but recently I've got task to implement and I've read several AspectJ tutorials so I think that AspectJ can be my solution.

The task is the following: I have a class A with some method b() and objects of this class are included as fields in other classes. I'd like to annotate these fields with some annotation @C and to get this annotation value each time I call the method b() on field with type A and annotation @C.

Simplified code:

   class A{
    field1;
    field2;
    field3;

        void b(String[] fieldsToIgnore){
         doSomething with fields 1,2,3 (excluding fields from fieldsToIgnore array)
    }
        }

   class B{
        @C(value="field1,field2")
        A fieldA;
        }


        //Here when I want to weaver my aspect - before I call to method b() on fieldA with annotation @C - I want to get annotation value and to pass it as an argument to method b()
        new B.fieldA.b()

Please help me to write correct pointcut for me advise. I also can't quite understand how can I transfer data from my advise method to my method b() - is it possible at all?

Will appreciate any help - even if you just tell mt "No, it's not possible" - it will save me a lot of time and nerves :)


Answer:

Actually, if you are already using reflection massively anyway - which is not an excuse for not refactoring the code, BTW - and wish to continue doing so, actually you do not really need AspectJ in order to make the mess even worse. You can just do it like this:

Helper class for reflective field access:

package de.scrum_master.app;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;

public class FieldHelper {
  public static Field getField(Class<?> clazz, String fieldName) {
    Field field;
    try {
      field = clazz.getDeclaredField(fieldName);
    } catch (NoSuchFieldException | SecurityException e) {
      throw new RuntimeException("Reflection problem", e);
    }
    field.setAccessible(true);
    return field;
  }

  public static Field[] getFields(Class<?> clazz) {
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields)
      field.setAccessible(true);
    return fields;
  }

  public static List<String> extractIgnoredFieldsList(Class<?> clazz, String fieldName) {
    return Arrays.asList(
      getField(clazz, fieldName)
        .getAnnotation(IgnoreFields.class)
        .fieldNames()
    );
  }
}

Marker annotation:

package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface IgnoreFields {
  public String[] fieldNames();
}

Class with method to be called:

package de.scrum_master.app;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.List;

import static de.scrum_master.app.FieldHelper.*;

public class A {
  int number = 11;
  String text = "Hi there!";
  Date date = new Date();
  String optionalText = "I am not really always needed";
  int optionalNumber = 123;

  public void doSomething(List<String> ignoredFields) {
    for (Field field : getFields(this.getClass())) {
      if (!ignoredFields.contains(field.getName())) {
        try {
          System.out.println(field.getName() + " = " + field.get(this));
        } catch (IllegalArgumentException | IllegalAccessException e) {
          throw new RuntimeException("Reflection problem", e);
        }
      }
    }
  }
}

Class with annotated member fields:

package de.scrum_master.app;

import static de.scrum_master.app.FieldHelper.*;

public class B {
  @IgnoreFields(fieldNames = { "optionalText", "optionalNumber" })
  A noOptionalsA = new A();

  @IgnoreFields(fieldNames = { "text", "number", "date" })
  A onlyOptionalsA = new A();

  public static void main(String[] args) {
    B b = new B();
    b.noOptionalsA.doSomething(extractIgnoredFieldsList(b.getClass(), "noOptionalsA"));
    System.out.println("----------------------------------------");
    b.onlyOptionalsA.doSomething(extractIgnoredFieldsList(b.getClass(), "onlyOptionalsA"));
  }
}

Console log:

number = 11
text = Hi there!
date = Wed Dec 27 18:54:44 ICT 2017
----------------------------------------
optionalText = I am not really always needed
optionalNumber = 123

If you do not understand what is happening here or if you still insist in an AspectJ solution, please let me know and I will explain and/or provide extra aspect code.

Question:

I have the following aspect hadling all REST controllers:

@Pointcut(value="execution(* com.company.app.features.*.controller.*.*(..))")
public void controller() { }

@Before("controller()")
public void before(JoinPoint jp) {
    // Log
}

That works fine on all methods in the package defined in @Pointcut as required.

However when I try to point the @Before out to the methods annoted only with @GetMapping(..), the URL is resulting 404 error, however another ones work as usually.

What do I do wrong? Noone of my attempts are working:

  • Amended only @Before: @Before("method() && @annotation(GetMapping)")
  • Amended only @Pointcut: @Pointcut(value="execution(@GetMapping com.company...
  • Amended only @Pointcut: @Pointcut(value="execution(@GetMapping * com.company...

The same result (error 404) is when I implement an interface over the controller class, @Override a method annoted with @GetMapping and place this method from the interface to the @Pointcut as the first piece of code says. I suggest there is a similar thing behind. Would someone explain me?


Answer:

@Pointcut(value="execution(* com.company.app.features.*.controller.*.*(..))")
public void controller() { }

@Pointcut(value="execution(@within(org.springframework......GetMapping)")
public void getMapping() { }


@Before("controller() && getMapping(object)")
public void controllerGetMapping(Object objectIfYouNeedIt) {
    // Log
}

Question:

I'm learning Spring AOP, and decided to use it for some performance monitoring on a batch job. I want to monitor the execution times of a jdbctemplate object's .update() method within a Spring Batch ItemWriter's write() method.

The relevant parts of my pom.xml:

  <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.5.4</version>
    </dependency>
    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib-nodep</artifactId>
        <version>3.2.5</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>3.1.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.3.9.RELEASE</version>
    </dependency>

My spring configuration XML file:

<aop:config>
    <aop:pointcut id="writerMethods" expression="execution(* my.package.name.writers.IvrWriter.write())"/>
    <aop:advisor advice-ref="performanceMonitor" pointcut-ref="writerMethods" order="2"/>
</aop:config>

However, I'm receiving a NoSuchMethodError that I'm having some trouble understanding how to debug:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Initialization of bean failed; nested exception is java.lang.NoSuchMethodError: org.springframework.beans.factory.config.ConfigurableBeanFactory.getSingletonMutex()Ljava/lang/Object;
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:92)
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:102)
    at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(AspectJAwareAdvisorAutoProxyCreator.java:103)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessBeforeInstantiation(AbstractAutoProxyCreator.java:248)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:880)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:852)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:446)
    ... 15 more
Caused by: java.lang.NoSuchMethodError: org.springframework.beans.factory.config.ConfigurableBeanFactory.getSingletonMutex()Ljava/lang/Object;
    at org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor.resetAdviceMonitor(AbstractBeanFactoryPointcutAdvisor.java:81)
    at org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor.setBeanFactory(AbstractBeanFactoryPointcutAdvisor.java:76)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1475)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1443)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
    ... 27 more

I'm not even sure whether or not this is a dependency issue with Spring AOP, a syntax error in terms of how I am writing the pointcut expression, or something else. I have followed a tutorial accessedenter link description here here on how to write pointcut expressions. Can anyone direct me in the right direction?


Answer:

from exception stacktrace:

NoSuchMethodError: org.springframework.beans.factory.config.ConfigurableBeanFactory.getSingletonMutex()Ljava/lang/Object;

you should update in your pom.xml version for for spring aop afticat to version : 4.3.9.RELEASE . You use two different version for spting artifacts spring-aspects with 3.1.2.RELEASE and spring-aop with 4.3.9.RELEASE they are not compatible

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>4.3.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>4.3.9.RELEASE</version>
    </dependency>

better use properties variable in pom.xml

<properties>
     <spring.version>4.3.4.RELEASE</spring.version>
</properties>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

Question:

This is the code in question.

@Aspect
@EnableAspectJAutoProxy
public class TransactionAspect extends TransactionSynchronizationAdapter {
   public TransactionMonitor transactionMonitor;    
   String message;

 @Before("execution(@org.springframework.transaction.annotation.Transactional * *.*(..)) && args(message,..))")
public void registerTransactionSynchronization(String message) {
    TransactionSynchronizationManager.registerSynchronization(this);
    this.message = message;
}

    public void setTransactionMonitor(TransactionMonitor transactionMonitor) {
    this.transactionMonitor = transactionMonitor;
}

I have created this Aspect bean in my spring config file.

I originally had this in the @Before block @Before("@annotation(org.springframework.transaction.annotation.Transactional)")

This worked. The places where I have the Transactional annotation would call this Pointcut. However I also need variables from the method that I and putting this aspect on. That's where the args(message) comes in. I have tried several different ways of retrieving that message (which is a String) but to no avail.

Would anyone know how I could craft this Pointcut to hit on the Transactional Annotation as well as pull in a variable from the method that I have annotated with Transactional? Thank you kindly.


Answer:

You can try to use the JoinPoint to get its arguments[1]:

@Before("@annotation(annotation)")
public void registerTransactionSynchronization(final JoinPoint jp, final Transactional annotation) {

    // These are the method parameters, yours would be at parameters[0], but check first... ;)
    final Object[] parameters = jp.getArgs(); 

    // Your stuff here       
}

Using "args(message,...)" in the JP definition probably works as well, but IIRC the first parameter needs to be the JoinPoint itself. So it might be enough to just add that to the method signature.

[1] http://www.eclipse.org/aspectj/doc/released/runtime-api/org/aspectj/lang/JoinPoint.html#getArgs()

Question:

I want to intercept all assignments to a field which is annotated with MyAnnotation in this case. If it works when the value is assigned with reflction is much better. This is what I tried, but it does not run, and I think that something else might be wrong:

public privileged aspect MyAnnotationAspect {

    pointcut hasAnnotation(MyAnnotation annotation) : @annotation(annotation);

    pointcut methodExecution() : execution(* *(..));

    Object around(MyAnnotation annotation) : set(String word) && methodExecution() && hasAnnotation(annotation) {
        Object result = null;
        try {
            result = proceed(annotation, "new"); //Just to try I want to assign "new" instead of the variable word
        } catch (Throwable ex) {
            throw new RuntimeException(ex);
        }
        return result;
    }

}

It says that are too many arguments for the method proceed. Can anyone help me? Thank you!

EDIT

Now it throws "Warning:(10, 0) ajc: advice defined in aspects.AnnotationAspect has not been applied [Xlint:adviceDidNotMatch]"

This is my aspect:

public aspect AnnotationAspect {

    pointcut hasAnnotation(Annotation annotation) : @annotation(annotation);

    Object around(Annotation annotation, String word) : hasAnnotation(annotation) && set(String *) && args(word) {
        Object result = null;
        System.out.println(thisJoinPoint);
        try {
            result = proceed(annotation, "intercepted");
        } catch (RuntimeException ex) {
            throw ex;
        }
        return result;
    }
}

This is the annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Annotation {
}

I have a dummy in order to test it:

class DummyEntity{

  @Annotation
  var name: String =_

  def setName(n: String): Unit ={
    name = n
  }
}

And this is the test where I'm testing it:

public class AnnotationAspectTest {

    private DummyEntity dummyEntity;

    @Before
    public void setUp(){
        dummyEntity = new DummyEntity();
    }

    @Test
    publ