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

ben-manes / caffeine / #5173

29 Dec 2025 05:27AM UTC coverage: 0.0% (-100.0%) from 100.0%
#5173

push

github

ben-manes
speed up development ci build

0 of 3838 branches covered (0.0%)

0 of 7869 relevant lines covered (0.0%)

0.0 hits per line

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

0.0
/jcache/src/main/java/com/github/benmanes/caffeine/jcache/LoadingCacheProxy.java
1
/*
2
 * Copyright 2015 Ben Manes. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package com.github.benmanes.caffeine.jcache;
17

18
import static java.util.stream.Collectors.toUnmodifiableList;
19

20
import java.util.List;
21
import java.util.Map;
22
import java.util.Objects;
23
import java.util.Optional;
24
import java.util.Set;
25
import java.util.concurrent.CompletableFuture;
26
import java.util.concurrent.Executor;
27

28
import javax.cache.Cache;
29
import javax.cache.CacheException;
30
import javax.cache.CacheManager;
31
import javax.cache.expiry.ExpiryPolicy;
32
import javax.cache.integration.CacheLoader;
33
import javax.cache.integration.CompletionListener;
34

35
import org.jspecify.annotations.Nullable;
36

37
import com.github.benmanes.caffeine.cache.LoadingCache;
38
import com.github.benmanes.caffeine.cache.Ticker;
39
import com.github.benmanes.caffeine.jcache.configuration.CaffeineConfiguration;
40
import com.github.benmanes.caffeine.jcache.event.EventDispatcher;
41
import com.github.benmanes.caffeine.jcache.management.JCacheStatisticsMXBean;
42
import com.google.errorprone.annotations.Var;
43

44
/**
45
 * An implementation of JSR-107 {@link Cache} backed by a Caffeine loading cache.
46
 *
47
 * @author ben.manes@gmail.com (Ben Manes)
48
 */
