How to write a pointcut to get an operation on a class method? - spring

I have a class named PersonDAOImpl, where I use Hibernate to persist data on my data base.
In order to audit the class, I created another class using the #Aspect annotation, where I declared some Pointcuts and Advices. Everytime I insert, update or delete a person, I'm able to store on a table proper information about the operation executed.
However now I have more DAO classes, and I don't want to create more Aspects classes or more Advices for every method on every DAO. Instead, I want to "capture" the operations of persist(), update() or delete() in a single pointcut.
For example I have this method on my DAO:
#Override
#Transactional
public void addPerson(Person p) {
Session session = this.sessionFactory.getCurrentSession();
session.persist(p);
session.flush();
logger.info("Person saved successfully, Person Details="+p);
}
And this is how I audit the insertions:
#Pointcut("execution(* com.dacasals.raspertwo.dao.PersonDAOImpl.addPerson(..))")
public void addNewPerson() {
}
#After("addNewPerson()")
public void aP() {
System.out.println("added a new person");
operation = "Insert";
date = Calendar.getInstance().getTime();
register(operation, date);
}
But I want something like #Pointcut("execution(*com.dacasals.raspertwo.dao.anydaoclass.anymethod.persist(..))")
I mean a pointcut for any method on any of my DAO classes where persist() is called. Same thing for update() and delete().
How can I achieve this? I've tried with 'within' and 'withincode' but nothing happens. Thanks in advance.

Instead of execution expression you might want to use the within expression something like this.
within(com.yourpackage..*)
For this you will have to make sure that all your DAO's are within this package. The above expression will match all the methods defined in classes inside package com.yourpackage and classes sub-packages.
Here is a short doc if you would like to configure it some other way,
Pointcut Expressions in Spring

I would use the 'AroundAdvice'.
Quote for documentation:
Around advice runs "around" a matched method execution. It has the opportunity to do work both before and after the method executes, and to determine when, how, and even if, the method actually gets to execute at all.
Around Advice Spring documentation
So, in your example, you would have a method:
#Around("com.dacasals.raspertwo.dao.*.persist(..)")
public Object doSomething(ProceedingJoinPoint pjp) throws Throwable {
}
This way every time someone on 'com.dacasals.raspertwo.dao' calls persist method, Spring Aspect will invoke doSomething method. Around advice works both before and after the method executes, so you should take care to don't do the same thing twice.
I would create a specific method for every operation (one for insert, another for update and delete) but you could use the same method using short-circuit operators. That way, your #Around annotation would be like:
#Around("com.dacasals.raspertwo.dao.*.persist(..) || com.dacasals.raspertwo.dao.*.update(..) || com.dacasals.raspertwo.dao.*.delete(..)")
public Object doSomething(ProceedingJoinPoint pjp) throws Throwable {
}

Related

#Async is not working if I give it at service level in spring-boot

