• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TAKETODAY / today-infrastructure / 18154768944

01 Oct 2025 07:26AM UTC coverage: 81.882% (-0.005%) from 81.887%
18154768944

push

github

web-flow
Merge pull request #290 from TAKETODAY/dev/jspecify

jspecify

59788 of 78013 branches covered (76.64%)

Branch coverage included in aggregate %.

141239 of 167496 relevant lines covered (84.32%)

3.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

43.08
today-context/src/main/java/infra/cache/annotation/AnnotationCacheOperationSource.java
1
/*
2
 * Copyright 2017 - 2025 the original author or authors.
3
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see [https://www.gnu.org/licenses/]
16
 */
17

18
package infra.cache.annotation;
19

20
import org.jspecify.annotations.Nullable;
21

22
import java.io.Serializable;
23
import java.lang.reflect.Method;
24
import java.util.ArrayList;
25
import java.util.Collection;
26
import java.util.Collections;
27
import java.util.Set;
28

29
import infra.cache.interceptor.AbstractFallbackCacheOperationSource;
30
import infra.cache.interceptor.CacheOperation;
31
import infra.cache.interceptor.CacheOperationSource;
32
import infra.lang.Assert;
33

34
/**
35
 * Implementation of the {@link CacheOperationSource
36
 * CacheOperationSource} interface for working with caching metadata in annotation format.
37
 *
38
 * <p>This class reads Framework's {@link Cacheable}, {@link CachePut} and {@link CacheEvict}
39
 * annotations and exposes corresponding caching operation definition to Framework's cache
40
 * infrastructure. This class may also serve as base class for a custom
41
 * {@code CacheOperationSource}.
42
 *
43
 * @author Costin Leau
44
 * @author Juergen Hoeller
45
 * @author Stephane Nicoll
46
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
47
 * @since 4.0
48
 */
