Caching in Spring on methods with array parameters
Asked Answered
H

3

6

I have a service with multiple methods and am attempting to cache them using Spring @Cacheable annotations. Everything works fine except I've found the methods with an array as a method parameter are not cached. This somewhat makes sense considering arrays can hold different values, but I would still think it would be possible.

The following methods are cached:

@Cacheable("myCache")
public Collection<Building> findBuildingByCode(String buildingCode) {...}

@Cacheable("myCache")
public Collection<Building> getBuildings() {...}

However, if I change the findBuildingByCode method to either of the following, it is not cached:

@Cacheable("myCache") 
public Collection<Building> findBuildingByCode(String[] buildingCode) {...}

@Cacheable("myCache")
public Collection<Building> findBuildingByCode(String... buildingCode) {...}

Here is the relevant Spring xml configuration:

<!-- Cache beans -->
<cache:annotation-driven/>

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

<!-- EhCache library setup -->
<bean id="ehcache"
    class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />

Ehcache configuration:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">

<diskStore path="java.io.tmpdir/ehcache" />

<!-- Default settings -->
<defaultCache eternal="false" maxElementsInMemory="1"
    overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
    timeToLiveSeconds="100" memoryStoreEvictionPolicy="LRU" />

<!-- Other caches -->

<cache name="myCache" eternal="false" maxElementsInMemory="500"
    overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
    timeToLiveSeconds="43200" memoryStoreEvictionPolicy="LRU" />

 </ehcache>

Is this known functionality or a bug?

Huonghupeh answered 1/8, 2013 at 17:57 Comment(0)
R
9

Try to define the cache key like that:

@Cacheable(value="myCache", key="#buildingCode.toString()")

Or #buildingCode.hashCode(). So the cache manager will be able to cache the method.

Resolvable answered 1/8, 2013 at 19:42 Comment(2)
how about collections like arrayList hashMap?Dewan
could you please answer this #46937189Lodhia
U
1

Using hash or string representation for the array does not define uniqueness in terms of caching. For example, the array contains 2 or more identical entries or has a different order: the hash/toString will be different...but the cache key should probably be the same. What I would do is create a wrapper around your array... and create a getCacheKey() that would do whatever you need it to do...

public class BuildCodesCacheWrapper {
private String[] buildingCodes;

private BuildCodesCacheWrapper(String[] buildingCodes) {
    super();
    this.buildingCodes = buildingCodes;
}

public String getCacheKey(){
    String key = "";
    if(null != buildingCodes){
        for(String code : buildingCodes){
            if(!key.contains("")){
                key += code;
            }
        }
    }
    return key;
}
}

(code above not tested and could be made more generic for all sort of arrays etc...)

And use that getCacheKey() method in the SPEL expression...

@Cacheable("myCache", key="#buildingCode.getCacheKey()") 
public Collection<Building> findBuildingByCode(BuildCodesCacheWrapper buildingCode) {...}
Unavoidable answered 1/8, 2013 at 20:46 Comment(1)
You can use a SortedSet insteaf of the array, so that you get rid of duplicates and order issues.Peptize
K
1

Just expanding on @Benoit's answer:

@Cacheable(value = "myCache", key = "T(java.util.Arrays).asList(#terms).hashCode()")

In my case I was using the spread operator for passing in the arguments to the cacheable function, as such:

@Cacheable(...) public Object func(String... terms)

Calling toString or hashCode on the terms array produced different results every time, however converting it to a list and hashCoding it seemed to do the trick.

Kilan answered 10/11, 2021 at 18:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.