Spring + AspectJ pointcut on CrudRepository and Annotation - java

I have #Tenantable annotation to decide for pointCut :
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface Tenantable {
}
this my aspect :
#Slf4j
#Aspect
#Configuration
public class TenancyAspect {
#Pointcut("execution(public * *(..))")
public void publicMethod() {}
#Around("publicMethod() && #within(com.sam.example.aspect.aspectexample.model.Tenantable)")
public Object tenatable(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("my operations ...");
return joinPoint.proceed();
}
}
This is working without any problem for this service class :
#Tenantable
#Service
public class MyService(){
public void doSomething(){
...
}
}
my aspect is running when I call doSomething() method, It is ok but I want to implement aspect for CrudRepository interface that belongs spring data.
I have changed my Aspect to achieve this like below :
#Slf4j
#Aspect
#Configuration
public class TenancyAspect {
#Pointcut("execution(public * *(..))")
public void publicMethod() {}
#Pointcut("this(org.springframework.data.repository.Repository)")
public void repositoryExec(){}
#Around("publicMethod() && repositoryExec() && #within(com.sam.example.aspect.aspectexample.model.Tenantable)")
public Object tenatable(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("my operations ...");
return joinPoint.proceed();
}
}
this is repository :
#Tenantable
#Repository
public interface MyRepository extends CrudRepository{
}
But it doesn't work when I call any method inside of MyRepository.
Is there anyway to do this?
Edit :
It works for all repositories when I apply these :
#Pointcut("execution(public * org.springframework.data.repository.Repository+.*(..))")
and exclude this :
#within(com.sam.example.aspect.aspectexample.model.Tenantable)
But I need this anotation to apply it for specific repositories.

Having taken another look, I think I know what is going on here: You are assuming that just because you made your annotation #Inherited, it will be inherited by implementing classes if you annotate an interface. But this assumption is wrong. #Inherited only works in exactly one case: when extending an annotated base class. It does not work for annotated interfaces, methods etc. This is also documented here:
Note that this meta-annotation type has no effect if the annotated type is used to annotate anything other than a class. Note also that this meta-annotation only causes annotations to be inherited from superclasses; annotations on implemented interfaces have no effect.
As soon as you annotate your implementing class, it works.

Your repositoryExec pointcut should end with + to advice all subclass of Repository
#Pointcut("this(org.springframework.data.repository.Repository+)")

Related

Spring #Transactional method and class

