user182944
user182944

Reputation: 8067

Spring AOP: Passing parameter in aspect method

I am new to Spring AOP and trying to create a demo using aop:around.

A simple bean class:

public class Employee {

private String name;
public String getName() {
    System.out.println("Name: " + name);
    return name;
}
public void setName(String name) {
    this.name = name;
}
}

Aspect implementation:

public class PrintingAspect {

public void performPrinting(ProceedingJoinPoint point){
    try {
        System.out.println("Before Printing!!!");
        point.proceed();        
        System.out.println("After Printing!!!");
    } catch (Throwable e) {         
        System.out.println("Exception Printing");
    }
}
}

Context XML:

<bean id="aspect" class="com.aop.aspect.PrintingAspect">        
</bean>    
<bean id="employee" class="com.aop.model.Employee">
    <property name="name" value="XXX"></property>
</bean>
<aop:config>
    <aop:pointcut id="empName" expression="execution(* com.aop.model.Employee.getName(..))"/>
    <aop:aspect ref="aspect">            
        <aop:around pointcut-ref="empName" method="performPrinting"/>
    </aop:aspect>
</aop:config>

App.java

public class App 
{
public static void main( String[] args )
{
    ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
    Employee empl = (Employee)context.getBean("employee");
    System.out.println("Employee Names: " + empl.getName());
}
}

The o/p I am getting is:

Before Printing!!! Name: XXX After Printing!!! Employee Names: null

Why is the last one null ?

Upvotes: 0

Views: 7629

Answers (3)

roj
roj

Reputation: 1373

@user182944, although you may have solved this long ago, I'm answering it because it may help others hitting the same issue!

Because your Aspect returns void (i.e. nothing), then any method you apply it to will return null.

With your current code, when you execute getName(), the Aspect kicks in and executes getName() but then throws away the result since your Aspect returns void, leaving your calling code with a null to deal with. To ensure that the method you annotate returns the value you expect it to, you need your Aspect to return the object that's returned by it - i.e. by the .proceed() call.

In this case we know your method returns a String, so we could define the Aspect as returning a String. However, since we don't necessarily always know in advance what kind of object will be returned by the annotated method, the simplest solution is to declare your annotation with the return type Object.

So, to fix this, simply make your Aspect return the object returned by the annotated method, similar to @Rahul Jain's incomplete snippet), like this:

public class PrintingAspect {

  public Object performPrinting(ProceedingJoinPoint point){
    Object returnValue = null;
    try {
        System.out.println("Before Printing!!!");
        returnValue = point.proceed();        
        System.out.println("After Printing!!!");
    } catch (Throwable e) {         
        System.out.println("Exception Printing");
    }
    return returnValue;
  }
}

Now that we have an Aspect that returns the annotated method's response, we can execute our getName() method and our Aspect will kick in and then return the String that getName() returned, as you expected.

Hope this helps explain what's going on!

Upvotes: 0

Rahul Jain
Rahul Jain

Reputation: 115

Point.proceed() in the below code is responsible for actual exceution of the code and as your are using around advice you should capture the return value and return in the below method. As you are return nothing in the below method Its coming as null.

Please let me know if it doesn't work.I haven't tested It But It will Work.

public void performPrinting(ProceedingJoinPoint point){
    try {
        System.out.println("Before Printing!!!");
        Object returnValue = point.proceed();        
        System.out.println("After Printing!!!");
    } catch (Throwable e) {         
        System.out.println("Exception Printing");
    }
return returnValue;
}

Upvotes: 1

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 279920

One way to do it is with these changes:

XML:

<aop:pointcut id="empName"
        expression="execution(* com.example.Employee.getName(..))" />

Java:

public void performPrinting(ProceedingJoinPoint jp) { // Here empl is coming null
    System.out.println("Before Printing!!!");
    System.out.println(((Employee)jp.getTarget()).getName()); // empl is coming as NULL
    System.out.println("After Printing!!!");
}

In other words, you get access to the target which is the object that is being proxied for the AOP advice to be applied.

Upvotes: 1

Related Questions