From edd497c20f4bc6c70f26d52979a015cd32d0aae1 Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Mon, 21 Sep 2026 17:04:50 +0200 Subject: [PATCH] Polish Javadoc and reference documentation for caching annotations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../pages/integration/cache/annotations.adoc | 14 +++++--- .../cache/annotation/CacheEvict.java | 14 ++++---- .../cache/annotation/CachePut.java | 34 +++++++++++-------- .../cache/annotation/Cacheable.java | 20 ++++++----- 4 files changed, 47 insertions(+), 35 deletions(-) diff --git a/framework-docs/modules/ROOT/pages/integration/cache/annotations.adoc b/framework-docs/modules/ROOT/pages/integration/cache/annotations.adoc index 276dd91e5c2..763fa8fd645 100644 --- a/framework-docs/modules/ROOT/pages/integration/cache/annotations.adoc +++ b/framework-docs/modules/ROOT/pages/integration/cache/annotations.adoc @@ -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 findBooks(String author) {...} ---- +This collected `List` is also what an `unless` SpEL expression sees as the `#result` for +such a method (see <>); 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` diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java b/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java index 00841d7a14a..41e5cff8ebc 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java @@ -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. * *

This annotation may be used as a meta-annotation to create custom * composed annotations with attribute overrides. @@ -84,8 +84,8 @@ public @interface CacheEvict { * affected cache(s) respectively. *

  • Shortcuts for the method name ({@code #root.methodName}) and target class * ({@code #root.targetClass}) are also available. - *
  • 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 + *
  • 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.
  • * */ @@ -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}. *

    Default is {@code ""}, meaning the cache eviction is always performed. *

    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. *

  • Shortcuts for the method name ({@code #root.methodName}) and target class * ({@code #root.targetClass}) are also available. - *
  • 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 + *
  • 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.
  • * */ diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java b/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java index 74f1bf55003..bee3ecb1409 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java @@ -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. * *

    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. * *

    This annotation may be used as a meta-annotation to create custom * composed annotations with attribute overrides. @@ -84,14 +84,16 @@ public @interface CachePut { *

    */ @@ -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}. *

    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 { *

    */ @@ -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}. *

    Default is {@code ""}, meaning that caching is never vetoed. *

    The SpEL expression evaluates against a dedicated context that provides the * following meta-data: *

    * @since 3.2 diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java b/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java index 4f0ccd85fd6..0b2b8f2ea5a 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java @@ -104,8 +104,8 @@ public @interface Cacheable { * affected cache(s) respectively. *
  • Shortcuts for the method name ({@code #root.methodName}) and target class * ({@code #root.targetClass}) are also available. - *
  • 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 + *
  • 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.
  • * */ @@ -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}. *

    Default is {@code ""}, meaning the method result is always cached. *

    The SpEL expression evaluates against a dedicated context that provides the @@ -149,8 +149,8 @@ public @interface Cacheable { * affected cache(s) respectively. *

  • Shortcuts for the method name ({@code #root.methodName}) and target class * ({@code #root.targetClass}) are also available. - *
  • 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 + *
  • 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.
  • * */ @@ -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}. *

    Unlike {@link #condition}, this expression is evaluated after the method * has been called and can therefore refer to the {@code result}. *

    Default is {@code ""}, meaning that caching is never vetoed. @@ -167,14 +167,16 @@ public @interface Cacheable { *

    * @since 3.2