Q:

MongoDB Spring Data Repository - Cache methods

I need to have calls to MongoDB cached using spring @Cacheable annotation:
public interface SiteRepository extends PagingAndSortingRepository<Site, String>{
    @Cacheable
    List<Site> findByStatus(Site. Status status);
}

Unfortunately, annotating any method in the interface with @Cacheable causes the following exception:

Nov 22, 2014 7:11:06 PM org.apache.catalina.core. ApplicationContext
  log SEVERE: StandardWrapper. Throwable
  org.springframework.beans.factory. BeanCreationException: Error
  creating bean with name 'example': Injection of autowired dependencies
  failed; nested exception is
  org.springframework.beans.factory. BeanCreationException: Could not
  autowire field: com.example.repositories.mongodb. SiteRepository
  com.example.siteRepo; nested exception is
  org.springframework.beans.factory. BeanCreationException: Error
  creating bean with name 'siteRepository': Post-processing of
  FactoryBean's singleton object failed; nested exception is
  org.springframework.aop.framework. AopConfigException: Could not
  generate CGLIB subclass of class [class com.sun.proxy.$Proxy92]:
  Common causes of this problem include using a final class or a
  non-visible class; nested exception is
  java.lang. IllegalArgumentException: Cannot subclass final class class
  com.sun.proxy.$Proxy92    at
  org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
    at
  org.springframework.beans.factory.support. AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1147)
    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:191)
    at
  org.springframework.beans.factory.support. DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:633)
    at
  org.springframework.context.support. AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at
  org.springframework.context.support. AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at
  org.springframework.web.servlet. FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:651)
    at
  org.springframework.web.servlet. FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:602)
    at
  org.springframework.web.servlet. FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:665)
    at
  org.springframework.web.servlet. FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:521)
    at
  org.springframework.web.servlet. FrameworkServlet.initServletBean(FrameworkServlet.java:462)
    at
  org.springframework.web.servlet. HttpServletBean.init(HttpServletBean.java:136)
    at javax.servlet. GenericServlet.init(GenericServlet.java:160)   at
  org.apache.catalina.core. StandardWrapper.initServlet(StandardWrapper.java:1189)
    at
  org.apache.catalina.core. StandardWrapper.loadServlet(StandardWrapper.java:1103)
    at
  org.apache.catalina.core. StandardWrapper.load(StandardWrapper.java:1010)
    at
  org.apache.catalina.core. StandardContext.loadOnStartup(StandardContext.java:4935)
    at
  org.apache.catalina.core. StandardContext$3.call(StandardContext.java:5262)
    at
  org.apache.catalina.core. StandardContext$3.call(StandardContext.java:5257)
    at java.util.concurrent. FutureTask.run(Unknown Source)  at
  java.util.concurrent. ThreadPoolExecutor.runWorker(Unknown Source)     at
  java.util.concurrent. ThreadPoolExecutor$Worker.run(Unknown Source)    at
  java.lang. Thread.run(Unknown Source) Caused by:
  org.springframework.beans.factory. BeanCreationException: Could not
  autowire field: com.example.repositories.mongodb. SiteRepository
  com.example.siteRepo; nested exception is
  org.springframework.beans.factory. BeanCreationException: Error
  creating bean with name 'siteRepository': Post-processing of
  FactoryBean's singleton object failed; nested exception is
  org.springframework.aop.framework. AopConfigException: Could not
  generate CGLIB subclass of class [class com.sun.proxy.$Proxy92]:
  Common causes of this problem include using a final class or a
  non-visible class; nested exception is
  java.lang. IllegalArgumentException: Cannot subclass final class class
  com.sun.proxy.$Proxy92    at
  org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:517)
    at
  org.springframework.beans.factory.annotation. InjectionMetadata.inject(InjectionMetadata.java:87)
    at
  org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286)
    ... 27 more Caused by:
  org.springframework.beans.factory. BeanCreationException: Error
  creating bean with name 'siteRepository': Post-processing of
  FactoryBean's singleton object failed; nested exception is
  org.springframework.aop.framework. AopConfigException: Could not
  generate CGLIB subclass of class [class com.sun.proxy.$Proxy92]:
  Common causes of this problem include using a final class or a
  non-visible class; nested exception is
  java.lang. IllegalArgumentException: Cannot subclass final class class
  com.sun.proxy.$Proxy92    at
  org.springframework.beans.factory.support. FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:115)
    at
  org.springframework.beans.factory.support. AbstractBeanFactory.getObjectForBeanInstance(AbstractBeanFactory.java:1465)
    at
  org.springframework.beans.factory.support. AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:304)
    at
  org.springframework.beans.factory.support. AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
    at
  org.springframework.beans.factory.support. DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:917)
    at
  org.springframework.beans.factory.support. DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:860)
    at
  org.springframework.beans.factory.support. DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:775)
    at
  org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:489)
    ... 29 more Caused by:
  org.springframework.aop.framework. AopConfigException: Could not
  generate CGLIB subclass of class [class com.sun.proxy.$Proxy92]:
  Common causes of this problem include using a final class or a
  non-visible class; nested exception is
  java.lang. IllegalArgumentException: Cannot subclass final class class
  com.sun.proxy.$Proxy92    at
  org.springframework.aop.framework. CglibAopProxy.getProxy(CglibAopProxy.java:218)
    at
  org.springframework.aop.framework. ProxyFactory.getProxy(ProxyFactory.java:109)
    at
  org.springframework.aop.framework.autoproxy. AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:477)
    at
  org.springframework.aop.framework.autoproxy. AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:362)
    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.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1656)
    at
  org.springframework.beans.factory.support. FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:112)
    ... 36 more Caused by: java.lang. IllegalArgumentException: Cannot
  subclass final class class com.sun.proxy.$Proxy92     at
  org.springframework.cglib.proxy. Enhancer.generateClass(Enhancer.java:446)
    at
  org.springframework.cglib.transform. TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
    at
  org.springframework.cglib.core. DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at
  org.springframework.cglib.core. AbstractClassGenerator.create(AbstractClassGenerator.java:216)
    at
  org.springframework.cglib.proxy. Enhancer.createHelper(Enhancer.java:377)
    at org.springframework.cglib.proxy. Enhancer.create(Enhancer.java:285)
    at
  org.springframework.aop.framework. CglibAopProxy.getProxy(CglibAopProxy.java:206)
    ... 43 more

I am looking for a way to cache calls to DB (which are quite expensive).  Any idea? 

A:

From the Spring documentation on caches:

Spring recommends that you only annotate concrete classes (and methods
  of concrete classes) with the @Cache* annotation, as opposed to
  annotating interfaces.  You certainly can place the @Cache* annotation
  on an interface (or an interface method), but this works only as you
  would expect it to if you are using interface-based proxies.  The fact
  that Java annotations are not inherited from interfaces means that if
  you are using class-based proxies ( proxy-target-class="true") or the
  weaving-based aspect ( mode="aspectj"), then the caching settings are
  not recognized by the proxying and weaving infrastructure, and the
  object will not be wrapped in a caching proxy, which would be
  decidedly bad. 

Probably your cache configuration is colliding with the way that Spring creates implementations of your repository interfaces at runtime. 
You could review your caching configuration to make it play nice with spring data (see here for different caching configuration options). 
Or, you could do this:
public interface SiteRepository extends PagingAndSortingRepository<Site, String>{
    List<Site> findByStatus(Site. Status status);
}

@Service
public class CachedSiteService {

    @Autowired
    private SiteRepository siteRepository;

    @Cacheable("sites")
    List<Site> findByStatus(Site. Status status) {
        return siteRepository.findByStatus(status);
    }

}

