spring-framework icon indicating copy to clipboard operation
spring-framework copied to clipboard

Support annotation on the method of interface in spring-aop integrate with aspectj

Open cdfive opened this issue 6 years ago • 5 comments

Affects: spring-aop:5.0.9.RELEASE, spring-boot-starter-aop:2.0.5.RELEASE

public interface FooService {
  @MyAnnotation 
  void hello();
}
public class FooServiceImpl implements FooService {
  void hello();
}
public class MyAspect {
  @Pointcut("@annotation(MyAnnotation")
     public void myPointcut() {
   }
  @Around("myPointcut()")
  public Object around(ProceedingJoinPoint pjp) throws Throwable {
     ...
  }
}
@Configuration
public class MyAopConfiguration {
    @Bean
    public MyAspect myAspect () {
        return new MyAspect();
    }
}

Using spring-aop like the code above, it doesn't work, around(ProceedingJoinPoint pjp) never execute.

If put the @MyAnnotation on the implement method of FooServiceImpl, it works.

public interface FooService { 
  void hello();
}
public class FooServiceImpl  implements FooService {
  @MyAnnotation
  void hello();
}

Learned from two questions in stackoverflow: https://stackoverflow.com/questions/6594457/aspectj-annotation-pointcut-not-triggered-for-interface-annotations https://stackoverflow.com/questions/7178782/aspectj-pointcut-for-methods-that-override-an-interface-method-with-an-annotati

According to the Java 5 specification, non-type annotations are not inherited, and annotations on types are only inherited if they have the @Inherited meta-annotation.

It's seems that it's unpossible in spring-aop.

I tried the code without spring-aop, only using aspectjweaver 1.7.4, and add a aop.xml in the resources/META-INF

<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
    <aspects>
        <aspect name="com.xxx.MyAspect"/>
    </aspects>
    <weaver options="-verbose -showWeaveInfo -Xset:weaveJavaxPackages=true" />
</aspectj>

and add JVM parameter: -javaagent:xxx/aspectjweaver-1.7.4.jar It works no matter the @MyAnnotation is on the interface or class. And then in around(ProceedingJoinPoint pjp), I can get the @MyAnnotation with the api of pjp, like this:

MethodSignature signature = (MethodSignature)joinPoint.getSignature();
Class<?> targetClass = pjp.getTarget().getClass();
Method method = targetClass.getDeclaredMethod(signature.getName(), signature.getMethod().getParameterTypes());
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);

or 

Class<?>[] interfaces = targetClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
   Method method = targetClass.getDeclaredMethod(signature.getName(), 
   signature.getMethod().getParameterTypes());
   MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
}

So I think spring-aop may also have way to solve this problem, since it's a common scene for users to add annotation on the method of interface.

Something in AopUtils#getMostSpecificMethod,AspectJExpressionPointcut#getShadowMatch(Method targetMethod, Method originalMethod) may be about, I'm not sure.

Could you please give some help?

cdfive avatar Jan 26 '19 13:01 cdfive

I'm afraid there is not much we can do about this on Spring's side since those annotation checks are performed by AspectJ itself which focuses on the concrete class to be weaved and generally follows Java language semantics where interface-declared annotations are not inherited.

jhoeller avatar Dec 29 '23 12:12 jhoeller

Reopening again after re-reading the details and noticing that the AspectJ compiler does seem to behave differently there. We should investigate how it does that, maybe we can imitate that via custom ShadowMatch checks indeed.

jhoeller avatar Dec 29 '23 14:12 jhoeller

Any advancement on this ?

constantinLu avatar Mar 27 '24 14:03 constantinLu

it would be amazing to be able to listen to annotated methods from interfaces'

FiruzzZ avatar Jul 10 '24 17:07 FiruzzZ

Also in need

NicoStrecker avatar Aug 14 '24 13:08 NicoStrecker