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

spring-boot-sample-cache.zip

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.