Spring AOP Pointcut expression for custom annotation in subclass - java

I am working on a logging aspect which need to intercept all the classes and methods annotated with a custom annotation.
Below is custom annotation class which can be annotated on class and methods:
#Documented
#Inherited
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE, ElementType.METHOD})
public #interface Loggable {
LogLevel value();
}
I am using these pointcut expressions to intercept methods and classes with annotation #Loggable, which is working for all the simple classes but does not work for classses which extend or implement.
//Works for annotation #Loggable on class level
#Pointcut("execution(* *(..)) && within(#com.logger.Loggable *)")
public void classAnnotationLogger() {
}
//Working for methods annotated with #Loggable
#Before(value = "#annotation(loggable)", argNames = "jp, loggable")
public void logBeforeAdvice(JoinPoint jp, Loggable loggable) {
..
..
}
Below is code for super class
#Component
#Loggable(LogLevel.INFO)
public abstract class Processor{
public void process(){
readProcess();
}
public abstract void readProcess();
}
Below is code for subclass
#Service
#Loggable(LogLevel.INFO)
public class MyServiceProcessor extends Processor {
#Override
public void readProcess(){
...
...
}
}
In the application readProcess() is called by doing
Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();
Even though I have #Loggable on Processor and MyServiceProcessor, when readProcess is called the advice is not being invoked.
But advice is invoked for process() and not readProcess.
How do I write the pointcut expression which also intercepts the call to any subclass methods, when annotation #Logabble is applied on any class or method?

Well, first of all this
#Pointcut("execution(* *(..)) && within(#com.logger.Loggable *)")
public void classAnnotationLogger() {}
is just a pointcut and not an advice, so it does not do anything unless you also have an advice actually using this pointcut. You have not posted such an advice, so I can only speculate.
Secondly, you have not provided any sample code which would be triggered by
#Before(value = "#annotation(loggable)", argNames = "jp, loggable")
public void logBeforeAdvice(JoinPoint jp, Loggable loggable) {}
at all, i.e. no annotated method. Your sample code only shows annotated classes.
As for the #Loggable annotation on the subclass, it should not be necessary because its base class already carries the same annotation and the annotation is #Inherited. This works for annotations on classes, but not for annotations on methods or interfaces, see my other answer for an explanation and a possible workaround.
This example of yours should actually work, I cannot see a reason why it would not:
Processor processor = applicationContext.getBean(MyServiceProcessor.class);
processor.readProcess();
But this internal call to readProcess() (equivalent to this.readProcess()) will not work:
public void process() {
readProcess();
}
This is because Spring AOP is a proxy-based "AOP lite" framework relying on JDK dynamic proxies (for interfaces) or CGLIB proxies (for classes). But calls to this.someMethod() are not routed through proxies of any type so they cannot be intercepted by Spring aspects. This is documented behaviour. If you want to overcome this limitation and apply aspects to internal method calls as well, please use full-blown AspectJ as documented here.

Related

Is a type-level annotation always inherited by public methods of that type?

Is it always the case that the following
public interface Foo {
#MyCustomAnnotation
void bar();
#MyCustomAnnotation
void bar2();
}
Is equivalent to
#MyCustomAnnotation
public interface Foo {
void bar();
void bar2();
}
Or does it depend on how the annotation is defined? In other words, are class/interface-level annotations always inherited by methods of that type (as long as the method isn't also marked with this annotation)?
Specifically, if I define the annotation above as
#Target({ ElementType.METHOD, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
public #interface MyCustomAnnotation {
}
Will methods inherit this annotation from the surrounding class/interface?
It is never the case that they are equivalent unless the library interpreting the annotation specifically decides to treat the type-level annotation as a default (e.g., Spring's #Transactional). Even then, it is entirely up to the code written in the library whether a combination of class-level and method-level annotations result in combination (#RequestMapping) or replacement (#Transactional) of definitions.

#Inherited annotation in Java

Herbert Schildt mentions in his book on Java,
#Inherited is a marker annotation that can be used only on another annotation declaration. Furthermore, it affects only annotations that will be used on class declarations. #Inherited causes the annotation for a superclass to be inherited by a subclass.
Therefore, when a request for a specific annotation is made to the subclass, if that annotation is not present in the subclass, then its superclass is checked. If that annotation is present in the superclass, and if it is annotated with #Inherited, then that annotation will be returned.
I know pretty well that annotations are not inherited. Exceptions are annotations, which its declaration is annotated with #Inherited.
I have understood the rest of the annotations which includes java.lang.annotation: #Retention, #Documented, and #Target. and other three—#Override, #Deprecated, and #SuppressWarnings.
I am a bit confused when it comes to the #Inherited annotation. Could someone demonstrate it with a simple foobar example?
Secondly, going through one of the questions regarding this on StackOverflow, I came across this,
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD) #Inherited
public #interface Baz {
String value(); }
public interface Foo{
#Baz("baz") void doStuff();
}
public interface Bar{
#Baz("phleem") void doStuff();
}
public class Flipp{
#Baz("flopp") public void doStuff(){}
}
What use does the #Inherited annotation have when put on the annotation #interface Baz?
Please don't explain me in context with annotations used Spring Framework, I am no in way familiar with it.
First, as the quote you posted states,
it affects only annotations that will be used on class declarations
So your example doesn't apply since you're annotating methods.
Here's one that does.
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(Bar.class.isAnnotationPresent(InheritedAnnotation.class));
}
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
//#Inherited
#interface InheritedAnnotation {
}
#InheritedAnnotation
class Foo {
}
class Bar extends Foo {
}
This will print false since the CustomAnnotation is not annotated with #Inherited. If you uncomment the use of #Inherited, it will print true.

