Monday, March 23, 2015

Spring Aspect Oriented Programming , AOP - writting custom Annotation

Basic Scenario
This is to describe on How to write a simple annotation.
I am writing custom annotation with name "Loggable" and I will use it with the "myArroundAdvice" which is Advice with type "Around" written in the LoginAspect.java

basic code for project is described in
http://cgenit.blogspot.com/2015/03/aop-basic-application-code-and.html

Let's write custom annotation.
If you using eclipse , you can select annotation and give name "Loggable" and it will create Loggable custom annotation.
Else simply you can create a class with name "Loggable" , and put "@interface" before name "Loggable"  as shown in below code

package I have used is same package "org.aop.aspect".  You can have your own package.

So we have defined custom annotation. Then how to use it.
So in the advice , give the path to custom annotation, in the place where you give the poincut.

----------------------------------------------------------------------------------------

@Around("@annotation(org.aop.aspect.Loggable)")
public Object myArroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
// advice code here
}

----------------------------------------------------------------------------------------

put the annotation in the place you need to do the Logging or execute advice.
Here we are going to add the Logging to "getCircle" method in the ShapeService object
So we add the annotation above the "getCircle" method as shown in below

-----------------------------------------------------------------------------------
@Loggable
public Circle getCircle() {

return circle;
}
-----------------------------------------------------------------------------------

Once you run the project . you will get below output.

Output - custom annotation
=================================================
Circle set name =Circle name
Before advice.
After Returning.
After Finally.
Circle set name =dummy name
====================================================

Final coding as below


Loggable .java
----------------------------------------------------------------------------------------
package org.aop.aspect;

public @interface Loggable {


}

----------------------------------------------------------------------------------------

Below is the new Advice. You may have some unused imports, that's cause i have ommited some codes to ease of explanation. Don't worry about that. Just remove those.

LoginAspect .java
----------------------------------------------------------------------------------------
package org.aop.aspect;

import org.aop.model.Circle;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

@Aspect

public class LoginAspect {
@Around("@annotation(org.aop.aspect.Loggable)")
public Object myArroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
Object returnValue = null;
try {
System.out.println("Before advice.");
returnValue = proceedingJoinPoint.proceed();
System.out.println("After Returning.");
} catch (Throwable e) {
System.out.println("After Throwing.");
}

System.out.println("After Finally.");
return returnValue;

}
}
----------------------------------------------------------------------------------------

ShapeService .java
----------------------------------------------------------------------------------------
package org.aop.service;

import org.aop.aspect.Loggable;
import org.aop.model.Circle;
import org.aop.model.Triangle;

public class ShapeService {

private Circle circle;
private Triangle triangle;

@Loggable
public Circle getCircle() {
// circle = null;
// circle.getName();
return circle;
}

public void setCircle(Circle circle) {
this.circle = circle;
}

public Triangle getTriangle() {
return triangle;
}

public void setTriangle(Triangle triangle) {
this.triangle = triangle;
}

}
----------------------------------------------------------------------------------------

AppMain .java
----------------------------------------------------------------------------------------

package org.aop.main;

import org.aop.service.ShapeService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppMain {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"spring.xml");

// you need to cast if not use second parameter ShapeService.class
ShapeService shapeService = ctx.getBean("shapeService",
ShapeService.class);


shapeService.getCircle().setName("dummy name");
}

}


----------------------------------------------------------------------------------------


You can check the exception also.
To get a exception and check what;s happen when an exception , just remove commented two lines in the "getCircle" method in the ShaepService.java
This will make null pointer exception

------------------------------------------------------------------------------------
@Loggable
public Circle getCircle() {
circle = null;
circle.getName();
return circle;
}
------------------------------------------------------------------------------------


Output - custom annotation with Nullpointer exception
=================================================
Circle set name =Circle name
Before advice.
After Throwing.
After Finally.
Exception in thread "main" java.lang.NullPointerException
at org.aop.main.AppMain.main(AppMain.java:18)
====================================================

You can see that in output Line number 3 , it's printing  After Throwing. .

If you need to see the what's happening with the ProceedingJoinPoint , you can print that just using sysout.

so if you add a sysout to advice . It's highlighted in the below code inside advice.

LoginAspect .java
------------------------------------------------------------------------------------

package org.aop.aspect;

import org.aop.model.Circle;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class LoginAspect {


@Around("@annotation(org.aop.aspect.Loggable)")
public Object myArroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
Object returnValue = null;
try {
System.out.println("Before advice.");
System.out.println(proceedingJoinPoint);
returnValue = proceedingJoinPoint.proceed();
System.out.println("After Returning.");
} catch (Throwable e) {
System.out.println("After Throwing.");
}

System.out.println("After Finally.");
return returnValue;
}


}

------------------------------------------------------------------------------------


So the new output will be

Output - custom annotation with Nullpointer exception and with sysout proceedingJoinPoint
=================================================
Circle set name =Circle name
Before advice.
execution(Circle org.aop.service.ShapeService.getCircle())
After Throwing.
After Finally.
Exception in thread "main" java.lang.NullPointerException
at org.aop.main.AppMain.main(AppMain.java:18)

====================================================

you can see it's printing the joinpoint of the execution, where we have applied our custom annotation.
I have highlighted in  the output.
execution(Circle org.aop.service.ShapeService.getCircle())

Also you can see what happens if you remove the "proceedingJoinPoint.proceed();" from the advice. So let's comment that line and see what will happen.

So new Advice will look like below

LoginAspect .java  Note: proceedingJoinPoint.proceed();  is commented.
-----------------------------------------------------------------------------------------------
package org.aop.aspect;

import org.aop.model.Circle;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class LoginAspect {


@Around("@annotation(org.aop.aspect.Loggable)")
public Object myArroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
Object returnValue = null;
try {
System.out.println("Before advice.");
// System.out.println(proceedingJoinPoint);
// returnValue = proceedingJoinPoint.proceed();
System.out.println("After Returning.");
} catch (Throwable e) {
System.out.println("After Throwing.");
}

System.out.println("After Finally.");
return returnValue;
}



}


------------------------------------------------------------------------------------------------

Output - commenting "proceedingJoinPoint.proceed();"
=================================================
Circle set name =Circle name
Before advice.
After Returning.
After Finally.
Exception in thread "main" java.lang.NullPointerException
at org.aop.main.AppMain.main(AppMain.java:18)

====================================================

Note : you are getting a NullPointerException.


No comments:

Post a Comment