I am trying this project: https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-cache to test out Caffeine cache with refreshAfterWrite settings. See the attached modified project. As soon as I use refreshAfterWrite in application.properties I got the following stack trace:
2016-12-01 14:48:16.065 INFO 14246 --- [ main] s.cache.SampleCacheApplicationTests : Started SampleCacheApplicationTests in 15.355 seconds (JVM running for 17.169)
java.lang.IllegalStateException: refreshAfterWrite requires a LoadingCache
at com.github.benmanes.caffeine.cache.Caffeine.requireState(Caffeine.java:181)
at com.github.benmanes.caffeine.cache.Caffeine.requireNonLoadingCache(Caffeine.java:894)
at com.github.benmanes.caffeine.cache.Caffeine.build(Caffeine.java:802)
at org.springframework.cache.caffeine.CaffeineCacheManager.createNativeCaffeineCache(CaffeineCacheManager.java:210)
at org.springframework.cache.caffeine.CaffeineCacheManager.createCaffeineCache(CaffeineCacheManager.java:197)
at org.springframework.cache.caffeine.CaffeineCacheManager.getCache(CaffeineCacheManager.java:183)
at sample.cache.SampleCacheApplicationTests.validateCache(SampleCacheApplicationTests.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
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:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
2016-12-01 14:48:16.122 INFO 14246 --- [ Thread-1] o.s.w.c.s.GenericWebApplicationContext : Closing org.springframework.web.context.support.GenericWebApplicationContext@298a5e20: startup date [Thu Dec 01 14:48:11 AEDT 2016]; root of context hierarchy
Comment From: shahid21st
Same error happens for Guava.
Comment From: snicoll
Thanks for getting in touch, but it feels like this is a question that would be better suited to Stack Overflow. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add some more details if you feel this is a genuine bug.
It should be pretty obvious from the stacktrace that this exception comes from Guava/Caffeine. There's nothing Spring Boot can do about that.
Comment From: ben-manes
The issue is that no cache loader has been configured. You'd need to use Java configuration for that. The annotations use the get(key, function) if sync or else get/put, so there is no attached loader for us to automatically refresh with.
Comment From: q3769
Thanks for getting in touch, but it feels like this is a question that would be better suited to Stack Overflow. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add some more details if you feel this is a genuine bug.
It should be pretty obvious from the stacktrace that this exception comes from Guava/Caffeine. There's nothing Spring Boot can do about that.
I think this is a legitimate bug/enhancement on Spring Boot side. Spring Boot already supports "expireAfterWrite" which needs direct usage of Caffeine API. If during the Spring Boot cache abstraction, using Caffeine native API is fair game, then there is no reason not to support "refreshAfterWrite" as the same kind of abstraction. Under the hood, it's just a different way of using the Caffeine API. In the case of "refreshAfterWrite", a Caffeine cache loader is needed (and is currently missing). The abstraction should be "translating" the very same user method that is being annotated by @Cacheable
into the cache loader for the underlying Caffeine cache. In that sense, it is exactly the kind of "abstraction" Spring Boot aims to provide.