How to get annotations of interface or abstract class methods in Java

I have an interface like this:
public interface IFoo{
#AnnotationTest(param="test")
String invoke();
}
and I implement this like this:
public class Foo implements IFoo{
#Override
public String invoke(){
Method method = new Object() {
}.getClass().getEnclosingMethod();
AnnotationTest ann = method.getAnnotation(AnnotationTest.class);
if(ann == null){
System.out.printl("Parent method's annotation is unreachable...")
}
}
}
If it is possible to reach parent's annotation, I want to learn the way of it.
Any help or idea will be appreciated.
You can use Spring AnnotationUtils.findAnnotation to read annotations from interfaces.
Example :
Interface I.java
public interface I {
#SomeAnnotation
void theMethod();
}
Implementing class A.java
public class A implements I {
public void theMethod() {
Method method = new Object() {}.getClass().getEnclosingMethod();
SomeAnnotation ann = AnnotationUtils.findAnnotation(method, AnnotationTest.class);
}
}
It obviously requires to include in your project (and import) Spring framework classes.
There is no direct way to get it. If you really need, you have to manually loop over getInterfaces() to find if any implemented interface has the annotation. If you want to search for (eventually abstract) superclasses and the annotation is not #Inherited, you can again iterate the superclass chain until finding Object (*).
But beware, as following post states, there are good reasons for this not to be directly implemented in Java : Why java classes do not inherit annotations from implemented interfaces?
(*) If the annotation is #Inherited it is automatically searched on superclasses, but not on interfaces.
you can't inherit annotations.
But a framework that uses an annotation can check to see if annotation is present on superclass

Extending Spring's pointcut-definig expression language

I am currently experimenting with Spring and its AOP features.
What I would like to know is if it is possible to extend the expression language of pointcut definition somehow...
I am quite familiar with the standard behaviour and usage of pointcut designators Spring provides but for my needs I would like to implement my own one.
Say we have a method in our aspect:
#Aspect
public class AspectClass {
#Before("execution(* *.get*(..)) && #annotation(someAnnotation)"
public void doStuff(ProceedingJoinPoint pjp, SomeAnnotation someAnnotation) {
System.out.println("Doing stuff!");
}
}
Now what I would like is something like this:
...
#Before("execution(* *.get*(..)) && #myAnnotation(someAnnotation)"
public void doStuff(ProceedingJoinPoint pjp, SomeAnnotation someAnnotation){
...
Where the myAnnotation(..) token is my custom extension of the expression language.
When I delved into Spring implementation I found where the parser resides and the fact it is hard-coded into AspectJExpressionPointcut implementation. Hence providing a custom implementation of said parser and sticking it someplace in some bean initialization routine seems like a no-no.
Exemplary usage of this extension would be for example matching a method by it's annotation, disregarding proximity of this annotation in the object hierarchy. So it would match a method that is overriden and whose annotation is defined on the parent's implementation.
public abstract class Superclass {
#SomeAnnotation
public abstract String getValue();
}
public class TheClass extends Superclass {
#Override
public String getValue() { // <- this would get advised by Spring using formerly defined aspect
// return some stuff
}
}
I know that I can reflect the method in the advice and check if the annotation is present on some method of some superclass, but I would like to encapsulate this process and offer it for convenient usage.
Have you guys stumbled upon something like this & can you offer me a solution (if it is possibe) / explanation (if it is not)? :-)
Thanks in advance, Janek.

Java annotation to execute some code before and after method

I'm writing an swing app and i'd like to have 'wait' cursor when some methods are executed. We can do it this way:
public void someMethod() {
MainUI.getInstance().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
//method code
MainUI.getInstance().setCursor(Cursor.getDefaultCursor());
}
What I'd like to achieve is a java annotation, that would set wait cursor before method execution and set it back to normal after execution. So previous example would look something like this
#WaitCursor
public void someMethod() {
//method code
}
How can i achieve this? Suggestions about other variants of solving this problem are also welcome.
Thanks!
P.S. - We use Google Guice in our project, but i don't get how to solve the problem using it. If someone would provide me with simple example of similar problem, that would be very helpful
You may use AspectJ, or use Google Guice which bring its own AOP.
The object having the method annotated with your WaitCursor annotation must be injected with Guice.
You define your annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface WaitCursor {}
You add a MethodInterceptor :
public class WaitCursorInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
// show the cursor
MainUI.getInstance().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
// execute the method annotated with `#WaitCursor`
Object result = invocation.proceed();
// hide the waiting cursor
MainUI.getInstance().setCursor(Cursor.getDefaultCursor());
return result;
}
}
And define a module where you bind the interceptor on any method having your annotation.
public class WaitCursorModule extends AbstractModule {
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(WaitCursor.class), new WaitCursorInterceptor());
}
}
You can see more advanced uses on this page
You might want to look at using around() advice in AspectJ in conjunction with your annotation to associate the around() advice with all methods that are qualified with your annotation.

Categories

Resources