49
@SuppressWarnings("OvershadowingSubclassFields")
50
public final class LoadingCacheProxy<K, V> extends CacheProxy<K, V> {
51
  private final LoadingCache<K, @Nullable Expirable<V>> cache;
52

53
  @SuppressWarnings({"PMD.ExcessiveParameterList", "TooManyParameters"})
54
  public LoadingCacheProxy(String name, Executor executor, CacheManager cacheManager,
55
      CaffeineConfiguration<K, V> configuration, LoadingCache<K, @Nullable Expirable<V>> cache,
56
      EventDispatcher<K, V> dispatcher, CacheLoader<K, V> cacheLoader, ExpiryPolicy expiry,
57
      Ticker ticker, JCacheStatisticsMXBean statistics) {
58
    super(name, executor, cacheManager, configuration, cache, dispatcher,
×
59
        Optional.of(cacheLoader), expiry, ticker, statistics);
×
60
    this.cache = cache;
×
61
  }
×
62

63
  @Override
64
  public @Nullable V get(K key) {
65
    requireNotClosed();
×
66
    try {
67
      return getOrLoad(key);
×
68
    } catch (NullPointerException | IllegalStateException | ClassCastException | CacheException e) {
×
69
      throw e;
×
70
    } catch (RuntimeException e) {
×
71
      throw new CacheException(e);
×
72
    } finally {
73
      dispatcher.awaitSynchronous();
×
74
    }
75
  }
76

77
  /** Retrieves the value from the cache, loading it if necessary. */
78
  private @Nullable V getOrLoad(K key) {
79
    boolean statsEnabled = statistics.isEnabled();
×
80
    long start = statsEnabled ? ticker.read() : 0L;
×
81

82
    @Var long millis = 0L;
×
83
    @Var Expirable<V> expirable = cache.getIfPresent(key);
×
84
    if ((expirable != null) && !expirable.isEternal()) {
×
85
      millis = nanosToMillis((start == 0L) ? ticker.read() : start);
×
86
      if (expirable.hasExpired(millis)) {
×
87
        var expired = expirable;
×
88
        cache.asMap().computeIfPresent(key, (k, e) -> {
×
89
          if (e == expired) {
×
90
            dispatcher.publishExpired(this, key, expired.get());
×
91
            statistics.recordEvictions(1);
×
92
            return null;
×
93
          }
94
          return e;
×
95
        });
96
        expirable = null;
×
97
      }
98
    }
99

100
    if (expirable == null) {
×
101
      expirable = cache.get(key);
×
102
      statistics.recordMisses(1L);
×
103
    } else {
104
      statistics.recordHits(1L);
×
105
    }
106

107
    @Var V value = null;
×
108
    if (expirable != null) {
×
109
      setAccessExpireTime(key, expirable, millis);
×
110
      value = copyValue(expirable);
×
111
    }
112
    if (statsEnabled) {
×
113
      statistics.recordGetTime(ticker.read() - start);
×
114
    }
115
    return value;
×
116
  }
117

118
  @Override
119
  public Map<K, V> getAll(Set<? extends K> keys) {
120
    return getAll(keys, /* updateAccessTime= */ true);
×
121
  }
122

123
  /** Returns the entries, loading if necessary, and optionally updates their access expiry time. */
124
  private Map<K, V> getAll(Set<? extends K> keys, boolean updateAccessTime) {
125
    requireNotClosed();
×
126
    boolean statsEnabled = statistics.isEnabled();
×
127
    long start = statsEnabled ? ticker.read() : 0L;
×
128
    try {
129
      Map<K, Expirable<V>> entries = getAndFilterExpiredEntries(keys, updateAccessTime);
×
130

131
      if (entries.size() != keys.size()) {
×
132
        List<K> keysToLoad = keys.stream()
×
133
            .filter(key -> !entries.containsKey(key))
×
134
            .collect(toUnmodifiableList());
×
135
        entries.putAll(cache.getAll(keysToLoad));
×
136
      }
137

138
      Map<K, V> result = copyMap(entries);
×
139
      if (statsEnabled) {
×
140
        statistics.recordGetTime(ticker.read() - start);
×
141
      }
142
      return result;
×
143
    } catch (NullPointerException | IllegalStateException | ClassCastException | CacheException e) {
×
144
      throw e;
×
145
    } catch (RuntimeException e) {
×
146
      throw new CacheException(e);
×
147
    } finally {
148
      dispatcher.awaitSynchronous();
×
149
    }
150
  }
151

152
  @Override
153
  @SuppressWarnings({"CheckReturnValue", "CollectionUndefinedEquality", "FutureReturnValueIgnored"})
154
  public void loadAll(Set<? extends K> keys, boolean replaceExistingValues,
155
      @Nullable CompletionListener completionListener) {
156
    requireNotClosed();
×
157
    keys.forEach(Objects::requireNonNull);
×
158
    CompletionListener listener = (completionListener == null)
×
159
        ? NullCompletionListener.INSTANCE
×
160
        : completionListener;
×
161

162
    var future = CompletableFuture.runAsync(() -> {
×
163
      try {
164
        if (replaceExistingValues) {
×
165
          Map<K, V> loaded = cacheLoader.orElseThrow().loadAll(keys);
×
166
          for (var entry : loaded.entrySet()) {
×
167
            putNoCopyOrAwait(entry.getKey(), entry.getValue(), /* publishToWriter= */ false);
×
168
          }
×
169
        } else {
×
170
          getAll(keys, /* updateAccessTime= */ false);
×
171
        }
172
        listener.onCompletion();
×
173
      } catch (RuntimeException e) {
×
174
        listener.onException(e);
×
175
      } finally {
176
        dispatcher.ignoreSynchronous();
×
177
      }
178
    }, executor);
×
179

180
    inFlight.add(future);
×
181
    future.whenComplete((r, e) -> inFlight.remove(future));
×
182
  }
×
183
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc