Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No way to specify @Pointcut that matches either a method or a class level annotation, binding expression do not short-circuit [SPR-10285] #14919

Closed
spring-issuemaster opened this issue Feb 13, 2013 · 1 comment

Comments

@spring-issuemaster
Copy link
Collaborator

@spring-issuemaster spring-issuemaster commented Feb 13, 2013

Wujek opened SPR-10285 and commented

I have a simple annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target([ElementType.TYPE, ElementType.METHOD])
public @interface Tx {

    String value() default '';
}

which I can apply either on a method or class level (which would then mean it applies to all methods). In my aspect, I have the following pointcut and advice:

@Pointcut('within(test.service..*) && !execution(* getMetaClass())')
void serviceMethods() {}

@Around(value = 'serviceMethods() && (@annotation(txmethod) || @target(txclass))', argNames = 'txmethod, txclass')
Object aroundService_inconsistentBinding(ProceedingJoinPoint pjp, Tx txmethod, Tx txclass) {
    println ">>> before $pjp.signature.name with '${txValue(txmethod, txclass)}'"
    pjp.proceed()
}

private String txValue(Tx txmethod, Tx txclass) {
    txmethod ? txmethod.value() : txclass.value()
}

and a simple usage class:

//@Tx('class')
class PersonService {

    @Tx('method')
    void method() {
    }
}

This fails at runtime with the following exception:

Caught: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personService' defined in class path resource [beans.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 inconsistent binding
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'personService' defined in class path resource [beans.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 inconsistent binding
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:532)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at Main.run(Main.groovy:5)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.lang.IllegalArgumentException: error at ::0 inconsistent binding
at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:301)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:208)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:194)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.checkReadyToMatch(AspectJExpressionPointcut.java:183)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.getClassFilter(AspectJExpressionPointcut.java:164)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:208)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:262)
at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:294)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:118)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:88)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:69)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:359)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:412)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1492)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
... 12 more

Why is the binding inconsistent?

So, I tried to replace the advice with the following:

@Around('serviceMethods() && (@annotation(tx) || @target(tx))')
Object aroundService_alwaysClassLevelUsed(ProceedingJoinPoint pjp, Tx tx) {
    println ">>> before '$pjp.signature' with '${tx.value()}'"
    pjp.proceed()
}

Now, I get a NPE:

Caught: java.lang.NullPointerException: Cannot invoke method value() on null object
java.lang.NullPointerException: Cannot invoke method value() on null object
at test.aop.MyAspect.aroundService_alwaysClassLevelUsed(MyAspect.groovy:24)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at test.service.PersonService$$EnhancerByCGLIB$$aa5c5d10.method(<generated>)
at test.service.PersonService$method.call(Unknown Source)
at Main.run(Main.groovy:8)

The problem is that the binding expression is not short-circuit, i.e., the annotation on the method is found, but spring (or is it aspectj?) binds further and bind a null Tx annotation on the class level to the parameter. This can be easily checked when the PersonService class has both class-level and method-level annotations configured.

I attach a groovy-2.1.0 and gradle-1.4 based project to help easily reproduce this issue. Just invoke

./gradlew clean run

in the project folder. I also configured remote debugging so, but it doesn't suspend the JVM - change line 78 of build.gradle accordingly.


Affects: 3.2.1

Attachments:

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Jan 12, 2019

Bulk closing outdated, unresolved issues. Please, reopen if still relevant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.