I have annotation like #SecureObject, which might be applied to some classes. Additionally there is the ORM, which provides method like
public ObjectID get(Class paramClass, Object object);
Now I need to create aspect, which will be triggered only in case if paramClass is annotated with #SecureObject.
Straightforward solution like:
#Before("call(public * some.orm.Datastore.get(..,#SecureObject *,..))"
void runBefore() {
// method code
}
does not work - method is never invoked. but wired (checked with aspectj -debug).
Is it possible to achieve such behavior with AspectJ, and if so - how?
The problem is that the first parameter of your get() method is of type Class.
Given that, you can't use an annotation-based method signature pattern. One possible solution is to use an if() pointcut expressions:
package aspects;
#Aspect
public class MyAspect {
#Pointcut("if() && call(public * some.orm.Datastore.get(..)) && args(paramClass,..)")
public static boolean runBefore(JoinPoint jp, Class paramClass) {
return paramClass.isAnnotationPresent(annotation.SecureObject.class);
}
#Before("runBefore(jp, paramClass)")
public void runBeforeAdvice(JoinPoint jp, Class paramClass) {
System.out.println("annotated!");
}
}
Note: This pointcut also triggers if no #SecureObject annotation is present but the if() condition gets evaluated at runtime.
Related
I hope I have chosen a title as clear as possible.
I have classes annotated with a custom annotation
#MyAnnotation
public class MyClass1 {
//...
}
#MyAnnotation
public class MyClass2 {
//...
}
I have another class that I want to enrich with two methods with the same name:
one method that takes only the annotated class as parameters, and the other method that takes other classes as parameters
public class MyOtherClass {
public void myMethod(Object obj) {
//.....
}
public void myMethod (#MyAnnotation Object obj) {
// this method is applied for only classes annotated with #MyAnnotation
}
}
I know that public void myMethod (#MyAnnotation Object obj) is a wrong way we can not pass annotation as parameter. But I want to find the proper way to handle this need.
You can have a single myMethod(Object obj) and inside it manually check if the obj passed to this method was annotated with #MyAnnotation (supposing that the retention policy is to keep it at runtime). Then dispatch calls to some private void processAnnotated(Object obj) and private void processNotAnnotated(Object obj) based on the result.
public void myMethod(Object obj) {
if (obj != null && obj.getClass().isAnnotationPresent(MyAnnotation.class)) {
processAnnottated(obj);
} else {
processNotAnnottated(obj);
}
}
I am not sure what you are trying to achieve. As you say, you can't annotate a parameter. You can mark an annotation as Runtime, but then you can only check with reflection if an annotation is present or not. So you could start myMethod with a call to a private validation method validateMyAnnotationIsSet(parameter) that checks if the annotation is set on the given class or not.
Perhaps it's better however to work with a MarkerInterface. You can create an empty interface that the class may or may not implement. Within your method you can accept that interface as parameter and then do an 'instanceof' and a cast to continue to work with it.
How can I use #around spring AOP annotation on method declaration? actually there are lots of duplicate code in the java class so I am thinking to optimize it.Only the #around execution values are getting changed every time and method definition is same for 3-4 methods.Can you please suggest what I can do in this case for code optimization?Here in the given example you can see nicdStatus and nicdPortStatus are only getting changed and rest all the method definition is same.
Please provide some suggestion for code optimization because I have duplicate code in my java class.
#Around("execution(* dcp.casa.services.nicd.NicdController.**nicdStatus**(..)) && args(*, relationId,..)")
Object handleRunTest(final ProceedingJoinPoint joinPoint, final String relationId) {
log.info("xyz");
callAbc();
return joinPoint.proceed();
}
#Around("execution(* dcp.casa.services.nicd.NicdController.nicdPortStatus(..)) && args(*, relationId,..)")
Object handleRunTest(final ProceedingJoinPoint joinPoint, final String relationId) {
log.info("xyz");
callAbc();
return joinPoint.proceed();
}
AOP means you want to intercept some logic. While with #around , you are ready to put the some logic before and after some your method. That's good way to remove duplicate code.
What you need to do:
1) find all the methods with duplicate code.
2) abstract those duplicate code into some methods.
3) config with right pointcut.
here have more example. Hope can help.
Your question is a bit unclear. Am I guessing right that you have multiple #Around advice methods with identical method bodies and you want to factor out those method bodies into a helper method in order to avoid code duplication within your aspect(s)?
yes you are correct #kriegaex. you understood my question.
Well, then the answer is simple: Just refactor like you would refactor any other Java class:
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#Aspect
public class LoggingAspect {
private static final Logger log = LoggerFactory.getLogger(LoggingAspect.class);
private void callAbc() {}
#Around("execution(* dcp.casa.services.nicd.NicdController.**nicdStatus**(..)) && args(*, relationId, ..)")
public Object handleRunTestA(ProceedingJoinPoint joinPoint, String relationId) throws Throwable {
return handleRunHelper(joinPoint);
}
#Around("execution(* dcp.casa.services.nicd.NicdController.nicdPortStatus(..)) && args(*, relationId, ..)")
public Object handleRunTestB(ProceedingJoinPoint joinPoint, String relationId) throws Throwable {
return handleRunHelper(joinPoint);
}
private Object handleRunHelper(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("xyz");
callAbc();
return joinPoint.proceed();
}
}
If the helper method also needs access to String relationId, just add another parameter to it and call it correspondingly.
I am investigating AspectJ and its many uses and have discovered mixins.
I can find many examples employing pure AspectJ .aj aspects however I need to use only #AspectJ annotations.
What I am trying to achieve is the following:-
I have a class that I cannot amend, it has a private class variable that I need to interrogate after a particular class method has completed execution. This class does not have getter or setter methods associated with this private class variable.
public final class CannotAmend {
private Uri privateUri;
public final void methodOne(){}
public final void methodTwo(){}
public final void methodThree(){
privateUri = "something";
}
}
I require an aspect/mixin that can capture #After methodThree() and allow me to see the value set in privateUri.
Is this possible to achieve?
With #AspectJ annotations?
Where can I discover documentation/tutorial/examples of how to achieve this?
Within an aspect you can access the private field using the reflection API.
In the aspect you need two things:
A pointcut to define methods on which the aspect matches.
And a method annotated with #After containing logic that's executed after a method matched by the pointcut returns.
#Aspect
public class MyAspect {
#Pointcut("execution(* CannotAmend.methodThree(..))")
public void methodThreePointcut(){
}
#After("methodThreePointcut()")
public void afterMethod(JoinPoint joinPoint) throws NoSuchFieldException, IllegalAccessException {
Object instance = joinPoint.getThis();
Field privateUriField = instance.getClass().getDeclaredField("privateUri");
privateUriField.setAccessible(true);
String privateUri = (String) privateUriField.get(instance);
System.out.println(privateUri); // prints "something"
}
}
On a side note, using String constants to access a private field is not a clean solution. If sometime in the future the name of the variable changes or if it's removed, the aspect will break.
Not with mixins, but you can use #Around advice to get JoinPoint and get field through reflection.
For example:
#Around("execution(* *.methodThree())")
public Object getValue(ProceedingJoinPoint pjp) throws Throwable {
try {
return pjp.proceed();
} finally {
System.out.println(pjp.getThis().getClass().getDeclaredField("privateUri").get(pjp.getThis()));
}
}
What I'm looking for is a way to specify a pointcut around a class level variable. Something like:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.FIELD)
#interface MyPointCut
{
}
public class Foo
{
#MyPointCut
BarAPI api = new BarAPI();
}
#Aspect
public class MyAspect
{
#Around(value="execution(* *(..)) && #annotation(MyPointCut)")
public Object doSomethingBeforeAndAfterEachMethodCall()
{
...
}
}
I would then like to have an aspect that performs some work before and after each method invocation of the api field.
Is this doable? Could you please point me to some documentation where I can read how to do it?
It is a bit like simply putting execution advice on all the methods in type BarAPI, but your difference is that you only care about a specific instance of BarAPI and not all of them.
// Execution of any BarAPI method running in the control flow of a Foo method
Object around(): execution(* BarAPI.*(..)) && cflow(within(Foo)) {...}
cflow is a bit 'heavy' for this though, can we do something lighter:
// Call to any BarAPI method from the type Foo
Object around(): call(* BarAPI.*(..)) && within(Foo) { ... }
And what about something like that but more generally applicable:
// Assume Foo has an annotation on it so it is more general than type Foo.
#HasInterestingBarAPIField
public class Foo { ... }
Object around(): call(* BarAPI.*(..)) && #within(HasInterestingBarAPIField) { ... }
I have several Aspects coded in my application. All others works except for the following.
Service Interface
package com.enbiso.proj.estudo.system.service;
...
public interface MessageService {
...
Message reply(Message message);
Message send(Message message);
...
}
Service Implementation
package com.enbiso.proj.estudo.system.service.impl;
....
#Service("messageService")
public class MessageServiceImpl implements MessageService {
...
#Override
public Message reply(Message message) {
...
return this.send(message);
}
#Override
public Message send(Message message) {
...
}
}
Aspect
#Aspect
#Component
public class NewMessageAspect {
...
#AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(..))",
returning = "message")
public void perform(Message message){
...
}
}
When I try to execute the send method the debug point is not getting hit in the aspect perform.
UPDATE
I did some investigations and found that this doesn't work, when the send method is invoked from the reply method as below
#Autowire MessageService messageService;
...
messageService.reply(message);
But if I call the method messageService.send(message) it works fine. But as reply method is calling send method internally, shouldn't it also invoke the aspect?
I have no idea what i have done wrong. Please help me.
Thank you jst for clearing the things up. Just for the information purposes for the future developer in SO, I'm posting the full answer to this question
Lets assume that there is a bean from SimplePojo
public class SimplePojo implements Pojo {
public void foo() {
this.bar();
}
public void bar() {
...
}
}
When we call the method foo(), it reinvokes the method bar() inside it. Even thought the method foo() is invoked from the AOP Proxy, the internal invocation of the bar() is not covered by the AOP Proxy.
So eventually this makes, if there are any advices attached to the method bar() to not get invoked
Solution
Use AopContext.currentProxy() to call the method. Unfortunately this couples the logic with AOP.
public void foo() {
((Pojo) AopContext.currentProxy()).bar();
}
Reference:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies
You are running into a limitation of Spring AOP on self-invocation. You basically can get around it by using AopContext.currentProxy(), refactor code into different beans, or use full ApsectJ weaving.
See explanation here and workaround(s).
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies
I guess the problem is the #args condition.
Spring documentation states the following:
#args - limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given type(s)
Therefore the parameter of #args has to be a type expression. So the correct pointcut expression is
#AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(..)) && args(com.enbiso.proj.estudo.system.service.impl.Message")
or simply
#AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(com.enbiso.proj.estudo.system.service.impl.Message))")
Please adjust the package of Message if it doesn't fit.