Hot questions for Spring Framework's version of AOP

Top 10 Java Open Source / Spring / Spring Framework's version of AOP

Question:

I have below annotation.

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

}
SomeAspect.java
public class SomeAspect{

 @Around("execution(public * *(..)) && @annotation(com.mycompany.MyAnnotation)")
    public Object procede(ProceedingJoinPoint call) throws Throwable {

  //Some logic

}

}
SomeOther.java
public class SomeOther{

@MyAnnotation("ABC") 
public String someMethod(String name){


}


}

In above class am passing "ABC" with in @MyAnnotation. Now how can i access "ABC" value in procede method of SomeAspect.java class?

Thanks!


Answer:

You can get the Signature from a ProceedingJoinPoint and in case of a method invocation just cast it to a MethodSignature.

@Around("execution(public * *(..)) && @annotation(com.mycompany.MyAnnotation)")
public Object procede(ProceedingJoinPoint call) throws Throwable {
    MethodSignature signature = (MethodSignature) call.getSignature();
    Method method = signature.getMethod();

    MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
}

But you should first add an annotation attribute. Your example code doesn't have one, e.g.

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

    String value();
}

Then you can access it

MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
String value = myAnnotation.value();

EDIT

How to get value if I have @MyAnnotation("ABC") at class level ?

A Class is also an AnnotatedElement, so you can get it the same way as from a Method. E.g. An annotation of the method's declaring class can be obtained using

 Method method = ...;
 Class<?> declaringClass = method.getDeclaringClass();
 MyAnnotation myAnnotation = declaringClass.getAnnotation(MyAnnotation.class)

Since you are using spring you might also want to use spring's AnnotationUtils.findAnnotation(..). It searches for an annotation as spring does. E.g. also looking at superclass and interface methods, etc.

 MyAnnotation foundAnnotation = AnnotationUtils.findAnnotation(method, MyAnnotation.class);

Question:

The question is short and simple: Is there a way to get the Method object from an apsectj ProceedingJoinPoint?

Currently I am doing

Class[] parameterTypes = new Class[joinPoint.getArgs().length];
Object[] args = joinPoint.getArgs();
for(int i=0; i<args.length; i++) {
    if(args[i] != null) {
        parameterTypes[i] = args[i].getClass();
    }
    else {
        parameterTypes[i] = null;
    }
}

String methodName = joinPoint.getSignature().getName();
Method method = joinPoint.getSignature()
    .getDeclaringType().getMethod(methodName, parameterTypes);

but I don't think this is the way to go ...


Answer:

Your method is not wrong, but there's a better one. You have to cast to MethodSignature

MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();

Question:

I am moving from an xml config to annoations. i want to convert a session scoped bean that is

<aop:scoped-proxy>

can this be done with annotations, and if not, what can i do to still keep that declaration working?

edit: I am interested in doing this in Spring 2.5


Answer:

In Spring 3.0 it can be specified by the proxyMode attribute of @Scope annotation:

@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)

Question:

I have the following spring configuration:

<context:component-scan base-package="uk.co.mysite.googlecontactsync.aop"/>

<bean name="simpleEmailSender" class="uk.co.mysite.util.email.simple.SimpleEmailSenderImplementation"/>

<aop:aspectj-autoproxy/>

Then I have an aspect:

@Aspect
public class SyncLoggingAspect {
    @Autowired
    private SimpleEmailSender simpleEmailSender

    @AfterReturning(value="execution(* uk.co.mysite.datasync.polling.Poller+.doPoll())", returning="pusher")
    public void afterPoll(Pusher pusher) {      
        simpleEmailSender.send(new PusherEmail(pusher));
    }
}

This aspect works (I can hit a breakpoint on afterPoll) but simpleEmailSender is null. Unfortunately I cannot find clear documentation on why this is. (For the record, my simpleEmailSender bean exists and is correctly wired into other classes) The following things confuse me:

  1. Is context:component-scan supposed to be picking up @Aspect? If it is then surely it would be a spring managed bean, thus autowired should work?
  2. If context:component-scan isn't for creating aspects, how is my aspect being created? I thought aop:aspectj-autoproxy just creates a beanPostProcessor to proxy my @Aspect class? How would it do this if it isn't a spring managed bean?

