Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 613 Vote(s) - 3.58 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How do I tell Spring cache not to cache null value in @Cacheable annotation

#1
Is there a way to specify that if the method returns null value, then don't cache the result in @Cacheable annotation for a method like this?

@Cacheable(value="defaultCache", key="#pk")
public Person findPerson(int pk) {
return getSession.getPerson(pk);
}

Update:
here is the JIRA issue submitted regarding caching null value last November, which hasn't resolved yet:
[\[#SPR-8871\] @Cachable condition should allow referencing return value - Spring Projects Issue Tracker][1]


[1]:

[To see links please register here]

Reply

#2
**update** this answer is outdated now, for Spring 3.2 and later see Tech Trip's [answer](

[To see links please register here]

), OP: feel free to mark it as accepted.

I don't think that it's possible(even though there's conditional Cache eviction in Spring that can be executed after the method invocation with `@CacheEvict` parameter *beforeInvocation* set to false, which is default value) examining the `CacheAspectSupport` class shows that the returned value is not stored anywhere before the `inspectAfterCacheEvicts(ops.get(EVICT));` call.


protected Object execute(Invoker invoker, Object target, Method method, Object[] args) {
// check whether aspect is enabled
// to cope with cases where the AJ is pulled in automatically
if (!this.initialized) {
return invoker.invoke();
}

// get backing class
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(target);
if (targetClass == null && target != null) {
targetClass = target.getClass();
}
final Collection<CacheOperation> cacheOp = getCacheOperationSource().getCacheOperations(method, targetClass);

// analyze caching information
if (!CollectionUtils.isEmpty(cacheOp)) {
Map<String, Collection<CacheOperationContext>> ops = createOperationContext(cacheOp, method, args, target, targetClass);

// start with evictions
inspectBeforeCacheEvicts(ops.get(EVICT));

// follow up with cacheable
CacheStatus status = inspectCacheables(ops.get(CACHEABLE));

Object retVal = null;
Map<CacheOperationContext, Object> updates = inspectCacheUpdates(ops.get(UPDATE));

if (status != null) {
if (status.updateRequired) {
updates.putAll(status.cUpdates);
}
// return cached object
else {
return status.retVal;
}
}

retVal = invoker.invoke();

inspectAfterCacheEvicts(ops.get(EVICT));

if (!updates.isEmpty()) {
update(updates, retVal);
}

return retVal;
}

return invoker.invoke();
}
Reply

#3
If Spring annotation

@Cacheable(value="defaultCache", key="#pk",unless="#result!=null")

does not work ,you can try:

@CachePut(value="defaultCache", key="#pk",unless="#result==null")

It works for me.

Reply

#4
Hooray, as of Spring 3.2 the framework allows for this using Spring SpEL and `unless`. Note from the java doc for [`Cacheable` element `unless`][1]:

> Spring Expression Language (SpEL) expression used to veto method caching. Veto caching the result if the condition evaluates to true.
>
> Unlike condition(), this expression is evaluated after the method has been called and can therefore refer to the result. Default is "", meaning that caching is never vetoed.

The important aspect is that `unless` is evaluated after the method has been called. This makes perfect sense because the method will never get executed if the key is already in the cache.

So in the above example you would simply annotate as follows (#result is available to test the return value of a method):

@Cacheable(value="defaultCache", key="#pk", unless="#result == null")
public Person findPerson(int pk) {
return getSession.getPerson(pk);
}

I would imagine this condition arises from the use of pluggable cache implementations such as Ehcache which allows caching of nulls. Depending on your use case scenario this may or may not be desirable.


[1]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through