How to Iterate on a cache entries
Asked Answered
W

5

12

I am using Spring3.1 in standalone Env. I am caching my entry using @Cachable annotation.

Sometimes I need to iterate on the caching list in order to get specific value(not key).

So I managed to retrieve the cached list but how could I iterate on it's elements.

private ClientDTO getClientDTOByClientId(Integer clientId)
{

    Cache clientCache = null;
    try
    {
        clientCache = ehCacheCacheManager.getCache("client");

          //need here to iterate on clientCache. how?


    }
    catch (Exception e)
    {
        log.error("Couldnt retrieve client from cache. clientId=" + clientId);
    }
    return clientDTO;
}

I using ehcache mechanism.

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
        p:cache-manager-ref="ehcache" />

    <bean id="ehcache"
        class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
        p:config-location="classpath:ehcache.xml" />

thanks, ray.

Weinreb answered 6/8, 2012 at 13:36 Comment(0)
J
18

CacheManager.getCache() returns a net.sf.ehcache.Cache, which has a getKeys() method that returns a list of cache keys that you can iterate over. To retrieve the actual object that's been stored (as opposed to the wrapped net.sf.ehcache.Element), use the Element.getObjectValue().

EDIT: According to Spring it doesn't look like they will ever support Cache.getKeys(), so you'll have to cast to the underlying provider.

Something like this:

public boolean contains(String cacheName, Object o) {
  net.sf.ehcache.EhCache cache = (net.sf.ehcache.EhCache) org.springframework.cache.CacheManager.getCache(cacheName).getNativeCache();
  for (Object key: cache.getKeys()) {
    Element element = cache.get(key);
    if (element != null && element.getObjectValue().equals(o)) {
      return true;
    }
  }
  return false;
}
Jewbaiting answered 6/8, 2012 at 14:10 Comment(6)
But I dont have cache.getKeys() method. I am using org.springframework.cache.CacheWeinreb
Did you find any solution? How to iterate over infinispan Cache. I need keys.Dunton
Did you cast to the underlying provider?Jewbaiting
This answer assumes that the inherited Cache type object has a getKeys method. This is not always true, and one such cache, as mention above, the org.springframework.cache.Cache does not include this.Cyder
Getting class org.springframework.cache.ehcache.EhCacheCache cannot be cast to class net.sf.ehcache.EhcacheCleanthes
Check to make sure you're calling .getNativeCache() to get the underlying cache manager implementation.Jewbaiting
H
9

Another solution, cast org.springframework.cache.Cache to javax.cache.Cache by using getNativeCache() method and use java iterator as javax.cache.Cache already extends Iterable<Cache.Entry<K, V>>.

for more details read javax.cache.Cache javadoc

    Cache cache = (Cache) cacheManager.getCache("yourCacheName").getNativeCache();
    Iterator<Cache.Entry> iterator = cache.iterator();

    while (iterator.hasNext()) {
        String key = (String) iterator.next().getKey();
        System.out.println(key);
    }
Handhold answered 10/9, 2019 at 14:28 Comment(0)
H
2
var cache = cacheManager.getCache("CACHE_NAME");
var nativeCache = (ConcurrentHashMap<?, ?>) cache.getNativeCache();

for (var entry: nativeCache.entrySet()){
    // Access entry key and value
    entry.getKey()
    entry.getValue()
}
Hydromedusa answered 1/9, 2021 at 18:14 Comment(0)
I
1

The below method will give a set of keys of cached objects, But here if you add your cache with keys then it's easy to retrieve(If you add directly list of objects to cache then it'll not work out).

Also, I used GuavaCache in the cache manager like below.

@Bean
public CacheManager cacheManager() {
    SimpleCacheManager simpleCacheManager = new SimpleCacheManager();

    GuavaCache userLabCache = new GuavaCache("yourCacheName",
            CacheBuilder.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES).build());
    simpleCacheManager.setCaches(Arrays.asList(userLabCache));
    return simpleCacheManager;
}

Then it'll return the list of keys as objects, then you'll get the keys and you can iterate through keys and get the objects one by one from the cache.

Autowire Springboot CacheManager in your class

@Autowired
CacheManager cacheManager;

below is the code to get all keys.

public Set<Object> getAllCachedUserLabKeys() {
    Set<Object> keys = null;
    try {
        GuavaCache cache = (GuavaCache) cacheManager.getCache("yourCacheName");
        if (cache != null) {
            ConcurrentMap<Object, Object> cachedMap = cache.getNativeCache().asMap();
            keys = cachedMap.keySet();
        }
    } catch (Exception e) {
        LOGGER.error("Unknown exception occured while fetchting all cached User Labs..!", e);
    }
    return keys;
}
Initiatory answered 11/10, 2018 at 7:59 Comment(0)
I
0

I use this

first endpoint will tell you the caches you have

second endpoint will give you all the entries for a specific cache (with safe mapping)

third endpoint will give you all the entries for all your caches (with safe mapping)

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.github.benmanes.caffeine.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;

@RestController
@RequestMapping("cache")
public class CacheController {
    private final CacheManager cacheManager;
    private final ObjectMapper objectMapper;

    public CacheController(final CacheManager cacheManager) {
        this.cacheManager = cacheManager;
        this.objectMapper = new ObjectMapper();
        this.objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        this.objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    }

    @GetMapping("/names")
    public Collection<String> getCacheNames() {
        return cacheManager.getCacheNames();
    }

    @GetMapping("{cacheName}")
    public Map<String, Object> getEntriesForCache(@PathVariable(name = "cacheName") final String cacheName) throws JsonProcessingException {
        final Cache<String, Object> cache = (Cache<String, Object>) cacheManager.getCache(cacheName).getNativeCache();

        final ConcurrentMap<String, Object> data = cache.asMap();
        final String json = objectMapper.writeValueAsString(data);

        final TypeReference<HashMap<String,Object>> typeRef = new TypeReference<>() {};
        return objectMapper.readValue(json, typeRef);
    }

    @GetMapping("entries")
    public Map<String, Map<String, Object>> getAllEntries() throws JsonProcessingException {
        final Map<String, Map<String, Object>> entries = new HashMap<>();
        for(final String cacheName: getCacheNames()){
            entries.put(cacheName, getEntriesForCache(cacheName));
        }
        return entries;
    }
}
Indubitability answered 21/5, 2021 at 14:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.