I had written an aspect as part of an application using Spring AOP/AspectJ annotations similar to below aspect:
@Aspect
@Component
public class LoggingAspect {
@Around("@annotation(loggable)")
public Object log(final ProceedingJoinPoint joinPoint, final Loggable loggable) throws Throwable {
//log method arguments
try {
Object returnValue = joinPoint.proceed();
// log return value
return returnValue;
} catch (Exception ex) {
// publish exception metrics to some other system
throw ex;
}
}
}
Now I want to use this same aspect in another project, but this project uses Guice instead of Spring.
I was reading about Guice AOP which requires aspect to implement the MethodInterceptor interface and thus I will need to implement the below method:
Object invoke(MethodInvocation methodInvocation) throws Throwable;
What I was thinking was to modify the already existent aspect to implement the MethodInterceptor and internally call the log method. Something like below:
@Aspect
@Component
public class LoggingAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
// call already defined log method, but that method expects a ProceedingJoinPoint, however
// I get MethodInvocation as input parameter in this method
}
// already defined log method
@Around("@annotation(loggable)")
public Object log(final ProceedingJoinPoint joinPoint, final Loggable loggable) throws Throwable {
......
.....
}
But due to incompatible type between two methods, I am unable to proceed.
Is there a way I can reuse the existing code instead of writing a brand new aspect with duplicate code to support Guice?
If I understand correctly, you want to reverse the control flow, which can be done with callbacks.
@Aspect
@Component
class LoggingAspect implements MethodInterceptor {
@Around("@annotation(loggable)")
public Object log(final ProceedingJoinPoint joinPoint, final Loggable loggable) throws Throwable {
return log(joinPoint::getArgs, () -> joinPoint.proceed(joinPoint.getArgs()));
}
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
return log(methodInvocation::getArguments, methodInvocation::proceed);
}
public Object log(Supplier<Object[]> arguments, Supplier<Object[]> proceed) {
Object[] args = arguments.get();
//log method arguments
try {
Object returnValue = proceed.get();
// log return value
return returnValue;
} catch (Exception ex) {
// publish exception metrics to some other system
throw ex;
}
}
}
BTW do you intentionally catch only Exception
and not Throwable
? Error
s would not be logged.