Spring AOP - How to pass in a different number of parameters? - java

I have an Aspect:
#Aspect
#Component
public class BusinessAspect {
#Around("#annotation(Business)")
public Object getCorrespondingBusiness(ProceedingJoinPoint joinPoint, Business business) throws Throwable {
//BEFORE METHOD EXECUTION
Object data = joinPoint.getArgs()[0]; // gets first argument
int businessNumber = business.value(); // gets # in annotation
BusinessObj correspondingBusiness = getBusiness614(); // will make modular later
// This is where ACTUAL METHOD will get invoke
Object result = joinPoint.proceed( new Object[] { data, correspondingBusiness} );
// AFTER METHOD EXECUTION
System.out.println(result);
return result;
}
private BusinessObj getBusiness614() {
return valid business..
}
}
And here is the method that needs to access that correspondingBusiness object:
#Business(614)
public BusinessRule rangeFromGreaterThanRangeThrough(BusinessProfile businessProfile) {
return BusinessRule.businessRuleBuilder()
.withParameter("from", ...)
.withParameter("through", ...)
.withCrudOperationAction(...)
.withCrudOperationAction(...)
.setBusiness(correspondingBusiness) // not recognizing the parameter. compilation error?
).build();
}
Essentially, my issue is the correspondingBusiness object is not being recognized. I understand that you can manipulate and change parameters, but can you pass in extra parameters, or can you only change them? If I can only change them, how would I make it so I can call this method without having to pass in a second parameter? Creating an overload for each of these seems like a lot of unnecessary code.
Thank you!
Edit:
Here is the annotation interface for clarity:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Business {
int value();
}

The solution can be found in Spring documentation:
The parameter binding in advice invocations relies on matching names used in pointcut expressions to declared parameter names in (advice and pointcut) method signatures.
Define your Around advice as shown below and business parameter will be passed to the advice method.
#Around("execution(* *(..)) && #annotation(business)")

Related

Guice: Intercepting method with params and fields

Im looking into intercepting method invocations with Guice. I saw from here that basic interceptions are possible. However, the logic intercepting the methods require access to not only the parameters passed into the function, but also (unfortunately) a class member property. Is it possible to achieve this with Guice AOP? If so, what needs to be done? I'm thinking of something that might look like this:
class Foo {
#customInterceptor Object member; // Intercepting logic needs this
// function to be intercepted, param needed for the logic as well
#customInterceptor
void myFunc(#customInterceptor String param) {
// body, do something with member and param
}
}
It is possible using reflection. Not sure if it is a good practice and I assume you know what you are doing!
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object o = methodInvocation.getThis();
Field f = methodInvocation.getMethod().getDeclaringClass().getDeclaredField("member");
//if member is private
f.setAccessible(true);
System.out.println("inside interception :: " + f.get(o));
f.setAccessible(false);
return methodInvocation.proceed();
}

Where is the right place for annotation processing?

I write simple application. I don't want to use any frameworks. Please suggest me right place to hold annotation processing.
I have a few lines in main method:
String myString = (#NonNull String)list;
And I created #interface:
#Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
public #interface NonNull {
}
Which step should I take next? Can I work with annotations without using reflection? Could you expose for me samples of such annotation processing code?
There is no way (AFAIK) to work with annotations without reflection.
If you don't want to use any framework, first step is to write kind of proxy class handling the method requests. It is an example of method processing with annotation use over method:
public class MyProxy {
private <T> T getProxy(T t) {
return (T) Proxy.newProxyInstance(t.getClass().getClassLoader(), new Class<?>[]{MyClass.class}, new MyInvocationHandler(t));
}
}
And then implement InvocationHandler:
public class MyInvocationHandler implements InvocationHandler {
private Object obj;
MyInvocationHandler (Object obj) {
this.obj = obj;
}
#Override
public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
boolean isNotNull = method.isAnnotationPresent(NotNull.class);
if (isNotNull) {
/* process annotated method. Or go through proxy object fields etc.. */
}
}
}
I hope it will help you.
You didn't say what kind of annotation processing you want to do.
Do you want to add a run-time check that will cause your code to crash if list is ever null at run time? For this, reflection will work.
Do you want to add a compile-time check that will reject your code if it cannot prove that list is never null at run time? For this, an annotation processor such as the Checker Framework will work.
Your question does not explain why you don't want to use a framework. Doing so will save you from re-implementing a lot of functionality that others have already created.

how to get the Annotated object using aspectJ

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 *).*(..))")

AspectJ exchange data between Advice and JoinPoint

