I have an annotation like this:
#Inherited
#Documented
#Target(value={ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface Restful {
}
I annotated this class like this:
#Restful
public class TestAspect {
public String yes;
}
I have a pointcut like this:
#Pointcut("#annotation(com.rest.config.Restful)")
public void pointCutMethod() {
}
I tried:
#Before("pointCutMethod()")
public void beforeClass(JoinPoint joinPoint) {
System.out.println("#Restful DONE");
System.out.println(joinPoint.getThis());
}
But getThis() returns null.
Basically I am trying to get that Object instance of TestAspect. How do I do it? Any clue? any help would be really appreciated.
Thanks in advance
With your annotation placed on the type only and the pointcut #annotation(com.rest.config.Restful) you are only going to match the static initialization join point for your type. As we can see if you use -showWeaveInfo when you compile (I slapped your code samples into a file called Demo.java):
Join point 'staticinitialization(void TestAspect.<clinit>())' in
Type 'TestAspect' (Demo.java:9) advised by before advice from 'X' (Demo.java:19)
When the static initializer runs there is no this, hence you get null when you retrieve it from thisJoinPoint. You haven't said what you actually want to advise but let me assume it is creation of a new instance of TestAspect. Your pointcut needs to match on execution of the constructor for this annotated type:
// Execution of a constructor on a type annotated by #Restful
#Pointcut("execution((#Restful *).new(..))")
public void pointcutMethod() { }
If you wanted to match methods in that type, it would be something like:
#Pointcut("execution(* (#Restful *).*(..))")
Related
I want to have annotation on class level that will execute advice on every method in annotated class.
Is that even possible.
Example: I would like to annotate OmniDemoService with #DoSomethingForMe and I want both method1 and method2 to log "look at me" before execution
This example is not working and I don't know why. When I transform Pointcut to Around and just use it with annotation (also change annotation ElementType to method) everything is working on method level.
So I think it is wrong defined Pointcut.
Annotation:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface DoSomethingForMe {
}
Advice:
#Aspect
#Component
public class DoSomethingForMeAdvice {
private static final Logger logger = LoggerFactory.getLogger(DoSomethingForMeAdvice.class);
#Pointcut("execution(public * *(..)) && #annotation(DoSomethingForMe)")
public void anyAnnotatedMethod() {
}
#Before("anyAnnotatedMethod()")
public void acquireExecution() {
logger.info("look at me");
}
}
Usage:
#Service
#DoSomethingForMe
public class OmniDemoService {
private static final Logger logger = LoggerFactory.getLogger(OmniDemoService.class);
public void method1() {
logger.info("---1---");
}
public void method2() {
logger.info("---2---");
}
}
Your issue is that you are confusing pointcut definition with advices.
Pointcut is aiming, advice performs the actual WhateverYouWantToBeExecuted. Like for example
#Pointcut("#annotation(com.omnidemo.advice.DoSomethingForMe)")
public void anyAnnotatedMethod() {
}
#Before("anyAnnotatedMethod()")
public void logMethodCall(JoinPoint jp) {
String methodName = jp.getSignature().toShortString();
logger.info("Executing: " + methodName);
}
Solution for the problem is to use within for pointcut
#Pointcut("#within(DoSomethingForMe)")
public void anyAnnotatedMethod() {
}
#Before("anyAnnotatedMethod()")
public void acquireExecution() {
logger.info("look at me");
}
Solution provided by #J Asgarov in the comments
Check out what the AspectJ quick reference says about #annotation():
any join point where the subject has an annotation of type
SomeAnnotation
You used #annotation(DoSomethingForMe) but the "subject" of a method execution is a method. So that would mean any method annotated #DoSomethingForMe.
Use #this(DoSomethingForMe) or #target(DoSomethingForMe).
Thanks to kriegaex for pointing out that #this and #target must be evaluated at runtime, which would pollute the codebase a lot (i.e. check in every method). So the next approach is better:
If you check the AspectJ manual section about type patterns you will see that you can annotate the type directly. Please also remember to use use fully qualified class names. So that would be:
execution(public * (#com.path.DoSomethingForMe *).*(..))
Also, if you have such a simple pointcut and you don't need to reuse it, I think you can drop the additional method and just use it in the advice directly:
#Before("execution(public * (#com.path.DoSomethingForMe *).*(..))")
which says: "before the execution of any public method of a type annotated with #com.path.DoSomethingForMe", where "before the execution of a method" means "inside the method, at the beginning".
Alternatively, if this pointcut looks a bit too complicated for you, you can separate annotation matching and method matching like this, as suggested by J Asgarov in his comment:
#Before("execution(public * *(..)) && #within(com.path.DoSomethingForMe)")
I've got a simple aspect that supposed to set the value of class fied, that has annotation #GuiceInject.
Originally I have this
#GuiceInject(module=RepositoryModule.class)
private IRacesRepository repository;
And I expect to get similar to this
private IRacesRepository repository = GuiceInject.getInstance(IRacesRepository.class);
And here is my aspect
public aspect InjectionAspect {
Object around(): get(#GuiceInject * *) {
System.out.println(thisJoinPointStaticPart);
// instantiate object as it supposed to be null originally
return GuiceInjector.getInstance(thisJoinPoint.getTarget().getClass());
}
}
As far as I understand - I am new to AOP - it supposed to replace get invokations of the field with the code in aspect.
It compiles fine, but when I run the application - nothing happens. I get NullPointerException for readRaces method as it stays null so aspect did not work.
My main class looks like this
public class Example {
#GuiceInject(module=RepositoryModule.class)
private IRacesRepository racesRepository;
private void execute() {
System.out.println("List of races: " + racesRepository.readRaces());
}
public static void main(String[] args) {
new Example().execute();
}
}
What is the problem? Annotation has this definition
#Target(ElementType.FIELD)
// make annotation visible in runtime for AspectJ
#Retention(RetentionPolicy.RUNTIME)
public #interface GuiceInject {
Class<? extends AbstractModule> module();
}
Please try to redefine pointcut syntax as
Object around(): get(#package.subpackage.GuiceInject * *.*)
Correct field signature must specify the type of the field, the declaring type, and name. If your annotation is in different package, it should be fully qualified.
I am trying to learn AspectJ and figuring out how to retrieve specific joinpoints at certain points in a flow. My example is something like this:
I want to run an unit test annotated with JUnit's #Test then any methods called in that test that may be in another class annotated with another annotation, let's say #Example, then I could access basically the entire flow at those certain points so I had the ability to get the class name/method name of the test annotated with #Test and then also get the method information for the method annotated #Example. I've included some example code for clarification:
Test class:
public class ExampleTest {
#Test
public void shouldTestSomething() {
ExampleClass exampleClazz = new ExampleClass();
exampleClazz.something();
// ...
}
POJO:
public class ExampleClass {
#Example
public void something() {
// do something
end
end
So with these classes, I would like to make an aspect that would basically find any kind of #Example called within a #Test so I can then have access to both (or more) join points where I can grab the method/class signatures from the AspectJ JoinPoint object.
I tried something like this:
#Aspect
public class ExampleAspect {
#Pointcut("execution(#org.junit.Test * *(..))
&& !within(ExampleAspect)")
public void testPointCut() {}
#Pointcut("#annotation(com.example.Example)")
public void examplePointCut() {}
#After("cflow(testPointCut) && examplePointCut()")
public void doSomething(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature());
}
}
But the output looks like this:
void ExampleTest.ExampleClass.something()
The main issue is that it is missing the name of the test method (shouldTestSomething()) in the signature. What would be the best way to retrieve that?
Not sure if I understand correctly, but if you need to access information about the context from where a piece of code under a join point of your interest gets called, then what you need is the thisEnclosingJoinPointStaticPart (in native AspectJ syntax). If you are using AspectJ 5 annotation style aspects, just add a parameter to your advice method with the type JoinPoint.EnclosingStaticPart.
Note that this is not available for execution() style pointcuts, only for call() style pointcuts, otherwise the JoinPoint.EnclosingStaticPart and JoinPoint.StaticPart will be the same.
This means you need to rewrite your aspect in the following way:
#Aspect
public class ExampleAspect {
#Pointcut("execution(#org.junit.Test * *(..)) && !within(ExampleAspect)")
public void testPointCut() {
}
#Pointcut("call(#com.example.Example * *(..))")
public void examplePointCut() {
}
#After("cflow(testPointCut()) && examplePointCut()")
public void doSomething(JoinPoint joinPoint, EnclosingStaticPart enclosingStaticPart) {
System.out.println(joinPoint.getSignature() + " was invoked from "
+ enclosingStaticPart.getSignature());
}
}
The output with your test code would be:
void q35991663.com.example.ExampleClass.something() was invoked from void q35991663.com.example.ExampleTest.shouldTestSomething()
I also rewrote your examplePointCut. The pointcut expression #annotation(com.example.Example) would mean
any join point where the subject has an annotation of type com.example.Example
which would include both execution() and call() type join points. We need only the call() join points in this case, so #annotation() isn't even necessary if you are not planning to bind the value of the annotation to the advice context.
I am building a custom annotation inside which there is a field of Class type. How do I set a value in it while using the annotation?
Code is given below :
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface SpringCache {
String putIt();
String getIt();
Class c();
}
This is my custom annotation. Now while I use it how do I give class to variable "c"?
#SpringCache(putIt="I'm put", getIt="I'm get", c=<??>)
public class TestSpringCache {
public static void main(String[] args) {
System.out.println();
}
}
As in this case I want c=TestSpringCache.class.
You just write the class you want:
#SpringCache(putIt="I'm put", getIt="I'm get", c=TestSpringCache.class)
public class TestSpringCache {
public static void main(String[] args) {
System.out.println();
}
}
You might have to add an import statement, if it is not in the same package.
You have to optain all class instances from ApplicationContext (you can inject it), ctx.getBean(). There you can check if an annotation is present.
Actually I didn't find the solution for this. As said by many it does not seem to be possible. Though I have found a work around this.
I removed the class type and kept only String and Boolean type variable there, and to get the annotated classes I took the path from the user to the package containing classes with the defined annotation. And then for each class in the package I checked for the annotation. If annotation was present I did what I wanted to, else did nothing.
Thanks to everyone for giving your time to this.
Pointcut declaration:
#Pointcut(value="com.someapp.someservice.someOperation() && args(t,req)",argNames="t,req")
private void logOperationArg(final String t,final String req)
{
}
Advice Declaration not compiling:
#Before(value="logOperationArg(t,req)")
public void logBeforeOperationAdvice(JoinPoint jp, final String t, final String req){
...
}
When compiling Aspect with Aspectj-maven-plugin (1.5 version), have error "can not build thisJoinPoint lazily for this advice since it has no suitable guard [Xlint:noGuardForLazyTjp]"
But the same advice compiles without JoinPoint argument.
Advice Declaration compiling:
#Before(value="logOperationArg(t,req)")
public void logBeforeOperationAdvice(final String t, final String req){
...
}
Spring AOP only supports method join points because it is based on dynamic proxies which creates proxied object if it is needed (for example if you are using ApplicationContext, it will be created after beans are loaded from BeanFactory)
Use execution() statement to match join points which are methods execution.
For example:
class LogAspect {
#Before("execution(* com.test.work.Working(..))")
public void beginBefore(JoinPoint join){
System.out.println("This will be displayed before Working() method will be executed");
}
And now how to declare your BO:
//.. declare interface
then:
class BoModel implements SomeBoInterface {
public void Working(){
System.out.println("It will works after aspect");
}
}
execution() statement is a PointCut expression to tell where your advice should be applied.
If you like to use #PointCut, you can do something like this:
class LogAspect {
//define a pointcut
#PointCut(
"execution(* com.test.work.SomeInferface.someInterfaceMethod(..))")
public void PointCutLoc() {
}
#Before("PointCutLoc()")
public void getBefore(){
System.out.println("This will be executed before someInterfaceMethod()");
}
}
Part2:
Also,the Error shows that you haven't put a guard on your advice. Technically guard makes your code faster, because you do not need construct thisJoinPoint everytime you execute it. So, if it does not make sense you can try to ignore it
canNotImplementLazyTjp = ignore
multipleAdviceStoppingLazyTjp=ignore
noGuardForLazyTjp=ignore