Obviously you can tell I don't have an understanding of how things should be working from the ground up.


Answer:

The aspect is a singleton object and is created outside the Spring container. A solution with XML configuration is to use Spring's factory method to retrieve the aspect.

<bean id="syncLoggingAspect" class="uk.co.demo.SyncLoggingAspect" 
     factory-method="aspectOf" />

With this configuration the aspect will be treated as any other Spring bean and the autowiring will work as normal.

You have to use the factory-method also on Enum objects and other objects without a constructor or objects that are created outside the Spring container.

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 am trying to define a pointcut, that would catch every method that is annotated with (i.e.) @CatchThis. This is my own annotation.

Moreover, I'd like to have access to the first argument of the method, which will be of Long type. There may be other arguments too, but I don't care about them.


EDIT

This is what I have right now. What I don't know is how to pass the first parameter of the method annotated with @CatchThis.

@Aspect 
public class MyAspect {
    @Pointcut(value = "execution(public * *(..))")
    public void anyPublicMethod() {
    }

    @Around("anyPublicMethod() && @annotation(catchThis)")
    public Object logAction(ProceedingJoinPoint pjp, CatchThis catchThis) throws Throwable {
        return pjp.proceed();
    }
}

Answer:

Something like this should do:

@Aspect
public class MyAspect{

    @Pointcut(value="execution(public * *(..))")
    public void anyPublicMethod() {
    }

    @Around("anyPublicMethod() && @annotation(catchThis) && args(.., Long ,..)")
    public Object logAction(
        ProceedingJoinPoint pjp, CatchThis catchThis, Long long)
        throws Throwable {

        return pjp.proceed();
    }
}

Question:

Can any one tell me what is the difference between Joinpoint and Proceedingjoinpoint ?

When to use Joinpoint and Proceedingjoinpoint in the method of aspect class ?

I used the JoinPoint in my AspectJ class like ,

@Pointcut("execution(* com.pointel.aop.test1.AopTest.beforeAspect(..))")  
public void adviceChild(){}  

@Before("adviceChild()")  
public void beforeAdvicing(JoinPoint joinPoint /*,ProceedingJoinPoint pjp - used refer book marks of AOP*/){ 

    //Used to get the parameters of the method !
    Object[] arguments = joinPoint.getArgs();
    for (Object object : arguments) {
        System.out.println("List of parameters : " + object);
    }

    System.out.println("Method name : " + joinPoint.getSignature().getName());
    log.info("beforeAdvicing...........****************...........");
    log.info("Method name : " + joinPoint.getSignature().getName());
    System.out.println("************************"); 
}

But some what I see in other resources is ,

@Around("execution(* com.mumz.test.spring.aop.BookShelf.addBook(..))")
public void aroundAddAdvice(ProceedingJoinPoint pjp){
    Object[] arguments = pjp.getArgs();
    for (Object object : arguments) {
        System.out.println("Book being added is : " + object);
    }
    try {
        pjp.proceed();
    } catch (Throwable e) {
        e.printStackTrace();
    }
} 

Here what the ProceedingJoinPoint will do special compare to 'JointPoint` ?

Also what pjp.proceed() will do for us ?


Answer:

An around advice is a special advice that can control when and if a method (or other join point) is executed. This is true for around advices only, so they require an argument of type ProceedingJoinPoint, whereas other advices just use a plain JoinPoint. A sample use case is to cache return values:

private SomeCache cache;

@Around("some.signature.pattern.*(*)")
public Object cacheMethodReturn(ProceedingJoinPoint pjp){
    Object cached = cache.get(pjp.getArgs());
    if(cached != null) return cached; // method is never executed at all
    else{
        Object result = pjp.proceed();
        cache.put(pjp.getArgs(), result);
        return result;
    }
}

In this code (using a non-existent cache technology to illustrate a point) the actual method is only called if the cache doesn't return a result. This is the exact way the Spring EHCache Annotations project works, for example.

Another specialty of around advices is that they must have a return value, whereas other advice types must not have one.

Question:

I'm having trouble with a pointcut definition in Spring (version 2.5.6). I'm trying to intercept all method calls to a class, except for a given method (someMethod in the example below).

