This question would not have existed if AspectJ worked the same way as EJB interceptors work.
Consider basic scenario the EJB-interceptor way:
@AroundInvoke
public Object log(final InvocationContext ctx) throws Exception {
// do stuff before
final Object result = ctx.proceed();
// do stuff after
return result;
}
Now I need the Method object that's being intercepted. Here I can simply do this:
Method method = ctx.getMethod();
And that's it, after this I will be inspecting intercepted method's annotations.
Now I'm working with application which is deployed to servlet container (Tomcat) and hence has no EJBs. AOP in it is implemented using Spring + AspectJ.
The around method looks like this:
@Around("execution(* foo.bar.domain.integration.database.dao..*(..))")
public Object log(final ProceedingJoinPoint pjp) throws Throwable {
// do stuff before
final Object result = pjp.proceed();
// do stuff after
return result;
}
Here I can no longer do this:
Method method = pjp.getMethod(); // no such method exists
Instead I am forced to get the Method object myself using reflection as follows:
final String methodName = pjp.getSignature().getName();
final Object[] arguments = pjp.getArgs();
final Class[] argumentTypes = getArgumentTypes(arguments);
final Method method = pjp.getTarget().getClass().getMethod(methodName, argumentTypes);
It works until you want to get a hold of the template method:
@Transactional
public <T extends Identifiable> T save(T t) {
if (null == t.getId()) {
create(t);
return t;
}
return update(t);
}
Assume you invoke this method as follows:
Person person = new Person("Oleg");
personService.save(person);
You will receive a:
Caused by: java.lang.NoSuchMethodException: foo.bar.domain.integration.database.dao.EntityService.save(foo.bar.domain.entity.Person)
which is thrown by:
pjp.getTarget().getClass().getMethod()
The problem is that generics do not exist at runtime and the actual method signature is:
public Identifiable save(Identifiable t) {}
final Class[] argumentTypes will contain one element and its type will be Person. So this call:
pjp.getTarget().getClass().getMethod(methodName, argumentTypes);
will be looking up method:
save(Person p)
and will not find it.
So the question is: how do I get instance of java's template Method object which represents the exact method that has been intercepted?
I guess one of the ways is to do it the brute force way: get arguments superclasses/interfaces and try getting the method using those types until you no longer get the NoSuchMethodException but that is plain ugly. Is there a normal clean way I can do that?