I am looking for a way to pass objects between Advice and JoinPoint, something like the following,
#Aspect
class SomeAspect {
#Around(execution * *.*(..) && #annotation(sample))
public Object PassbyRef(PJP pjp) {
SomeObjectToPass someObj = new SomeObjecttoPass();
Object retVal = pjp.proceed(someObj);
//process(someObj);
}
}
class UsingAspect {
#sample
public Object TestMethod() {
//how do I access someObj in this method?
}
}
I am looking to perform some action before execution of a method/JP, then I need to way to communicate between advice and method being executed, then I need to perform more actions after method has been executed.
Strange idea but if your design requires this You can try something like that:
just add a getter to your Advice class or maybe create an interface that requires this
class UsingAspect {
public getSomeObj(){return someObj};
}
and then from Aspect
if (joinPoint.getTarget().getClass() == UsingAspect.class){
UsingAspect ua=(UsingAspect)joinpoint.getTarget();
ua.getSomeObj()
}
Then in Advice and Aspect you should have reference to the same someObj. If you would like to do this in reverse direction just add a setter and save an object to your Advice class.

Code injection via custom annotation

Here's my use case:
I need to do some generic operation before and after each method of a given class, which is based on the parameter(s) of the method. For example:
void process(Processable object) {
LOGGER.log(object.getDesc());
object.process();
}
class BaseClass {
String method1(Object o){ //o may or may not be Processable(add process logic only in former case)
if(o intstanceof Prcessable){
LOGGER.log(object.getDesc());
object.process();
}
//method logic
}
}
My BaseClass has a lot of methods and I know for a fact that the same functionality will be added to several similar classes as well in future.
Is something like the following possible?
#MarkForProcessing
String method1(#Process Object o){
//method logic
}
PS: Can AspectJ/guice be used? Also want to know how to implement this from scratch for understanding.
Edit: Forgot to mention, what I have tried.(Not complete or working)
public #interface MarkForProcessing {
String getMetadata();
}
final public class Handler {
public boolean process(Object instance) throws Exception {
Class<?> clazz = instance.getClass();
for(Method m : clazz.getDeclaredMethods()) {
if(m.isAnnotationPresent(LocalSource.class)) {
LocalSource annotation = m.getAnnotation(MarkForProcessing.class);
Class<?> returnType = m.getReturnType();
Class<?>[] inputParamTypes = m.getParameterTypes();
Class<?> inputType = null;
// We are interested in just 1st param
if(inputParamTypes.length != 0) {
inputType = inputParamTypes[0];
}
// But all i have access to here is just the types, I need access to the method param.
}
return false;
}
return false;
}
Yes, it can be done. Yes, you can use AspectJ. No, Guice would only be tangentially related to this problem.
The traditional aspect approach creates a proxy which is basically a subclass of the class you've given it (e.g. a subclass of BaseClass) but that subclass is created at runtime. The subclass delegates to the wrapped class for all methods. However, when creating this new subclass you can specify some extra behavior to add before or after (or both) the call to the wrapped class. In other words, if you have:
public class Foo() {
public void doFoo() {...}
}
Then the dynamic proxy would be a subclass of Foo created at runtime that looks something like:
public class Foo$Proxy {
public void doFoo() {
//Custom pre-invocation code
super.doFoo();
//Custom post-invocation code
}
}
Actually creating a dynamic proxy is a magical process known as bytecode manipulation. If you want to to do that yourself you can use tools such as cglib or asm. Or you can use JDK dynamic proxies. The main downside to JDK proxies are that they can only wrap interfaces.
AOP tools like AspectJ provide an abstraction on top of the raw bytecode manipulation for doing the above (you can do a lot with bytecode manipulation, adding behavior before and after methods is all aspects allow). Typically they define 'Aspect's which are classes that have special methods called 'advice' along with a 'pointcut' which defines when to apply that advice. In other words you may have:
#Aspect
public class FooAspect {
#Around("#annotation(MarkForProcessing)")
public void doProcessing(final ProceedingJoinPoint joinPoint) throws Throwable
{
//Do some before processing
joinPoint.proceed(); //Invokes the underlying method
//Do some after processing
}
}
The aspect is FooAspect, the advice is doProcessing, and the pointcut is "#annotation(MarkForProcessing)" which matches all methods that are annotated with #MarkForProcessing. It's worth pointing out that the ProceedingJoinPoint will have a reference to the actual parameter values (unlike the java.lang.reflect.Method)
The last step is actually applying your aspect to an instance of your class. Typically this is either done with a container (e.g. Guice or Spring). Most containers have some way of knowing about a collection of aspects and when to apply them to classes constructed by that container. You can also do this programmatically. For example, with AspectJ you would do:
AspectJProxyFactory factory = new AspectJProxyFactory(baseClassInstance);
factory.addAspect(FooAspect.class);
BaseClass proxy = factory.getProxy();
Last, but not least, there are AOP implementations which use compile-time "weaving" which is a second compilation step run on the class files that applies the aspects. In other words, you don't have to do the above or use a container, the aspect will be injected into the class file itself.

Categories

Resources