• 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

61.36
today-context/src/main/java/infra/cache/interceptor/NameMatchCacheOperationSource.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.interceptor;
19

20
import org.jspecify.annotations.Nullable;
21

22
import java.io.Serializable;
23
import java.lang.reflect.Method;
24
import java.util.Collection;
25
import java.util.LinkedHashMap;
26
import java.util.Map;
27

28
import infra.logging.Logger;
29
import infra.logging.LoggerFactory;
30
import infra.util.ObjectUtils;
31
import infra.util.PatternMatchUtils;
32

33
/**
34
 * Simple {@link CacheOperationSource} implementation that allows attributes to be matched
35
 * by registered name.
36
 *
37
 * @author Costin Leau
38
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
39
 * @since 4.0
40
 */
41
@SuppressWarnings("serial")
42
public class NameMatchCacheOperationSource implements CacheOperationSource, Serializable {
2✔
43

44
  /**
45
   * Logger available to subclasses.
46
   * <p>Static for optimal serialization.
47
   */
48
  protected static final Logger logger = LoggerFactory.getLogger(NameMatchCacheOperationSource.class);
4✔
49

50
  /** Keys are method names; values are TransactionAttributes. */
51
  private final Map<String, Collection<CacheOperation>> nameMap = new LinkedHashMap<>();
6✔
52

53
  /**
54
   * Set a name/attribute map, consisting of method names
55
   * (e.g. "myMethod") and CacheOperation instances
56
   * (or Strings to be converted to CacheOperation instances).
57
   *
58
   * @see CacheOperation
59
   */
60
  public void setNameMap(Map<String, Collection<CacheOperation>> nameMap) {
61
    nameMap.forEach(this::addCacheMethod);
4✔
62
  }
1✔
63

64
  /**
65
   * Add an attribute for a cacheable method.
66
   * <p>Method names can be exact matches, or of the pattern "xxx*",
67
   * "*xxx" or "*xxx*" for matching multiple methods.
68
   *
69
   * @param methodName the name of the method
70
   * @param ops operation associated with the method
71
   */
72
  public void addCacheMethod(String methodName, Collection<CacheOperation> ops) {
73
    if (logger.isDebugEnabled()) {
3!
74
      logger.debug("Adding method [{}] with cache operations [{}]", methodName, ops);
×
75
    }
76
    this.nameMap.put(methodName, ops);
6✔
77
  }
1✔
78

79
  @Override
80
  @Nullable
81
  public Collection<CacheOperation> getCacheOperations(Method method, @Nullable Class<?> targetClass) {
82
    // look for direct name match
83
    String methodName = method.getName();
3✔
84
    Collection<CacheOperation> ops = this.nameMap.get(methodName);
6✔
85

86
    if (ops == null) {
2✔
87
      // Look for most specific name match.
88
      String bestNameMatch = null;
2✔
89
      for (String mappedName : this.nameMap.keySet()) {
12✔
90
        if (isMatch(methodName, mappedName)
7!
91
                && (bestNameMatch == null || bestNameMatch.length() <= mappedName.length())) {
×
92
          ops = this.nameMap.get(mappedName);
6✔
93
          bestNameMatch = mappedName;
2✔
94
        }
95
      }
1✔
96
    }
97

98
    return ops;
2✔
99
  }
100

101
  /**
102
   * Return if the given method name matches the mapped name.
103
   * <p>The default implementation checks for "xxx*", "*xxx" and "*xxx*" matches,
104
   * as well as direct equality. Can be overridden in subclasses.
105
   *
106
   * @param methodName the method name of the class
107
   * @param mappedName the name in the descriptor
108
   * @return if the names match
109
   * @see PatternMatchUtils#simpleMatch(String, String)
110
   */
111
  protected boolean isMatch(String methodName, String mappedName) {
112
    return PatternMatchUtils.simpleMatch(mappedName, methodName);
4✔
113
  }
114

115
  @Override
116
  public boolean equals(@Nullable Object other) {
117
    if (this == other) {
×
118
      return true;
×
119
    }
120
    if (!(other instanceof NameMatchCacheOperationSource otherTas)) {
×
121
      return false;
×
122
    }
123
    return ObjectUtils.nullSafeEquals(this.nameMap, otherTas.nameMap);
×
124
  }
125

126
  @Override
127
  public int hashCode() {
128
    return NameMatchCacheOperationSource.class.hashCode();
×
129
  }
130

131
  @Override
132
  public String toString() {
133
    return getClass().getName() + ": " + this.nameMap;
×
134
  }
135
}
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