Before Spring 4.0 it was possible to use both @CachePut and @Cacheable annotation when they have a mutually exclusive condition.
This was also explicited in the reference documentation:
Note that using @CachePut and @Cacheable annotations on the same method is generally discouraged because they have different behaviors. While the latter causes the method execution to be skipped by using the cache, the former forces the execution in order to execute a cache update. This leads to unexpected behavior and with the exception of specific corner-cases (such as annotations having conditions that exclude them from each other), such declarations should be avoided.
Changed the Priority to Major, since a workaround is possible (by using two methods), but I think this is not a Minor issue since can have a major performance impact on previously working applications (this is my case).
Adding the result attribute makes it hard to track if the condition passes until this result is available. Because we are now deferring the evaluation of the condition, any cache put is taken into account to figure out if the method has to be invoked (regardless of that condition).
That being said, using a cache should be transparent and your application should work exactly the same way with or without the cache. Why are you exposing those notions in your API? Can you elaborate a bit more on your use case? Thanks.
The data cached by our method can change outside of our application control. Usually is perfectly fine to use an outdated value, but at specific points we need to ensure that we have the new data (and to update the cache at those points).
Our program works perfectly well (outside of performance issue) without the cache, but to obtain this we had to "mark" the calls that need to have fresh data, and those that can use old data.
We could do this by using two methods, one with the @Cacheable annotation and one with the @Cache put. We will use this now that we are upgrading to Spring 4.0, but with Spring 3.x this method worked and was mentioned in the documentation so we used it.
If I understand the problem is that since @CachePut can use #result in the condition, it's not possible to evaluate it without calling the real method.
What if we add a limitation? If you have both @Cacheable and @CachePut on a method you cannot use #result in the condition.
This never worked so there isn't a compatibility problem and it allow to evaluate the @CachePut condition before calling the method if we have a @Cacheable annotation.
If this is not possible I think the following action should be taken:
Change the reference documentation to clearly state that it's never possible to use both @Cacheable and @CachePut in a method, without any exception.
As you have suspected yourself, we can validate the @CachePut condition upfront if it does not use the result variable. When this is the case (as in your example), the caching behaviour works now as expected. I have refreshed the documentation to mention that point.
On a personal note, I think that calling a different method (with an explicit name) is better than calling the same method with a different flag as an argument. That being said, this used to work and this capability has now been restored on master and will be backported soon.