I have a method which has reactive code in it (RxJava).
I have an Aspect @around wrapped around it.
The setup is fine, it does the print out as follows.
But it happens before the method is even subscribed to.
Is there a way we could set it up such that the Aspect is going to only kick off after the method gets subscribed to?
My Aspect class
@Aspect
public class AspectClass {
@Around("@annotation(someLogger) && execution(* *(..))")
public Object getMockedData(ProceedingJoinPoint pjp, SomeLogger someLogger) throws Throwable {
System.out.println("from aspect start: " + Thread.currentThread().getName());
Object actualResponse = pjp.proceed(methodArguments);
System.out.println("from aspect close: " + Thread.currentThread().getName());
return actualResponse;
}
}
The custom annotation
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SomeLogger {
String name() default "";
}
The method that gets annotated to use aspect.
@SomeLogger(name = "name")
public Single<Response> add(Request request) {
return sample(request)
.flatMapObservable(resultSet -> Observable.from(resultSet.getRows()))
.map(row -> Response.builder()
.sampleTimestamp(localDateTime(row.getInstant("sample")))
.build()
)
.first()
.toSingle()
.doOnSubscribe(() -> System.out.println("method is subbed: add " + Thread.currentThread().getName()))
.doOnEach(n -> System.out.println("method ends and doOnEach: add " + Thread.currentThread().getName()));
}
As mentioned the print lines in the aspect class gets printed even before subscription which is wrong.
Thus this is the current wrong order for the print.
from aspect start: eventloop-thread-3
from aspect close: eventloop-thread-3
method is subbed: add eventloop-thread-3
method ends and doOnEach: add eventloop-thread-3
I was expecting the following order.
method is subbed: add eventloop-thread-3
from aspect start: eventloop-thread-3
method ends and doOnEach: add eventloop-thread-3
from aspect close: eventloop-thread-3
Is this possible?
This is the closest question I found with regards to this. Writing Aspects For Reactive Pipelines
But that question is based off Spring. Also there is a line in that answer:
You do need to make the aspect aware of the asynchronous situation.
Sounds like this is what I need to do, but how can I do it? Thanks for any advice.
--- UPDATE after suggestion ---
To note, am using AspectJ not Spring.
This doesn't work cos variable proceed is null before subscription.
Thus I added a null check. But we are only going to enter here once.
Thus proceed.doOnSubscribe() never happens.
@Before("@annotation(someLogger) && execution(* *(..))")
public void before(JoinPoint jp, SomeLogger someLogger) throws Throwable {
Object[] args = jp.getArgs();
Single<?> proceed = ((Single<?>) ((ProceedingJoinPoint) jp).proceed(args));
if(proceed != null) {
proceed.doOnSubscribe(() -> System.out.println("doOnSubscribe in before"));
}
// this will print before a subscription
// as expected before which is not what I want.
System.out.println("inside before");
}
Further attempt:
At least in theory was expecting this to work. But throws AJC Compiler errors.
@Around("@annotation(someLogger) && execution(* *(..))")
public Object around(ProceedingJoinPoint pjp, SomeLogger someLogger) {
// return pjp.proceed(methodArguments); // compiles fine if no operations on method
return pjp.proceed(methodArguments)
.doOnSubscribe(() -> System.out.println("method is subbed: add " + Thread.currentThread().getName()))
.doOnEach(n -> System.out.println("method ends and doOnEach: add " + Thread.currentThread().getName()));
}