49
@SuppressWarnings("serial")
50
public class AnnotationCacheOperationSource extends AbstractFallbackCacheOperationSource implements Serializable {
51

52
  private final boolean publicMethodsOnly;
53

54
  private final Set<CacheAnnotationParser> annotationParsers;
55

56
  /**
57
   * Create a default AnnotationCacheOperationSource, supporting public methods
58
   * that carry the {@code Cacheable} and {@code CacheEvict} annotations.
59
   */
60
  public AnnotationCacheOperationSource() {
61
    this(true);
3✔
62
  }
1✔
63

64
  /**
65
   * Create a default {@code AnnotationCacheOperationSource}, supporting public methods
66
   * that carry the {@code Cacheable} and {@code CacheEvict} annotations.
67
   *
68
   * @param publicMethodsOnly whether to support only annotated public methods
69
   * typically for use with proxy-based AOP), or protected/private methods as well
70
   * (typically used with AspectJ class weaving)
71
   */
72
  public AnnotationCacheOperationSource(boolean publicMethodsOnly) {
2✔
73
    this.publicMethodsOnly = publicMethodsOnly;
3✔
74
    this.annotationParsers = Collections.singleton(new DefaultCacheAnnotationParser());
6✔
75
  }
1✔
76

77
  /**
78
   * Create a custom AnnotationCacheOperationSource.
79
   *
80
   * @param annotationParser the CacheAnnotationParser to use
81
   */
82
  public AnnotationCacheOperationSource(CacheAnnotationParser annotationParser) {
×
83
    Assert.notNull(annotationParser, "CacheAnnotationParser is required");
×
84
    this.publicMethodsOnly = true;
×
85
    this.annotationParsers = Collections.singleton(annotationParser);
×
86
  }
×
87

88
  /**
89
   * Create a custom AnnotationCacheOperationSource.
90
   *
91
   * @param annotationParsers the CacheAnnotationParser to use
92
   */
93
  public AnnotationCacheOperationSource(CacheAnnotationParser... annotationParsers) {
×
94
    Assert.notEmpty(annotationParsers, "At least one CacheAnnotationParser needs to be specified");
×
95
    this.publicMethodsOnly = true;
×
96
    this.annotationParsers = Set.of(annotationParsers);
×
97
  }
×
98

99
  /**
100
   * Create a custom AnnotationCacheOperationSource.
101
   *
102
   * @param annotationParsers the CacheAnnotationParser to use
103
   */
104
  public AnnotationCacheOperationSource(Set<CacheAnnotationParser> annotationParsers) {
×
105
    this.publicMethodsOnly = true;
×
106
    Assert.notEmpty(annotationParsers, "At least one CacheAnnotationParser needs to be specified");
×
107
    this.annotationParsers = annotationParsers;
×
108
  }
×
109

110
  @Override
111
  public boolean isCandidateClass(Class<?> targetClass) {
112
    for (CacheAnnotationParser parser : this.annotationParsers) {
11!
113
      if (parser.isCandidateClass(targetClass)) {
4!
114
        return true;
2✔
115
      }
116
    }
×
117
    return false;
×
118
  }
119

120
  @Override
121
  @Nullable
122
  protected Collection<CacheOperation> findCacheOperations(Class<?> clazz) {
123
    return determineCacheOperations(parser -> parser.parseCacheAnnotations(clazz));
9✔
124
  }
125

126
  @Override
127
  @Nullable
128
  protected Collection<CacheOperation> findCacheOperations(Method method) {
129
    return determineCacheOperations(parser -> parser.parseCacheAnnotations(method));
9✔
130
  }
131

132
  /**
133
   * Determine the cache operation(s) for the given {@link CacheOperationProvider}.
134
   * <p>This implementation delegates to configured
135
   * {@link CacheAnnotationParser CacheAnnotationParsers}
136
   * for parsing known annotations into Framework's metadata attribute class.
137
   * <p>Can be overridden to support custom annotations that carry caching metadata.
138
   *
139
   * @param provider the cache operation provider to use
140
   * @return the configured caching operations, or {@code null} if none found
141
   */
142
  @Nullable
143
  protected Collection<CacheOperation> determineCacheOperations(CacheOperationProvider provider) {
144
    Collection<CacheOperation> ops = null;
2✔
145
    for (CacheAnnotationParser parser : this.annotationParsers) {
11✔
146
      Collection<CacheOperation> annOps = provider.getCacheOperations(parser);
4✔
147
      if (annOps != null) {
2✔
148
        if (ops == null) {
2!
149
          ops = annOps;
3✔
150
        }
151
        else {
152
          ArrayList<CacheOperation> combined = new ArrayList<>(ops.size() + annOps.size());
×
153
          combined.addAll(ops);
×
154
          combined.addAll(annOps);
×
155
          ops = combined;
×
156
        }
157
      }
158
    }
1✔
159
    return ops;
2✔
160
  }
161

162
  /**
163
   * By default, only public methods can be made cacheable.
164
   */
165
  @Override
166
  protected boolean allowPublicMethodsOnly() {
167
    return this.publicMethodsOnly;
3✔
168
  }
169

170
  @Override
171
  public boolean equals(@Nullable Object other) {
172
    if (this == other) {
×
173
      return true;
×
174
    }
175
    if (!(other instanceof AnnotationCacheOperationSource otherCos)) {
×
176
      return false;
×
177
    }
178
    return (this.annotationParsers.equals(otherCos.annotationParsers) &&
×
179
            this.publicMethodsOnly == otherCos.publicMethodsOnly);
180
  }
181

182
  @Override
183
  public int hashCode() {
184
    return this.annotationParsers.hashCode();
4✔
185
  }
186

187
  /**
188
   * Callback interface providing {@link CacheOperation} instance(s) based on
189
   * a given {@link CacheAnnotationParser}.
190
   */
191
  @FunctionalInterface
192
  protected interface CacheOperationProvider {
193

194
    /**
195
     * Return the {@link CacheOperation} instance(s) provided by the specified parser.
196
     *
197
     * @param parser the parser to use
198
     * @return the cache operations, or {@code null} if none found
199
     */
200
    @Nullable
201
    Collection<CacheOperation> getCacheOperations(CacheAnnotationParser parser);
202
  }
203

204
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc