How to get the caller method information from Around advise - aspectj

ThisJoinPoint can only get the current method information, anyway to get the caller method information?

You can try the special variable thisEnclosingJoinPointStaticPart which holds the static part of the enclosing JoinPoint.
Mentioned here (example) and here (docs)
Or if using annotation-based AspectJ, pass following to the advice method's parameters, e.g.:
#Before("call( /* your pointcut definition */ )")
public void myCall(JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart)
{
// ...
}
Mentioned here

#Aspect
public class LoggingAspect {
#Before(value = "execution(public * findAll())")
public void beforeAdvice(JoinPoint pp){
System.out.println("before advice called ....get calling method Signature"+pp.getSignature());
System.out.println("before advice called ....get calling method name"+pp.getSignature().getName());
}
}

Related

Spring AOP : Interface method with Parameter annotation captured, but annotation is not present

I'm using Spring AOP to intercept a method execution.
I have an interface that looks like the following:
public interface MyAwesomeService {
public Response doThings(int id, #AwesomeAnnotation SomeClass instance);
}
Here is the implementation of the interface:
public class MyAwesomeServiceImpl implements MyAwesomeService {
public Response doThings(int id, SomeClass instance) {
// do something.
}
}
Now i would like any method which has a parameter annotated with #AwesomeAnnotation should be captured by Spring AOP.
So I wrote the following aspect which works.
#Aspect
#Component
public class MyAwesomeAspect {
#Around("myPointcut()")
public Object doAwesomeStuff(final ProceedingJoinPoint proceedingJoinPoint) {
final MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations();
// annotationMatrix is empty.
}
#Pointcut("execution(public * *(.., #package.AwesomeAnnotation (package.SomeClass), ..))")
public void myPointcut() {}
}
However when I try to find the parameter annotations I don't get any annotations back. As mentioned above, the annotationMatrix is empty.
So here are my questions:
Why is the annotationMatrix empty? Probably because parameter annotations are not inherited from an interface.
Why I'm able to capture the method execution. Since Spring AOP is able match the pointcut, Spring somehow is able to see the method's parameter annotations but when I try to see that using methodSignature.getMethod().getParameterAnnotations() it doesn't work.
I also faced this issue with one of my parameter annotations. I was able to fix the same by making sure that the parameter annotation definition had RetentionPolicy as RUNTIME and Target as PARAMETER
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
public #interface Param {
public String name();
}
The answers to your questions:
Parameter annotations are not inherited from interfaces to implementing methods. In fact, annotations are almost never inherited, only from class (not interface!) to subclass if the annotation type itself is annotated by #Inherited, see JDK API documentation.
Update: Because I have answered this question several times before, I have just documented the problem and also a workaround in Emulate annotation inheritance for interfaces and methods with AspectJ.
Because during compile or weave time AspectJ can match your pointcut against the interface method and thus sees the annotation.
You can fix the situation by adding the annotation to the parameter in your interface implementation, e.g. like this:
#Override
public Response doThings(int id, #AwesomeAnnotation SomeClass instance) {
// ...
}
Then with an aspect like this...
#Aspect
#Component
public class MyAwesomeAspect {
#Pointcut("execution(public * *..MyAwesomeService.*(*, #*..AwesomeAnnotation (*), ..)) && args(*, instance, ..)")
static void myPointcut(SomeClass instance) {}
#Around("myPointcut(instance)")
public Object doAwesomeStuff(Object instance, ProceedingJoinPoint proceedingJoinPoint) {
System.out.println(proceedingJoinPoint);
System.out.println(" instance = " + instance);
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations();
for (Annotation[] annotations : annotationMatrix) {
for (Annotation annotation : annotations) {
System.out.println(" annotation = " + annotation);
}
}
return proceedingJoinPoint.proceed();
}
}
... you get a console log similar to this:
execution(Response de.scrum_master.app.MyAwesomeServiceImpl.doThings(int, SomeClass))
instance = de.scrum_master.app.SomeClass#23fc625e
annotation = #de.scrum_master.app.AwesomeAnnotation()

guice ignores providers?