I understand that #Transactional annotation in class affect all the method and #Transactional annotation in method only affect this method and override the class annotation.
But, this code makes sense?(no more methods in class)
#Service
#Transactional
public class Service extends AbstractCrudService<A,Repository> {
#Transactional(readOnly=true)
public Optional<A> getByApplicant(B b) {
return repository.findByB(b);
}
Is the same if put #Transactional annotation only in method?
#Service
public class Service extends AbstractCrudService<A,Repository> {
#Transactional(readOnly=true)
public Optional<A> getByApplicant(B b) {
return repository.findByB(b);
}
Both examples work the same way
#Transactional on the class set on all methodos with #Transactional, but if you put #Transactional o method, this replace the class annotation
The #Transactional annotation on the class level will be applied to every method in the class.
However, when a method is annotated with #Transactional (like, getByApplicant(B b)) this will take precedence over the transactional settings defined at the class level.
More about it:
http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/transaction.html

Exclude a specific method to be invoked by CDI Interceptor

I have an interceptor binding annotation :
#InterceptorBinding
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface MyBinding {
}
To this CDI interceptor :
#Interceptor
#MyBinding
public class MyInterceptor {
#AroundInvoke
public Object applyPolicy(InvocationContext ctx) throws Exception {
return blablabla;
}
}
And a class annotated, that mean every methods of this class will invoke MyInterceptor
#MyBinding
public class GlobalController {
public void methodA() {...}
public void methodB() {...}
}
All works fine, but I wish methodB not invoking my interceptor.
I tried both annotations #ExcludeClassInterceptors and #ExcludeDefaultInterceptors on my method but it doesn't works for me. I think these annotations are especially for exclude a method for EJB Interceptor, and not CDI Interceptor with Interceptor binding.
Not sure about these annotations but as a workaround you can add an annotation to the method you want to exclude. Get Method from InvocationContext in the interceptor and check whether the method has the annotation. In this case just delegate to the original method.
Try #MyBinding at method level:
public class GlobalController {
#MyBinding
public void methodA() {...}
public void methodB() {...}
}

AspectJ - Pointcut at specified method with a param annotated with class level annotation

In an aspect, i'd like stop at a specified method. This method has one parameter which is annotated with a class level annotation:
The annotation is:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface Auditable {}
The parameter is an object of a class annotated like:
#Auditable
public class User {}
The method I like to inspect:
public Object findSingleResultByExample(final Object entity) {}
This aspect is not working:
#AfterReturning(value="execution(* org.wtp.repository.GenericDao.find*(#org.wtp.aspects.Auditable (*)))",
argNames = "joinPoint, result",
returning = "result")
private void auditFindAnnotation(final JoinPoint joinPoint, final Object result) {}
First of all, your advice method must be public, not private. Please change that into
public void auditFindAnnotation(...)
It is not working because your pointcut intercepts methods with an #Auditable parameter annotation. Your sample method does not have such an annotation, though. It would work if the method signature was like this:
public Object findSingleResultByExample(final #Auditable Object entity) {}
BTW, then the #Target(ElementType.TYPE) restriction must be removed or extended in order for the code to still compile.
But I guess what you want is not to match on parameter annotations, but on type annotations. Then your pointcut would look like this (no parentheses around * this time):
execution(* org.wtp.repository.GenericDao.find*(#org.wtp.aspects.Auditable *))
But again, this does not match your sample method because its parameter type is not User or Auditable but just Object and the latter does not carry the annotation. You can see the difference if you overload your find* method and do something like this:
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface Auditable {}
package de.scrum_master.app;
#Auditable
public class User {}
package de.scrum_master.app;
import java.util.ArrayList;
public class Application {
public Object findSingleResultByExample(final Object entity) {
return entity;
}
public Object findSingleResultByExample(final User entity) {
return entity;
}
public static void main(String[] args) {
Application application = new Application();
application.findSingleResultByExample("foo");
application.findSingleResultByExample(new User());
application.findSingleResultByExample(new ArrayList<String>());
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class AuditAspect {
#AfterReturning(
value = "execution(* de.scrum_master.app..find*(#de.scrum_master.app.Auditable *))",
argNames = "thisJoinPoint, result",
returning = "result"
)
public void auditFindAnnotation(final JoinPoint thisJoinPoint, final Object result) {
System.out.println(thisJoinPoint + " -> " + result);
}
}
The console log then looks like this:
execution(Object de.scrum_master.app.Application.findSingleResultByExample(User)) -> de.scrum_master.app.User#4a574795
Update: In order to get the whole thing working without changing or overloading any method signatures, you would have to make your pointcut match all calls and dynamically determine the type and its annotations from withing the aspect via reflection (not so nice, but possible). Feel free to ask questions if you do not understand this idea.

Add constructor to AspectJ aspect with parameters

I have
#Aspect
public class MyAspect {
int x,y,z;
public MyAspect(int _x,int _y,int _z){
x=_x;
y=_y;
z=_z;
}
#After("execution(public * save(..))")
public void methodAfter(JoinPoint joinPoint) {
//code
}
after calling save method,it doesn't execute the methodAfter. However,without constructor,it works.How can I use aspectj with constructors?
I assume you are working in a spring environment, so what I suggest you'll do is:
Add #Component annotation to your aspect.
Use #Inject and #Value annotations to inject it with the required values for x,y,z.

Spring aspectj annotation pointcut

I was trying to create an Aspectj pointcut on method annotation but I failed all the time with different approaches. I'm using aspectj autoproxy (I have no other weaving configured in my spring context). My classes look like this:
public interface Intf
{
#SomeAnnotation
void method1() throws SomeExc;
}
public class Impl implements Intf
{
#Override
public void method1() throws SomeExc
{
//...
}
}
#Aspect
public class MyAspect
{
#AfterThrowing(
pointcut = "execution(* *(..)) && #annotation(SomeAnnotation)",
throwing = "error")
public void afterThrowing(JoinPoint jp, Throwable error)
{
System.err.println(error.getMessage());
}
}
#Component
public class Usage
{
#Autowired
Intf intf;
public void doStuff()
{
intf.method1();
}
}
So I'm wondering why the aspectj won't create the pointcut. I managed to make it work using execution(* *(..) throws SomeExc) which does the job for me but I still want to know what I did wrong.
Also since method1 is defined in an interface and I specify the annotation on implementing class, is there a way to make it work this way? Other proxying mechanisms like transaction management/security works this way in other parts of spring right? And if I'm using interface proxying would specifying the pointcut on implementing class create the pointcut? (I guess not since I'm not using cglib)
try to add #Component to MyAspect class
#Component
#Aspect
public class MyAspect {
...
simply mark your aspect method with
#After("#annotation(package.SomeAnnotation)")
Have a look at this for a step by step guide

Categories