Java annotation to execute some code before and after method - java

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.

Related

Save method is intercepted but findAll is not

The problem is simple
#Around("execution(* package.*Repository.save(..))")
public Object saveInterupt(ProceedingJoinPoint joinPoint) throws Throwable {
// This gets called whenever repository save is called
}
#Around("execution(* package.*Repository.findAll(..))")
public Object findInterupt(ProceedingJoinPoint joinPoint) throws Throwable {
// This IS NOT GETTING called whenever repository findAll is called
}
Breaking head here!
Edit: A small break through. I printed the target , it returns SimpleJpaRepository instead of the Actual repository.
Assuming the repository is of the following construct
public interface JpaEmployeeRepository extends CrudRepository<JpaEmployee, Long> {..}
following pointcut works on both the cases
#Around("execution(* org..*Repository.save(..))")
and
#Around("execution(* org..*Repository.findAll(..))")
If I understand the question correctly the requirement is to intercept on the execution of a particular method within a specific package.If yes, More details on the same can be read here.
#AspectJ pointcut for all methods inside package
Are you using Spring-BOOT ? Aspecting in Spring-BOOT only calls the advice on a single method in the class the first time it is called. If you want Spring-BOOT to respect your #Around advice in all cases for multiple methods in any given class -- you need to access the class as a bean (SB's #Bean)...
Spring-BOOT's AOP is not 100% the same as aspecting using AspectJ -- the main difference is AspectJ modifies the byte-code where Spring uses a dynamic proxy.

Custom Annotation not found while unit testing

say i've an Annotation like that:
#Retention(RetentionPolicy.RUNTIME)
public #interface AutoConvert {
boolean enabled() default true;
}
and class annotated with it:
#AutoConvert
public class ExampleCommandToExample extends BaseConverter{}
On the superclass i'am doing the following:
public void convert(){
Annotation annotation = (AutoConvert) this.getClass().getAnnotation(AutoConvert.class);
}
Everything works fine on runtime! Annotation is getting found and properly set!
But! While unit testing the convert method with JUnit:
this.getClass().getAnnotation(AutoConvert.class)
always returns null.
The test looks like this:
#Test
public void convertTest(){
//when
exampleCommandToExample.convert();
}
Are custom annotations not being found by reflection while running unit tests?
Does anyone has an answer for me?
I would really really appreciate it.
Thank you in advance.
EDIT:
Alright it seems to be grounded in the kind of intatiation...
I do the following:
exampleCommandToExample = new ExampleCommandToExample() {
#Override
public Type overideSomeMethod() {
return type;
}
};
May it be possible that an instance looses all it's annotations
if I override some methods on instantiation?
Since exampleCommandToExample ref represents an instance of an anonymous class, the call this.getClass().getAnnotation(AutoConvert.class) collects the annotations at its level and all inherited ones.
However, #AutoConvert in this example of anonymous implementation is not inherited, that is why getAnnotation returns null, which corresponds exactly to the behavior declared in Java API:
Returns this element's annotation for the specified type if such an annotation is present, else null.
To solve the issue, simply add
import java.lang.annotation.Inherited;
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface AutoConvert { /* no changes */ }
#Inherited will make the annotation visible for the anonymous implementation.

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.

Create a Java Annotation with IDE contextual behaviour

I've created an Annotation
/**
* Highlights this method is declared in XML
*/
public #interface FromXML {
}
I'm using this on methods that look like this:
#FromXML
public void onSomethingClick(View v){
}
The v variable is needed by the Android reflection system to call this method.
However the input var v is unused, so my IDE warns me of this. I like this warning and want it on for the rest of my code.
To hide the warning I could do
#SuppressWarnings("unused")
#FromXML
public void onSomethingClick(View v){
}
or I could add a param tag
But I would rather that the IDE (eclipse) reads my #FromXML annotation and doesn't give me the warning.
I know you can't extend an Annotation, but thats basically what I want to do.
Is there a way I can add my annotation to be recognised as a 'suppress warnings' annotation.
or
Is there a way to code my annotation to 'act like' suppress warnings?
You can always create a plugin for Eclipse, that would scan through the source and find these annotations in your case #FromXML and add an extra annotation in your case #SuppressWarnings.
You could create a Command for it and when that command is fired you would run this plugin.
Creating Eclipse Plugin
Hope this helps.
UPDATE - IT WAS A FLUKE CANNOT BE DONE USING THIS (TRIED IT):
Or Using AspectJ for removing the warnings
Adding warnings in Eclipse using AspectJ
This tutorial uses AspectJ for adding warnings to eclipse if developer uses System.out.println() in the code. So the reverse can be done to remove the warning when annotation is present.
UPDATE 2: There is a way in Eclipse to create custom annotation processor or editting the bundeled annotation processor (that generates the unused variable warning). So will have to tweak that processor in a custom way.
Some great links:
Tutorials for Eclipse Annotation processor development
Java Development Tools - Annotation Processing Tools
I think you could create an interface defining this method. That way, your class will override the method and there should not be any warning.
FromXML.java:
public #interface FromXML {
}
MyInterface.java:
public interface MyInterface {
#FromXML
public void onSomethingClick(View v);
}
MyClass.java
public MyClass implements MyInterface {
#Override
#FromXML
public void onSomethingClick(View v){
}
}
EDIT :
Another solution could be to define your method as abstract. Indeed, as I understand your code, your methods are just declaration (Implementations are in a XML file). So, your problem is more a design problem than an IDE problem (your IDE is just right about the warning). The reality is that your method is abstract and is defined somewhere else.
Thus, defining your method as abstract will solve the problem but you'll have to make the class abstract:
public abstract class MyClassUsingOnSomethingClick {
/*
* All the class implementation can be here as the normal class.
*/
#FromXML
public abstract void onSomethingClick(View v);
}
I know you'll say that this solution make it impossible to create object easily but you'll have two solutions then:
1 - Create your objects inline:
MyClassUsingOnSomethingClick a = new MyClassUsingOnSomethingClick() {
#Override
#FromXML
public void onSomethingClick(View v) {}
};
2 - Create a factory method in your abstract MyClassUsingOnSomethingClick:
public static final MyClassUsingOnSomethingClick createEmptyMyClassUsingOnSomethingClick() {
return new MyClassUsingOnSomethingClick() {
#Override
#FromXML
public void onSomethingClick(View v) {}
};
}
// and then, create with: :
MyClassUsingOnSomethingClick a = MyClassUsingOnSomethingClick.createEmptyMyClassUsingOnSomethingClick();
Even is I understand that you would prefer a faster solution, I believe that this solution is the cleanest because:
It respects the Object Oriented Programming philosophy.
It is not specific to an IDE.
It avoids Annotation Processing Tool (which, in my opinion should be used very wisely)
Ok I can't do this in any easy way or form.
Looking at the annotation package http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/package-summary.html
I can't extend an annotation:
Why is not possible to extend annotations in Java?
I can't implement another annotation java.lang.Override
I can't mimic / mock / pretend to be #Override
If I add #Override to my #FromXML it is NOT inherited down the chain.
The only way would be to create an Eclipse plugin that recognises my annotation and stops the warning. Shame because I can't find an easy way to do this.
I also went down the route of creating an interface for my #FromXML entry points, this was very nice and communicated my Activity was of a type and therefore I didn't need the annotation anymore, perhaps this design change is the answer.

Categories

Resources