<aop:config>
    <aop:advisor
         pointcut="execution(* x.y.z.ClassName.*(..)) AND NOT
                   execution(* x.y.x.ClassName.someMethod(..))"
    />
</aop:config>

However, the interceptor is invoked for someMethod as well.

Then I tried this:

<aop:config>
    <aop:advisor
         pointcut="execution(* x.y.z.ClassName.(* AND NOT someMethod)(..)) )"
    />
</aop:config>

But this does not compile as it is not valid syntax (I get a BeanCreationException).

Can anybody give any tips?


Answer:

i know its probably a bit late at this stage but ive been having the same issue and I resolved it by escaping the ampersand chars so its &amp;&amp; ! instead of 'AND NOT' or '&& !'. I'm doing this in the xml file

<aop:config>
    <aop:pointcut id="blah" expression="execution(* com.disney.goofy..*.*(..)) &amp;&amp; !@annotation(com.disney.goofy.NonDisneyCharacter)"/>
    <aop:advisor advice-ref="transAdvice" pointcut-ref="blah"/>
</aop:config>

This applies the advice to all methods executed in com.disney.goofy and that are not annotated with NonDisneyCharacter

Question:

I ams using Spring 2.5.6, asm 1.5.3, aspectjrt/aspectjweaver 1.6.1, cglib 2.1_3 In my Web based Spring application I have following class:

package uk.co.txttools.aspects;

@Aspect
public class LoggingAspect {
    @Before("execution(* uk.co.txttools.web.controller.compose.PreviewMessageController.set*(..))")
    public void setLoggingAdvice(){
        System.out.println("********************************* Advice run..... set mothod called....");
    }

    @AfterThrowing("execution(* uk.co.txttools.web.controller.compose.PreviewMessageController.onSubmit(..) throws java.lang.Exception)")
    public void hadleException(){
       System.out.println("================= PreviewMessageController =========== ON SUBMIT Exception Throwen ==================");
    }

    @Before("execution(* uk.co.txttools.web.controller.compose.PreviewMessageController.onSubmit(..) throws java.lang.Exception)")
    public void OnSubmitAspect(){
        System.out.println("================= PreviewMessageController =========== ON SUBMIT CALLED ==================");
    }
}

I have one Controller:uk.co.txttools.web.controller.compose.PreviewMessageController which hasonSubmit()method, which get called from web page. I have separateapplicationContext.xml` file.

My springapp-servlet.xml(which is used in web.xml file with org.springframework.web.servlet.DispatcherServlet) file looks like this:

<?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:util="http://www.springframework.org/schema/util"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.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-2.5.xsd
            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd">

<aop:aspectj-autoproxy proxy-target-class="true" />

<bean id="loggingAspect" class="uk.co.txttools.aspects.LoggingAspect" />
.
.

Below in same xml file PreviewMessageController get initialize which means my Controller and Aspect live is same container.

I don't get any exception while running application but my aspect class LoggingAspect never get called. I'm not sure what is that missing or I'm doing wrong. Please help me..

Thanks


Answer:

I'm not sure if I did it properly but for me what solved it was adding @Component to the "Aspect'ed" class -

@Aspect
@Component
public class PerformanceLogger {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Around("within(com.something.rest.service..*)")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object retVal = pjp.proceed();
        long end = System.currentTimeMillis();
        logger.debug(pjp.getSignature().toShortString() + " Finish: " + (end - start) + "ms");
        return retVal;
    }
}

(And just to close the loop - if you are using annotation based, don't forget adding @EnableAspectJAutoProxy to your Config class.

@EnableAspectJAutoProxy

Question:

From Spring Documentation:

  • any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface:

    this(com.xyz.service.AccountService)
    
  • any join point (method execution only in Spring AOP) where the target object implements the AccountService interface:

    target(com.xyz.service.AccountService)
    

I don't understand what "target object" and the expression target(...) mean.

How is target different from this?


Answer:

this(AType) means all join points where this instanceof AType is true. So this means that in your case once the call reaches any method of AccountService this instanceof AccountService will be true.

target(AType) means all join points where anObject instanceof AType . If you are calling a method on an object and that object is an instanceof AccountService, that will be a valid joinpoint.

To summarize a different way - this(AType) is from a receivers perspective, and target(AType) is from a callers perspective.