I am autowiring service in controller. And in service, I have a scenario where I need to throw an exception and DB changes also. So, I tried #Async
#Transactional
public void verifyOtp(OtpDto otpDto)
...
if(xyz){
deactivateOtp(emp.getId());
throw new ServException("Mobile no requested is already assigned", "error-code");
}
}
#Async
#Transactional //with or without
public void deactivateOtp(Integer id){
otpRepo.deactivateOtp(id);
}
public interface OtpRepository extends JpaRepository<Otp, Integer> {
#Modifying
#Query("UPDATE Otp SET isActive = 0 WHERE id = :id")
public void deactiveOtp(#Param("id") Integer id);
This is not creating new thread. But, if I gives at repo, it works
public void deactivateOtp(Integer id){
otpRepo.deactivateOtp(id);
}
public interface OtpRepository extends JpaRepository<Otp, Integer> {
#Async
#Transactional
#Modifying
#Query("UPDATE Otp SET isActive = 0 WHERE id = :id")
public void deactiveOtp(#Param("id") Integer id);
First of all check that the service is wrapped into proxy (you can place a breakpoint in controller and see the reference to the service, it will be with proxy). Otherwise there is something wrong with the configuration and #Transactional/#Async won't work till you fix that.
Now, assuming this is not an issue, there is an issue in the code:
When the controller calls service.verifyOtp it goes to the proxy (to handle the transaction) and then to your implementation.
But when it reaches your implementation and you call the method that belongs to the same impl, it doesn't pass through the proxy again, instead it directly goes to the deactivateOtp as if there is no spring at all here. Of course, #Async doesn't work.
In terms of resolution:
Consider using self injection if you work with spring 4.3+. Read this thread for more information.
Alternatively, refactor your code so that the deactivateOtp will be a public method of another class. In this case the call won't be "internal" anymore, it will path through Proxy hence the #Async will work.
This is discussed many times.
Basically, Spring AOP will not intercept local method call
(in your case call deactivateOtp() within the same class)
You can read more about this behavior here: Understanding AOP proxies
Highlight:
The key thing to understand here is that the client code inside the main(..) of the Main class has a reference to the proxy. This means that method calls on that object reference will be calls on the proxy, and as such the proxy will be able to delegate to all of the interceptors (advice) that are relevant to that particular method call. However, once the call has finally reached the target object, the SimplePojo reference in this case, any method calls that it may make on itself, such as this.bar() or this.foo(), are going to be invoked against the this reference, and not the proxy. This has important implications. It means that self-invocation is not going to result in the advice associated with a method invocation getting a chance to execute.

#transactional in spring jpa not updating table

I am using spring jpa transactions in my project.One Case includes inserting a data in a synchronized method and when another thread accesses it the data is not updated.My code is given below :
public UpdatedDTO parentMethod(){
private UpdatedDTO updatedDTO = getSomeMethod();
childmethod1(inputVal);
return updatedDTO;
}
#Transactional
public synchronized childmethod1(inputVal){
//SomeCodes
//Place where update takes place
TableEntityObject obj = objectRepository.findByInputVal(inputVal);
if(obj == null){
childMethod2(inputVal);
}
}
#Transactional
public void childMethod2(inputVal){
//Code for inserting
TableEntityObject obj = new TableEntityObject();
obj.setName("SomeValue");
obj.setValueSet(inputVal);
objectRepository.save(obj);
}
Now if two threads access at the same time and if first thread completes childmethod2 and childmethod1 and without completing parentMethod() after that if second thread comes to the childMethod1() and checks if data exists,the data is null and is not updated by first thread.I have tried many ways like
#Transactional(propagation = Propagation.REQUIRES_NEW)
public synchronized childmethod1(inputVal){
//SomeCodes
//Place where update takes place
TableEntityObject obj = objectRepository.findByInputVal(inputVal);
if(obj == null){
childMethod2(inputVal);
}
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void childMethod2(inputVal){
//Code for inserting
TableEntityObject obj = new TableEntityObject();
obj.setName("SomeValue");
obj.setValueSet(inputVal);
objectRepository.save(obj);
}
also tried taking off #transactional in the childMethod1() but nothing works out.I know im doing something wrong here , but couldnt figure out where and what exactly i am doing wrong.Can anyone help me out with this
#Transactional is resolved using proxies on spring beans. It means it will have no effect if your method with #Transactional is called from the same class. Take a look at Spring #Transaction method call by the method within the same class, does not work?
The easiest would be moving those methods into separate service.
Typical checklist I follow in cases like these :
If Java based configuration then make sure
#EnableTransactionManagement annocation is present in the class
containing the #Configuration annotation
Make sure the transactionManager bean is created, again this should be mentioned in the configuration class.
Use of #Transactional annocatio over the method which is calling the repository, typically a class in the DAO layer
Adding the #Service annotation for the class which is invoking the methods in the repository
Nice blog which explains the Transaction configuration with JPA in depth --> http://www.baeldung.com/2011/12/26/transaction-configuration-with-jpa-and-spring-3-1/68954

Spring, AOP - how to define the aspect after Hibernate DAO transaction closes

My project is Web app with Spring and Hibernate. I need to perform some routine operation on the data returned by my DAO layer and transaction is committed and session is closed. I try to use aspects with annotations like this:
#AfterReturning(pointcut = "execution(* com.dao..*.*(..))", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result){
processResult(result);
}
or using
#Around("execution(* com.dao..*.*(..))")
but in either event I got Hibernate exceptions like this:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
Off course everything works if I just apply that same operation in my service:
public void serviceMethod(Object param) {
Object result = dao.getObject(param);
processResult(result);
}
'Cause I need to use processResult against every DAO method's result I am reluctant to use the latter approach and would be grateful for some advice on how to use either aspects or some other alternative way on doing so....

Using EJB interceptors after a method call

I know one can use interceptors before a method call by using the #AroundInvoke annotation.
What I would like to do is execute certain code after the method call, so that I can for example create a log entry before and after a method execution.
Is this possible with EJB3, or do I need to use AOP?
#AroundInvoke interceptor is passed InvocationContext, and proceed() must be called to advance the method. Thus:
#AroundInvoke
public Object log(InvocationContext ic) throws Exception {
logEntry();
try {
return ic.proceed();
} finally {
logExit();
}
}
Depending on your needs, you could also log the return value or exceptions, filter the methods being logged, etc.

Using Aspect to annotate methods with #InsightOperation for Spring Insight

I wanted to instrument a large number of classes to use with Spring Insight and instead of adding the #InsightOperation manually to the methods, I wrote an aspect to annotate the methods using point cuts.
However, this is not working. While the manual annotation affects the Spring Insight trace logging, the AspectJ method does not work.
Is there anything I am doing wrong here? (I decompiled the classes after aspectizing and do find the annotation in the class methods)
This is the aspect code snippet:
declare #method :public * com.example.IExample.execute(..) : #InsightOperation;
Spring documentation says this:
Use of the #Insight* annotations are
optional. They make it easy for end
users to define custom operation
frames and end points without needing
to create a plug-in. Because end user
code modification is required to use
the annotations, they are an option
for users who cannot or do not wish to
write aspects.
http://static.springsource.com/projects/tc-server/2.5/devedition/htmlsingle/devedition.html
So looks like the only way is to write a custom plugin
http://static.springsource.com/projects/tc-server/2.5/devedition/htmlsingle/devedition.html#tutorial-plugin
It is possible that the Insight LTW does not pick up your introduced annotations. I'll have to dig deeper on that.
In the meantime, you can try a more low-level annotation:
com.springsource.insight.collection.method.MethodOperationsCollected
If you look at the spring-core plugin, you will see that it does something similar:
public aspect RepositoryMethodOperationCollectionAspect {
declare #type: #Repository * : #MethodOperationsCollected;
}
An easy work around is to call another method from within your aspect method to continue executing the join point. I only tried calling a static method in a static class. See below my code for adding the #InsightOperation to all my JSON serialization.
My aspect:
#Aspect
public class JSONSerializerAspect {
#Around("call(* *.JSONSerializer.serialize(..)) && args(target)")
public Object serialize(ProceedingJoinPoint joinPoint, Object target) throws Throwable {
return JSONSerializationWrapper.serialize(joinPoint, target);
}
}
The static class it is calling:
public class JSONSerializationWrapper {
#InsightOperation(label = "JSON_SERIALIZATION")
public static Object serialize(ProceedingJoinPoint joinPoint, Object target) throws Throwable {
return joinPoint.proceed(new Object[]{target});
}
}
I'm using this myself and tested that it works.

Resources