Affects: Spring Context 4.3.4 and higher


Trying to use @CachePut on a method that might return null.

@CachePut(cacheNames = Constants.Caches.USER, key = "#result.id", unless = "#result == null")
public MyObject doSomething();

You would expect the key expression not to be evaluated if the unless condition is true but this is not happening. The key is being evaluated before the unless condition is evaluated which leads to a

org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 0): Property or field 'id' cannot be found on null

                if (cacheHit != null && cachePutRequests.isEmpty() && !hasCachePut(contexts)) {
            // If there are no put requests, just use the cache hit
            cacheValue = cacheHit.get();
            returnValue = wrapCacheValue(method, cacheValue);
        }
        else {
            // Invoke the method if we don't have a cache hit
            returnValue = invokeOperation(invoker);
            cacheValue = unwrapReturnValue(returnValue);
        }

        // Collect any explicit @CachePuts
        collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);

        // Process any collected put requests, either from @CachePut or a @Cacheable miss
        for (CachePutRequest cachePutRequest : cachePutRequests) {
            cachePutRequest.apply(cacheValue);
        }

The collectPutRequests tries to evaluate the key if the condition passes (there is no condition). I think the keys need to be evaluated only if unless is false?

Comment From: solarmicrobe

+1 Just hit this today. Luckily for me it is in a demo application and I can submit with just a javadoc on my function.

Comment From: sbrannen

I've edited your comment to improve the formatting. You might want to check out this Mastering Markdown guide for future reference.

Comment From: snicoll

Closing in favor of PR #22769