Adding some boolean conditions in pointcut expression - aop

I'm using some aspect around advice methods. I have methods for controller, service and repository.
#Around("execution(* com.abc..controller..*(..)) && #annotation(audit)")
public Object controllerAround(ProceedingJoinPoint proceedingJoinPoint, Audit audit) throws Throwable {
//some code here
return output;
}
#Around("execution(* com.abc..service.*Impl.*(..))")
public Object serviceAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//some code here
return output;
}
#Around("execution(* com.abc..persistence.*Impl.*(..))")
public Object persistenceAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//some code here
return output;
}
I have a query that, I need to check in serviceAround method pointcut expression that, whether it's comes from the controllerAround method. I tried using some flags, but spring doesn't support aspectj's if() pointcut primitive.
Any workaround for this will be appreciated. :)

What you actually need is cflow() or cflowbelow(), not if(). But those are also not supported by Spring AOP. So the remaining solution is to use the full power of AspectJ from within Spring via LTW (load-time weaving). How this is done is nicely documented.
The pointcut would look like this:
execution(* com.abc..service.*Impl.*(..)) &&
cflow(
execution(* com.abc..controller..*(..)) &&
#annotation(customAnnotation)
)
Or simpler, assuming you do not need the annotation in the advice method:
execution(* com.abc..service.*Impl.*(..)) &&
cflow(execution(* com.abc..controller..*(..)))
Attention: cflow() only works for control flows within one thread, not if e.g. *Impl*.(..) is executed in another thread than controller..*(..).
P.S.: Your sample code would probably not work because of a parameter name mismatch between customAnnotation and audit.

Related

How to avoid if..else(or any conditionals) while deciding which method to be called?

How to follow Open Close Principle without violating LSP while deciding which method to be invoked with different parameters in a statically typed language?
Consider the requirement like
Action 1: perform DB operation on Table 1
Action 2: Perform DB operation on Table 2 based on input
Action 3: Do Nothing
Code for above requirement would look like
process(obj) {
if(obj.type === action1) {
db.updateTable1()
}
if(obj.type === action2) {
db.updateTable2(obj.status)
}
if(obj.type === action3) {
//May be log action 3 recieved
}
}
Figured out a way to follow OCP in above code for additional actions, by moving body of if statement to method and maintain a map of keys with action as name. Reference
However feels solution is violating the OCP as method wrapping the contents of first if block will not receive any parameter, second method wrapping the contents of second if block will have a parameter.
Either it forces all method to follow the same signature in trade off following OCP but violating LSP or give up OCP itself and thereby live with multi if statements.
A simple solution would be to define a strategy, which execute the code currently contained in the if / else if / else branches:
interface Strategy {
String getType();
void apply();
}
The strategies need to be registered:
class Executor {
private Map<String, Strategy> strategies;
void registerStrategy(strategy Strategy) {
strategies.put(strategy.getType(), strategy);
}
void process(obj) {
if (strategies.containsKey(obj.type)) {
// apply might execute db.updateTable1(),
// depending on the interface's implementation
strategies.get(obj.type).apply();
} else {
System.out.println("No strategy registered for type: " + obj.type);
}
}
}
The tradeoffs you recognise are unfortunately what you'll have to deal with when working with OOP in Java, C++, C# etc as the systems are dynamically put together and SOLID is kind of addresses the flaws. But the SOLID principles are intended to provide guidance, I wouldn't follow them idiomatically.
I hoped to find an example by better programmers than myself illustrating the command pattern. But I was just finding really bad examples which were not really addressing your question.
The problem of defining an associating an intent (defined as string or enum, a button click) with an action (an object, a lambda function) will always require a level of indirection we have to deal with. Some layers of abstractions are acceptable, for example: never call a model or service directly in a view. You could also think of implementing am event dispatcher and corresponding listeners, which would help with the loose coupling. But at some lower level you'll have to look up all listeners ...
The nature of obj is ambiguous, but I would recommend having a well-defined interface and pass it throughout your code where the class implementation of your interface would be equivalent to your 'action'. Here's an example of what that might look like in Typescript:
interface someDBInterface {
performAction() : void;
}
function process(obj : someDBInterface) {
let result = obj.performAction();
}
class action1 implements someDBInterface {
status: any
performAction() {
//db.updateTable1();
}
}
class action2 implements someDBInterface {
status : any
performAction() {
//db.updateTable1(this.status);
}
}
class action3 implements someDBInterface {
performAction() {
//May be log action 3 recieved
}
}
If this doesn't meet your requirements, feel free to reach out :)

Pass annotation to a function in Kotlin

