1

I’m using Spring 3.2.11.RELEASE with Java 6. I’m trying to create a custom annotation but I’m having trouble getting the logic to handle it invoked. I have created this annotation

package org.mainco.subco.myproject.util;
…
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Caching
{
    CacheEvict[] evict() default {};
    CacheEvict[] evictByPartialKey() default {};
}

Then I creating this aspect to handle processing the logic …

package org.mainco.subco.myproject.util;
…
@Aspect
@Component
public class CachingAspect 
{
    …

    @Before(value = "@annotation(Caching)", argNames = "evict")
    public void doEvictions(JoinPoint joinPoint, Caching caching)
    {
        System.out.println("called my annotation.");

But when I annotate one of my methods like so …

@Repository
@Transactional
public class MyDaoImpl implements MyDao
{
...
@org.mainco.subco.myproject.util.Caching(evict = { @CacheEvict(value="main", key="{'org.mainco.subco.sbjects.repo.ObjectsDao', 'getObjectsStates'}"), 
                                              @CacheEvict(value="main", key="{'org.mainco.subco.sbjects.repo.ObjectsDao', 'getObjectDocument', #document.id}")},
                                       evictByPartialKey = { @CacheEvict(value="main", key="{'org.mainco.subco.sbjects.repo.ObjectsDao', 'getObjectCategories'}")})
public ObjectDocument save(ObjectDocument document)
{

and then invoke that method, I don’t see my annotation invoked.

m_objectsDao.save(obmDocument);

I have included this in my Spring context file …

<aop:aspectj-autoproxy/>

What else do I need to do to get my annotation invoked?

Edit: After adding in the proper context-component scan, I now get this error with the answer suggested

Caused by: java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut 
    at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:301)
    at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:203)
    at org.springframework.aop.aspectj.AspectJExpressionPointcut.checkReadyToMatch(AspectJExpressionPointcut.java:189)
    at org.springframework.aop.aspectj.AspectJExpressionPointcut.getClassFilter(AspectJExpressionPointcut.java:167)
    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:409)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1520)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1419)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1160)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
    at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:92)
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:101)
    at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors(AnnotationAwareAspectJAutoProxyCreator.java:85)
    at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(AspectJAwareAdvisorAutoProxyCreator.java:103)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessBeforeInstantiation(AbstractAutoProxyCreator.java:276)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:922)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:894)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:448)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1419)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1160)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
    at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:92)
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:101)
    at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors(AnnotationAwareAspectJAutoProxyCreator.java:85)
    at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(AspectJAwareAdvisorAutoProxyCreator.java:103)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessBeforeInstantiation(AbstractAutoProxyCreator.java:276)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:922)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:894)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:448)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1119)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:924)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:120)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:102)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:246)
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
    at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
    at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:122)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:283)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128)
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Dave
  • 15,639
  • 133
  • 442
  • 830

1 Answers1

0

Use this advice declaration instead:

@Before(value = "execution(* org.mainco.subco.myproject..*(..)) && @annotation(caching)")
public void doEvictions(JoinPoint joinPoint, Caching caching) {
    System.out.println("annotated method called with caching=" + caching);
}

It restricts the advice join points to method execution join points having the @Caching annotation, while binding the value of the annotation to the advice context so that you can extract the annotation parameters in the advice method body.

It will output the following message:

annotated method called with caching=@org.mainco.subco.myproject.util.Caching(
evictByPartialKey=[@org.springframework.cache.annotation.CacheEvict(condition=, 
...

Also change <aop:aspectj-autoproxy/> to <aop:aspectj-autoproxy proxy-target-class="true"/> if you are planning on intercepting non-interface methods too. The default value of proxy-target-class is false, so it will create JDK proxies which can only proxy interfaces, instead of CGLIB based proxies, which can also proxy classes.

Nándor Előd Fekete
  • 6,988
  • 1
  • 22
  • 47
  • @Dave I edited my answer so it includes an important configuration issue. Please take a look at it. – Nándor Előd Fekete Mar 21 '16 at 12:27
  • HI, I changed my @Before annotation to match yours, but the annotation is still not invoked ("annotated method called" is not printed). I have the annotation on methods that are implementations of the interface, so I'm assuming I do not need to specify ", per your explanation. – Dave Mar 21 '16 at 15:39
  • Is your `save()` method with the annotation part of a bean managed by spring? Please edit and post the class declaration for that bean too. – Nándor Előd Fekete Mar 21 '16 at 16:06
  • Also, where do you invoke `save()` from? Another class? Same class? – Nándor Előd Fekete Mar 21 '16 at 16:14
  • I discovered I didn't have a conext:component-scan capturing the aspect so adding that in addition to you suggestion now gives the exception, "java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut ". I have also added the bean definition capturing the method that is annotated, per yoru request. – Dave Mar 21 '16 at 19:44
  • Please double-check that you have the same advice declaration (pointcut expression AND method declaration) as I have in my answer. That error message you're getting means that you have a method parameter at your advice method which is not bound by the pointcut expression. – Nándor Előd Fekete Mar 21 '16 at 20:05
  • You’re talking about the “doEvcitions” method, right? I have the two parameters org.aspectj.lang.JoinPoint and org.mainco.subco.myproject.util.Caching if that was what you meant. But I did have to change your declaration to "execution(* org.mainco.subco.myproject..*(..)) && @annotation(org.mainco.subco.myproject.util.Caching)" because when I just had “annotation(caching),” nothing happened. – Dave Mar 21 '16 at 20:15
  • Use the exact declaration I provided. It has a reason it's not referring to the type but the method argument's name instead. That's how you bind the annotation value to the context, so that you can extract the annotation's value in the method body. The name in the pointcut expression and the name of the advice method argument (`caching` in this case) must match. – Nándor Előd Fekete Mar 21 '16 at 20:18
  • Ok, I did this, but changing the @Before value to "execution(* org.mainco.subco.myproject..*(..)) && @annotation(caching)” does not cause the method “doEvictions” to be invoked (i.e. there is no System.out.prinln statement called), even after adding proxy-target-class="true". – Dave Mar 21 '16 at 21:03
  • Place a breakpoint at this line `m_objectsDao.save(obmDocument);` and see if m_objectsDao is a proxy. It must be a proxy if you're using Spring AOP and not AspectJ compile-time weaving or load-time weaving. If it's not a proxy, Spring AOP didn't pick up the bean. This starts looking like an impossible task to guess what's wrong with your config. You should put up an [mcve] on github. – Nándor Előd Fekete Mar 21 '16 at 21:28
  • The class name for what you asked is “org.mainco.subco.objects.repo.ObjectsDaoImpl$$EnhancerBySpringCGLIB$$c62faf52”. The module org.springframework:spring-aop:jar:3.2.11.RELEASE is included in my project as well as org.aspectj:aspectjweaver:jar:1.8.6. I genuinely appreciate your help on this. – Dave Mar 21 '16 at 21:59
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/106956/discussion-between-nandor-elod-fekete-and-dave). – Nándor Előd Fekete Mar 21 '16 at 22:00