Contradictory Cacheable And CachePut
ID |
java.spring_cacheable_with_cacheput |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
best-practice, reliability, spring |
Description
Reports a method or class reachable by both @Cacheable and @CachePut: on the same method, through a class-level annotation of the opposite kind, or on the class itself with no method involved.
Rationale
@Cacheable skips the method body and returns the cached value when one already exists for the given arguments. @CachePut always runs the method and stores the result, overwriting whatever was cached. A method under both annotations behaves unpredictably: whether the body runs at all depends on cache state rather than on the code calling it.
This is reported for four shapes: the two annotations on the same method; @CachePut on a method inside a @Cacheable class; @Cacheable on a method inside a @CachePut class; and the two annotations on the same class, with no method involved. Whether the annotations' condition() / unless() expressions happen to make the combination safe in a particular case is not evaluated — the combination is flagged regardless. Once a class carries both annotations, a method inside it that carries only one of them is not reported a second time — the class-level finding already covers it.
// Bad - contradictory: skips on hit, but also always overwrites
@Cacheable("books")
@CachePut("books")
public Book findBook(String isbn) {
return repository.lookup(isbn);
}