How can I pass an annotion instance to a function?
I would like to call the java method AbstractCDI.select(Class<T> type, Annotation... qualifiers). But I don't know how to pass an annotation instance to this method.
Calling the constructor like
cdiInstance.select(MyClass::javaClass, MyAnnotation())
is not allowed and the #Annotation-Syntax cdiInstance.select(MyClass::javaClass, #MyAnnotation) is not allowed as parameter, too. How can I archive this?
When working with CDI you usually also have AnnotationLiteral available or at least you can implement something similar rather easy.
If you want to select a class using your annotation the following should do the trick:
cdiInstance.select(MyClass::class.java, object : AnnotationLiteral<MyAnnotation>() {})
Or you may need to implement your specific AnnotationLiteral-class if you require a specific value. In Java that would work as follows:
class MyAnnotationLiteral extends AnnotationLiteral<MyAnnotation> implements MyAnnotation {
private String value;
public MyAnnotationLiteral(String value) {
this.value = value;
}
#Override
public String[] value() {
return new String[] { value };
}
}
In Kotlin however, you can't implement the annotation and extend AnnotationLiteral or maybe I just did not see how (see also related question: Implement (/inherit/~extend) annotation in Kotlin).
If you rather want to continue using reflection to access the annotation then you should probably rather use the Kotlin reflection way instead:
ClassWithAnno::class.annotations
ClassWithAnno::methodWithAnno.annotations
Calling filter, etc. to get the Annotation you desire or if you know there is only one Annotation there, you can also just call the following (findAnnotation is an extension function on KAnnotatedElement):
ClassWithAnno::class.findAnnotation<MyAnnotation>()
ClassWithAnno::methodWithAnno.findAnnotation<MyAnnotation>()
One could annotate a method or field with the annotation an get it per Reflection:
this.javaClass.getMethod("annotatedMethod").getAnnotation(MyAnnotation::class.java)
Or According to Roland's suggestion the kotlin version of the above:
MyClass::annotatedMethod.findAnnotation<MyAnnotation>()!!
As suggested by Roland for CDI it is better to use AnnotationLiteral (see his post).

AspectJ OR Operator Doesn't Seem to be Functioning

I'm having a little trouble getting a logging aspect set up using SpringAOP + AspectJ. I would like an "Around" method to fire when either a class or method is annotated with the #Loggable annotation. Below is my advice code:
#Around(value = "execution( * *(..)) && target(bean) && #annotation(loggable)", argnames "bean, loggable")
public void test1(ProceedingJoinPoint method, Object bean, Loggable loggable) { }
#Around(value = "execution( * *(..)) && target(bean) && #within(loggable)", argnames "bean, loggable")
public void test2(ProceedingJoinPoint method, Object bean, Loggable loggable) { }
#Around(value = "execution( * *(..)) && target(bean) && (#annotation(loggable) || #within(loggable))", argnames "bean, loggable")
public void test3(ProceedingJoinPoint method, Object bean, Loggable loggable) { }
test1 and test2 fire. test3 does not, and it's the one that I really want. Any thoughts on why this might be?
First of all, there are syntax errors in your pointcuts. It is not lower-case argnames but argNames and you are missing an = in between parameter name and value. So it must be argNames = "bean, loggable".
Secondly if your advice returns void it will only match methods returning void as well. The more general case is to return Object in the advice to really match all methods.
Last but not least, you should see a warning which explains the problem with the third pointcut. This is displayed in your Eclipse IDE or on the AspectJ compiler's (ajc) log output:
ambiguous binding of parameter(s) loggable across '||' in pointcut
This means that you cannot say "bind one value or the other to the parameter 'loggable'". What if both conditions match? Which one should be assigned? You have two options, assuming your fully-qualified class name is de.scrum_master.app.Loggable:
A) No reference to #Loggable annotation needed:
This is the simple case. If #Loggable does not have any parameters you need to read, it is not necessary to bind it to a parameter. BTW, if you want your pointcut to also capture static methods, you should not bind target() either because the target would be null. Maybe in Spring-AOP this is irrelevant because it only works with Spring Beans anyway, but in full-featured AspectJ it would make a difference because it is more powerful.
#Around(value = "execution(* *(..)) && (#annotation(de.scrum_master.app.Loggable) || #within(de.scrum_master.app.Loggable))")
public Object withoutLoggableReference(ProceedingJoinPoint thisJoinPoint) {
Object bean = thisJoinPoint.getTarget();
System.out.println(thisJoinPoint + " -> " + bean);
return thisJoinPoint.proceed();
}
Or, equivalently:
#Around(value = "execution(* (#de.scrum_master.app.Loggable *.*)(..)) || execution(#de.scrum_master.app.Loggable * *.*(..))")
public Object withoutLoggableReference(ProceedingJoinPoint thisJoinPoint) {
Object bean = thisJoinPoint.getTarget();
System.out.println(thisJoinPoint + " -> " + bean);
return thisJoinPoint.proceed();
}
B) Reference to #Loggable annotation needed:
You have no other choice than to go with two separate pointcuts if you want to bind the annotations to parameters. Maybe you could use a utility method doing the actual logging in order to avoid code duplication in your advice.

