Этот вопрос не существовал бы, если бы AspectJ работал так же, как работают перехватчики EJB.
Рассмотрим базовый сценарий EJB-перехватчиком:
@AroundInvoke
public Object log(final InvocationContext ctx) throws Exception {
// do stuff before
final Object result = ctx.proceed();
// do stuff after
return result;
}
Теперь мне нужен объект Method, который перехватывается. Здесь я могу просто сделать это:
Method method = ctx.getMethod();
И все, после этого я буду проверять аннотации перехваченного метода.
Теперь я работаю с приложением, которое развернуто в контейнере сервлетов (Tomcat) и, следовательно, не имеет EJB. AOP в нем реализован с использованием Spring + AspectJ.
Метод округления выглядит следующим образом:
@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;
}
Здесь я больше не могу сделать это:
Method method = pjp.getMethod(); // no such method exists
Вместо этого я вынужден сам получить объект Method, используя отражение следующим образом:
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);
Это работает, пока вы не захотите овладеть методом шаблона:
@Transactional
public <T extends Identifiable> T save(T t) {
if (null == t.getId()) {
create(t);
return t;
}
return update(t);
}
Предположим, вы вызываете этот метод следующим образом:
Person person = new Person("Oleg");
personService.save(person);
Вы получите:
Caused by: java.lang.NoSuchMethodException: foo.bar.domain.integration.database.dao.EntityService.save(foo.bar.domain.entity.Person)
который выбрасывается:
pjp.getTarget().getClass().getMethod()
Проблема в том, что во время выполнения универсальных шаблонов не существует, а фактическая сигнатура метода:
public Identifiable save(Identifiable t) {}
final Class [] argumentsTypes будет содержать один элемент, а его тип будет Person. Итак, этот звонок:
pjp.getTarget().getClass().getMethod(methodName, argumentTypes);
будет искать метод:
save(Person p)
и не найдет его.
Итак, вопрос в том, как мне получить экземпляр java template Метод объекта, представляющий точный метод, который был перехвачен?
Полагаю, один из способов - сделать это методом грубой силы:
получите аргументы суперклассы / интерфейсы и попробуйте получить метод, использующий эти типы, пока вы больше не получите исключение NoSuchMethodException, но это выглядит ужасно. Есть ли нормальный чистый способ, которым я могу это сделать?