It seems Guice is ignoring my #Provider methods of my module.
I have a class MyModule like this:
public class MyModule extends AbstractModule {
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(Timed.class), new GuiceEnabledLoggingInterceptor());
bind(OneClass.class).to(OneClassImpl.class);
// And more binding lines...
}
#Provides
public AnotherClassInApi provideMyClass() {
return AnotherClassInApi.getInstance();
}
// And more #Provides methods
}
Main method is
public static void main(String[] args){
ConfigHandler.getInstance().loadConfigWhenNotRunningInsideMicrocontainer();
Injector INJECTOR = Guice.createInjector(new MyModule());
// ...
}
In some other part of the project I have class AnotherClassInApi, which is a very standard singleton plus one method:
public class AnotherClassInApi {
private static final AnotherClassInApi INSTANCE = new AnotherClassInApi();
private AnotherClassInApi() { }
// ... more methods
public static AnotherClassInApi getInstance() {
return INSTANCE;
}
}
Well, I understand that should effectively bind any request for an AnotherClassInApi object to the getInstance() method, but it doesn't work. Funny thing, a breakpoint in the #Provide method is never reached while debugging, but one in the configure method is reached. It seems guice is ignoring my provider annotation, and I think I'm following exactly what Guice guide says about #Provider, so I'm already stuck.
I've been googling around, but can't find anything similar. Any help will be much appreciated.
Thanks!
The concept of Providers (and #Provides methods) is, that they are only called when actually needed. So unless you really use your Injector to create an instance that has an #Inject dependency, your Provider is not ignored, just not used (nor needed).
You can monitor all configured bindings by using "injector.getAllBindings()".
java.util.Map,Binding> getAllBindings()
Returns a snapshot
of this injector's bindings, both explicit and just-in-time. The
returned map is immutable; it contains only the bindings that were
present when getAllBindings() was invoked. Just-in-time bindings are
only present if they have been requested at least once. Subsequent
calls may return a map with additional just-in-time bindings. The
returned map does not include bindings inherited from a parent
injector, should one exist.
This method is part of the Guice SPI and is intended for use by tools
and extensions.

How to pass our own runner instead of BlockJUnit4ClassRunner

Actually i wanted to override the runChild() method of BlockJUnit4ClassRunner hence I created a class (MyRunner.java) and exetended BlockJUnit4ClassRunner and overridden the runChild() method.
public class MyRunner extends BlockJUnit4ClassRunner
{
#Override
public void runChild(final FrameworkMethod method, RunNotifier notifier) {
System.out.println("<--------- Inside MyRunner.runChild() -------->");
// my code goes here
}
}
But the call doesn't go to my overridden method (it doesn't even come to MyRunner.java) and calls BlockJUnit4ClassRunner.runChild() method only.
I debugged and found that this is because the runner passed to JunitCore.run(Runner runner) method is BlockJUnit4ClassRunner.
I'm not sure on this but I think this might be coming from JUnit4Builder.runnerForClass() method .
// This is JUnit4Builder.runnerForClass(Class<?>) method
public Runner runnerForClass(Class<?> testClass) throws Throwable
{
return new BlockJUnit4ClassRunner(testClass);
}
I tried to override the JUnit4Builder.runnerForClass() also but that also did not helped.
Can anyone let me know if there's any way to pass the MyRunner or any means to override the BlockJUnit4ClassRunner.runChild() method.
You are probably not using the #RunWith annotation. In order to use your own Runner you need to annotate every TestClass with the #RunWith annotation. This will make sure, that your Test is executed with that runner.
Example:
#RunWith(MyRunner .class)
public class MyTest
{
....
}

Java and main()

I'm messing around with Eclipse(and java in general) for the first time in about a year. among the things I have forgotten is the following:
I have a function (void callvote() that I am hoping will be activated by my main function (that is, automatically, relatively early in the program). I currently have it within the same class (body) as the main function itself.
I try to call it withcallvote(); and get an error, "- Cannot make a static reference to the non-static method callvote() from the type body"
my function callvote is, at the moment, in the space below main and simply says
public void callvote()
{
}
am i committing a horrible sin by putting more functions in the same class as main?
is this a relatively easy fix that I missed somehow?
What does this error mean?
Have I woken Azatoth with this code?
Thanks in advance,
Tormos
Without the static modifier callvote is implicitly an instance method - you need an instance of a class to call it.
You could mark it as static also:
public static void callvote() ...
Or create an instance of the declaring class:
MyClass instance = new MyClass();
instance.callvote();
main() is a static method, meaning you can call it directly from a class whereas non-static members can only be called from an object. In order for you to call the callvote() method you need to first instantiate an object of your class:
public static void main(String [ ] args) {
MyClass myObject = new MyClass();
myObject.callvote();
}
Another way to avoid the error is to make you callvote() method static as well, but it's usually not what you want to do (but it depends on the nature of your class and method).
This post describes some of the dangers with the overuse of static methods: Class with single method -- best approach?
Try this:
public class Main {
public static void main(String[] args) {
new Main().callvote()
}
}
the main() entry point of your java program is static. You cannot call a non static method from a static one.
So you have to instanciate your Class first and call the method after.

aspectj - how to find a method of an annotated class is calling another method of same class. i.e. nested calls

I have an annotation #AppManaged which is used to signify classes that need to have certain behavior woven in. One behavior woven in is converting method calls into concurrent GPars(a groovy parallel library) calls instead.
However I do not want nested method calls on the same class to be advised.
So...
#AppManaged
class someclass
{
public void method1(){
method2(); **// should not be advised**
}
public void method2(){
}
}
But if the method call is from on AppManaged class to another, then it is supposed to be advised, hence something like !cflowbelow(#within(AppManaged)) does not help.
#AppManaged
class Someotherclass
{
private someclass s;
public void method3(){
s.method2();**// Should be advised.**
}
}
Basically I am looking for a pointcut which will match only nested calls within the same object instance and prevent them from being advised.
Any help would be highly appreciated.
Thanks and Regards
Abraham Menacherry.
How about:
pointcut appManagedExecution(Object appManaged) : execution(* (#AppManaged *).*(..)) && this(appManaged);
pointcut appManagedCall(Object called) : call(* (#AppManaged *).*(..)) && target(called);
pointcut routed(Object appManaged, Object called) : appManagedCall(called) && cflowbelow(appManagedExecution(appManaged)) && if(called != appManaged);