diff --git a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java index d9dd6a5881..acc1a12ec7 100644 --- a/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java +++ b/spring-context-support/src/main/java/org/springframework/cache/jcache/interceptor/DefaultJCacheOperationSource.java @@ -16,6 +16,8 @@ package org.springframework.cache.jcache.interceptor; +import java.util.Collection; + import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -23,7 +25,9 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; +import org.springframework.cache.interceptor.CacheOperationInvocationContext; import org.springframework.cache.interceptor.CacheResolver; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.cache.interceptor.SimpleCacheResolver; @@ -179,7 +183,7 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc @Override protected CacheResolver getDefaultExceptionCacheResolver() { if (this.exceptionCacheResolver == null) { - this.exceptionCacheResolver = new SimpleExceptionCacheResolver(getDefaultCacheManager()); + this.exceptionCacheResolver = new LazyCacheResolver(); } return this.exceptionCacheResolver; } @@ -189,4 +193,27 @@ public class DefaultJCacheOperationSource extends AnnotationJCacheOperationSourc return this.adaptedKeyGenerator; } + + /** + * Only resolve the default exception cache resolver when an exception needs to be handled. + *
A non-JSR-107 setup requires either a {@link CacheManager} or a {@link CacheResolver}. If only + * the latter is specified, it is not possible to extract a default exception {@code CacheResolver} + * from a custom {@code CacheResolver} implementation so we have to fallback on the {@code CacheManager}. + *
This gives this weird situation of a perfectly valid configuration that breaks all the sudden + * because the JCache support is enabled. To avoid this we resolve the default exception {@code CacheResolver} + * as late as possible to avoid such hard requirement in other cases. + */ + class LazyCacheResolver implements CacheResolver { + + private CacheResolver cacheResolver; + + @Override + public Collection extends Cache> resolveCaches(CacheOperationInvocationContext> context) { + if (this.cacheResolver == null) { + this.cacheResolver = new SimpleExceptionCacheResolver(getDefaultCacheManager()); + } + return this.cacheResolver.resolveCaches(context); + } + } + } diff --git a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheJavaConfigTests.java b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheJavaConfigTests.java index 4b0c4a8f12..1c72a2a433 100644 --- a/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheJavaConfigTests.java +++ b/spring-context-support/src/test/java/org/springframework/cache/jcache/config/JCacheJavaConfigTests.java @@ -61,10 +61,12 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests { return new AnnotationConfigApplicationContext(EnableCachingConfig.class); } + @Test public void fullCachingConfig() throws Exception { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(FullCachingConfig.class); + DefaultJCacheOperationSource cos = context.getBean(DefaultJCacheOperationSource.class); assertSame(context.getBean(KeyGenerator.class), cos.getKeyGenerator()); assertSame(context.getBean("cacheResolver", CacheResolver.class), @@ -102,16 +104,15 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests { } @Test - public void exceptionCacheResolverFallbacksToMainOne() { - ConfigurableApplicationContext context = new AnnotationConfigApplicationContext( - NoExceptionCacheResolverConfig.class); + public void exceptionCacheResolverLazilyRequired() { + ConfigurableApplicationContext context = + new AnnotationConfigApplicationContext(NoExceptionCacheResolverConfig.class); + try { DefaultJCacheOperationSource cos = context.getBean(DefaultJCacheOperationSource.class); assertSame(context.getBean("cacheResolver"), cos.getCacheResolver()); - assertNull(cos.getExceptionCacheResolver()); JCacheableService> service = context.getBean(JCacheableService.class); - service.cache("id"); // This call requires the cache manager to be set @@ -150,11 +151,11 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests { } } + @Configuration @EnableCaching public static class FullCachingConfig implements JCacheConfigurer { - @Override @Bean public CacheManager cacheManager() { @@ -186,6 +187,7 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests { } } + @Configuration @EnableCaching public static class EmptyConfigSupportConfig extends JCacheConfigurerSupport { @@ -195,6 +197,7 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests { } } + @Configuration @EnableCaching static class FullCachingConfigSupport extends JCacheConfigurerSupport { @@ -224,6 +227,7 @@ public class JCacheJavaConfigTests extends AbstractJCacheAnnotationTests { } } + @Configuration @EnableCaching static class NoExceptionCacheResolverConfig extends JCacheConfigurerSupport {