Too few interactions in a Spock test for a Grails service

I thought I've understood Spock interactions but I have to admin that I'm still missing some pieces of the picture.
Alright, here my problem: I have a method in a Grails service which performs some operations, including a call to a void method of the same service class. Here's the code:
class myService {
void myStuff(def myObj, params) {
// do my stuff
anotherMethod(myObj)
//do my stuff again
}
void anotherMethod(myObj) {
// do other stuff
}
}
I want to be sure that myStuff method calls anotherMethod, to test and document the correct behaviour.
So, here's the test in my Spock Specification class:
void 'test myStuff method'() {
given: 'my object and some params'
// doesn't really matter what I'm doing here
MyObject myObj = new MyObject()
params = [title: 'my object']
when: 'we call myStuff()'
service.myStuff(myObj, params)
then: 'anotherMethod() is called exactly one times'
1 * service.anotherMethod(myObj)
}
}
The error I get is:
Too few invocations for:
1 * service.anotherMethod(myObj) (0 invocations)
What do you think? What's wrong?
As always, thanks in advance.
You are asking for a very special, and generally discouraged, form of mock called partial mocking where methods on the class under test are mocked. Spock supports this since 0.7, but you'll have to create a Spy() rather than a Mock(). Also note that you cannot mock private methods. For more information on spies, see the reference documentation.

How to intercept proceed() in another AspectJ aspect?

