Polish Javadoc and reference documentation for caching annotations

This commit documents the semantics for the `#result` SpEL expression
variable for a method that returns a Flux for @⁠Cacheable and
@⁠CachePut, both of which have always collected such a Flux's values
into a List. For such a method, `#result` refers to that List rather
than the Flux itself.

This commit addresses a number of unrelated inconsistencies in the
documentation as well.

See gh-37309
This commit is contained in:
Sam Brannen
2026-09-21 17:16:43 +02:00
parent 26de340102
commit edd497c20f
4 changed files with 47 additions and 35 deletions
@@ -216,8 +216,8 @@ documentation of your cache provider for more details.
[[cache-annotations-cacheable-reactive]]
=== Caching with CompletableFuture and Reactive Return Types
As of 6.1, cache annotations take `CompletableFuture` and reactive return types
into account, automatically adapting the cache interaction accordingly.
Cache annotations take `CompletableFuture` and reactive return types into account,
automatically adapting the cache interaction accordingly.
For a method returning a `CompletableFuture`, the object produced by that future
will be cached whenever it is complete, and the cache lookup for a cache hit will
@@ -250,6 +250,10 @@ and the cache lookup for a cache hit will be retrieved as a `Flux` (backed by a
public Flux<Book> findBooks(String author) {...}
----
This collected `List` is also what an `unless` SpEL expression sees as the `#result` for
such a method (see <<cache-spel-context,SpEL evaluation context>>); the `Flux` returned
to the caller is unaffected by this collection process.
Such `CompletableFuture` and reactive adaptation also works for synchronized caching,
computing the value only once in case of a concurrent cache miss:
@@ -415,8 +419,8 @@ other), such declarations should be avoided. Note also that such conditions shou
on the result object (that is, the `#result` variable), as these are validated up-front to
confirm the exclusion.
As of 6.1, `@CachePut` takes `CompletableFuture` and reactive return types into account,
performing the put operation whenever the produced object is available.
`@CachePut` takes `CompletableFuture` and reactive return types into account, performing
the put operation whenever the produced object is available.
TIP: When `@CachePut` is combined with `@Retryable`, the retry advice is applied
outermost, so each successful retry attempt updates the cache; a failed attempt does
@@ -465,7 +469,7 @@ trigger, the return values are ignored (as they do not interact with the cache).
not the case with `@Cacheable` which adds data to the cache or updates data in the cache
and, thus, requires a result.
As of 6.1, `@CacheEvict` takes `CompletableFuture` and reactive return types into account,
`@CacheEvict` takes `CompletableFuture` and reactive return types into account,
performing an after-invocation evict operation whenever processing has completed. As with
`@Cacheable` and `@CachePut`, for a method returning a `Flux`, all emitted elements are
collected into a `List` before the evict operation is performed. When `beforeInvocation`
@@ -28,7 +28,7 @@ import org.springframework.core.annotation.AliasFor;
/**
* Annotation indicating that a method (or all methods on a class) triggers a
* {@link org.springframework.cache.Cache#evict(Object) cache evict} operation.
* {@linkplain org.springframework.cache.Cache#evict(Object) cache evict} operation.
*
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
* <em>composed annotations</em> with attribute overrides.
@@ -84,8 +84,8 @@ public @interface CacheEvict {
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* <li>Method arguments can be accessed by index. For example, the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
@@ -118,8 +118,8 @@ public @interface CacheEvict {
/**
* Spring Expression Language (SpEL) expression used for making the cache
* eviction operation conditional. Evict that cache if the condition evaluates
* to {@code true}.
* eviction operation conditional. Evicts from the cache if the condition
* evaluates to {@code true}.
* <p>Default is {@code ""}, meaning the cache eviction is always performed.
* <p>The SpEL expression evaluates against a dedicated context that provides the
* following meta-data:
@@ -134,8 +134,8 @@ public @interface CacheEvict {
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* <li>Method arguments can be accessed by index. For example, the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
@@ -28,14 +28,14 @@ import org.springframework.core.annotation.AliasFor;
/**
* Annotation indicating that a method (or all methods on a class) triggers a
* {@link org.springframework.cache.Cache#put(Object, Object) cache put} operation.
* {@linkplain org.springframework.cache.Cache#put(Object, Object) cache put} operation.
*
* <p>In contrast to the {@link Cacheable @Cacheable} annotation, this annotation
* does not cause the advised method to be skipped. Rather, it always causes the
* method to be invoked and its result to be stored in the associated cache if the
* {@link #condition()} and {@link #unless()} expressions match accordingly. Note
* that Java8's {@code Optional} return types are automatically handled and its
* content is stored in the cache if present.
* that Java's {@code Optional} return types are automatically handled and their
* contents are stored in the cache if present.
*
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
* <em>composed annotations</em> with attribute overrides.
@@ -84,14 +84,16 @@ public @interface CachePut {
* <ul>
* <li>{@code #result} for a reference to the result of the method invocation. For
* supported wrappers such as {@code Optional}, {@code #result} refers to the actual
* object, not the wrapper</li>
* object, not the wrapper. For a method that returns a {@code Flux}, {@code #result}
* refers to a {@code List} containing all values collected from the {@code Flux},
* mirroring the value that is cached.</li>
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* <li>Method arguments can be accessed by index. For example, the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
@@ -124,7 +126,7 @@ public @interface CachePut {
/**
* Spring Expression Language (SpEL) expression used for making the cache
* put operation conditional. Update the cache if the condition evaluates to
* put operation conditional. Updates the cache if the condition evaluates to
* {@code true}.
* <p>This expression is evaluated after the method has been called due to the
* nature of the put operation and can therefore refer to the {@code result}.
@@ -134,14 +136,16 @@ public @interface CachePut {
* <ul>
* <li>{@code #result} for a reference to the result of the method invocation. For
* supported wrappers such as {@code Optional}, {@code #result} refers to the actual
* object, not the wrapper</li>
* object, not the wrapper. For a method that returns a {@code Flux}, {@code #result}
* refers to a {@code List} containing all values collected from the {@code Flux},
* mirroring the value that is cached.</li>
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* <li>Method arguments can be accessed by index. For example, the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
@@ -149,21 +153,23 @@ public @interface CachePut {
/**
* Spring Expression Language (SpEL) expression used to veto the cache put operation.
* Veto updating the cache if the condition evaluates to {@code true}.
* Vetoes updating the cache if the condition evaluates to {@code true}.
* <p>Default is {@code ""}, meaning that caching is never vetoed.
* <p>The SpEL expression evaluates against a dedicated context that provides the
* following meta-data:
* <ul>
* <li>{@code #result} for a reference to the result of the method invocation. For
* supported wrappers such as {@code Optional}, {@code #result} refers to the actual
* object, not the wrapper</li>
* object, not the wrapper. For a method that returns a {@code Flux}, {@code #result}
* refers to a {@code List} containing all values collected from the {@code Flux},
* mirroring the value that is cached.</li>
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* <li>Method arguments can be accessed by index. For example, the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
* @since 3.2
@@ -104,8 +104,8 @@ public @interface Cacheable {
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* <li>Method arguments can be accessed by index. For example, the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
@@ -138,7 +138,7 @@ public @interface Cacheable {
/**
* Spring Expression Language (SpEL) expression used for making the method
* caching conditional. Cache the result if the condition evaluates to
* caching conditional. Caches the result if the condition evaluates to
* {@code true}.
* <p>Default is {@code ""}, meaning the method result is always cached.
* <p>The SpEL expression evaluates against a dedicated context that provides the
@@ -149,8 +149,8 @@ public @interface Cacheable {
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* <li>Method arguments can be accessed by index. For example, the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
*/
@@ -158,7 +158,7 @@ public @interface Cacheable {
/**
* Spring Expression Language (SpEL) expression used to veto method caching.
* Veto caching the result if the condition evaluates to {@code true}.
* Vetoes caching of the result if the condition evaluates to {@code true}.
* <p>Unlike {@link #condition}, this expression is evaluated after the method
* has been called and can therefore refer to the {@code result}.
* <p>Default is {@code ""}, meaning that caching is never vetoed.
@@ -167,14 +167,16 @@ public @interface Cacheable {
* <ul>
* <li>{@code #result} for a reference to the result of the method invocation. For
* supported wrappers such as {@code Optional}, {@code #result} refers to the actual
* object, not the wrapper</li>
* object, not the wrapper. For a method that returns a {@code Flux}, {@code #result}
* refers to a {@code List} containing all values collected from the {@code Flux},
* mirroring the value that would be cached.</li>
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.</li>
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
* ({@code #root.targetClass}) are also available.
* <li>Method arguments can be accessed by index. For instance the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
* <li>Method arguments can be accessed by index. For example, the second argument
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
* can also be accessed by name if that information is available.</li>
* </ul>
* @since 3.2