I have a situation as follows: I have a LoggingAspect with several pointcuts matching specific method executions in my main application. The corresponding advice bodies basically all look similar, causing a lot of code duplication:
void around() : download() {
String message = "Downloading, verifying (MD5) and unpacking";
SimpleLogger.verbose(message, IndentMode.INDENT_AFTER);
proceed();
SimpleLogger.verbose(message + " - done", IndentMode.DEDENT_BEFORE);
}
There is some variation, though. Sometimes the pointcut & advice have an arg or this parameter which is also printed to the log. Sometimes the "done" message is not printed if it s just a minor call not wrapping a lot of other calls, like this:
void around(BasicFilter filter) : fixFaultyLinkTargets() && this(filter) {
String message = "TOC file: checking for faulty link targets";
SimpleLogger.verbose(message, IndentMode.INDENT_AFTER);
proceed(filter);
SimpleLogger.dedent();
}
The constant thing is that I manually tell the logger
to increase the indent level after the first message is printed, i.e. directly before proceed() is called, and
to decrease the indent level before the final message is printed (if any is printed), i.e. directly after proceed() has returned.
My idea is that I would like to write a meta aspect (or call it a helper aspect) with a pointcut which intercepts the proceed() calls in LoggingAspect so as to automatically adjust the indentation level accordingly. But there seems to be no pointcut matching proceed(). I have tried call(SomeMethodInMyMainApp), even a pointcut matching everything in the logging aspect, but the pointcut matches anything I do not need, but never ever the proceed.
If anybody knows how I can do this, I would appreciate a hint or a code snippet.
An indirect way of doing this might be to intercept not the advice themselves, but the method calls (or executions) advised by those advice by creating an extra pointcut like this:
// ATTENTION: each new pointcut must also be added here
pointcut catchAll() : download() || fixFaultyLinkTargets() || ...;
void around() : catchAll() {
SimpleLogger.indent();
proceed();
SimpleLogger.dedent();
}
I would prefer another way though, without me having to remember to update the extra catchAll() pointcut everytime I change something in the logging aspect.
Suggestion wrap the proceed() in an anonymous class. And the write an aspect which adress this execution (but don't forget potential exceptions of proceed()).
My suggestion:
// AspectProceedCaller.java
public abstract class AspectProceedCaller {
public abstract Object doProceed();
};
// aspect ProceedCallerAspect.aj
aspect ProceedCallerAspect {
pointcut execProceedCaller() : execution( * AspectProceedCaller+.doProceed() );
Object around() : execProceedCaller() {
try {
SimpleLogger.indent();
return proceed();
}
finally {
SimpleLogger.dedent();
}
}
};
// Your application aspect
aspect AnyAspect {
pointcut anyPointcut() : ...;
Object around() : anyPointcut() {
AspectProceedCaller apc=new AspectProceedCaller() {
public Object doProceed() {
return proceed();
}
};
// DO Stuff before ....
Object retval = apc.doProceed();
// ... and after calling proceed.
return retval;
}
};
Best regards Marko
Please note: I am going to answer my own question here, adding more information and the additional feature of parametrisation to the solution suggested by loddar2012. Because his answer led me to the right direction, I am going to accept it even though this answer here really addresses all my needs from the original question, such as (quoting myself):
There is some variation, though. Sometimes the pointcut & advice have an arg or this parameter which is also printed to the log. Sometimes the "done" message is not printed if it s just a minor call not wrapping a lot of other calls
The basic thing we are dealing with here is what Ramnivas Laddad calls the worker object pattern in his book AspectJ in Action. His (and loddar2012's) idea is, in plain prose
to wrap a call into an instance of an anonymous class (the worker object) where
the base class or implemented interface provides a method intended to do the work,
the worker object provides a concrete implementation of the worker method and specifically calls proceed() therein,
the worker method can be called right after object creation (as we will do here) or later, maybe even in its own thread,
the worker object may be passed around or added to a scheduling queue (none of which we will need here).
An elegant solution if you need to execute your proceed() calls asynchronously would be to create instances of anonymous Runnable classes. We will use our own abstract base class LogHelper, though, because we want some more sugar in our tea, specifically the option to pass a log message and some other parameters influencing log output to each worker. So this is what I did (package names and imports not shown in the sample code):
Abstract worker base class:
abstract class LogHelper {
// Object state needed for logging
String message;
boolean logDone;
boolean indent;
LogType type;
// Main constructor
LogHelper(String message, boolean logDone, boolean indent, LogType type) {
this.message = message;
this.logDone = logDone;
this.indent = indent;
this.type = type;
}
// Convenience constructors for frequent use cases
LogHelper(String message, boolean logDone) {
this(message, logDone, true, LogType.VERBOSE);
}
LogHelper(String message) {
this(message, true);
}
// Worker method to be overridden by each anonymous subclass
abstract void log();
}
Logging advice capturing execution of worker objects:
aspect LoggingAspect
{
void around(LogHelper logHelper) :
execution(* LogHelper.log()) && this(logHelper)
{
try {
SimpleLogger.log(logHelper.type, logHelper.message);
if (logHelper.indent)
SimpleLogger.indent();
proceed(logHelper);
} finally {
if (logHelper.indent)
SimpleLogger.dedent();
if (logHelper.logDone)
SimpleLogger.log(logHelper.type, logHelper.message + " - done");
}
}
// (...)
}
As you can see, the logging advice does some things before calling proceed(logHelper) (i.e. executing the worker object's log() method) and some things afterwards, using the state information stored inside the worker object, such as
message to be logged,
log level (here called "type"),
flag specifying if indentation level should be raised before proceeding,
flag specifying if "done" message should be printed after worker execution.
Because in my use case all logged methods return void, there is no need to implement return value passing, but this would be easily possible, if necessary. The advice's return value would then just be Object and we would pass the result of proceed() back to our caller, no big deal.
Some advice capturing joinpoints to be logged and utilising parametrised worker objects to get the work done:
aspect LoggingAspect
{
// (...)
pointcut processBook() : execution(* OpenbookCleaner.downloadAndCleanBook(Book));
pointcut download() : execution(* Downloader.download());
pointcut cleanBook() : execution(* OpenbookCleaner.cleanBook(Book));
pointcut cleanChapter() : execution(* OpenbookCleaner.cleanChapter(Book, File));
pointcut initialiseTitle() : execution(* *Filter.initialiseTitle(boolean));
void around(final Book book) : processBook() && args(book) {
new LogHelper("Book: " + book.unpackDirectory) {
void log() { proceed(book); } }.log();
}
void around() : download() {
new LogHelper("Downloading, verifying (MD5) and unpacking") {
void log() { proceed(); } }.log();
}
void around() : cleanBook() {
new LogHelper("Filtering") {
void log() { proceed(); } }.log();
}
void around(final File origFile) : cleanChapter() && args(*, origFile) {
new LogHelper("Chapter: " + origFile.getName()) {
void log() { proceed(origFile); } }.log();
}
void around() : initialiseTitle() {
new LogHelper("Initialising page title", false) {
void log() { proceed(); } }.log();
}
}
The examples show how you can
instantiate an anonymous LogHelper as a worker object with one or more constructor parameters, setting its state
implement the log() method, optionally using joinpoint state bound via this() or args(),
call/run the worker object (the call will be intercepted by the logging advice's pointcut and the real logging business be done there).