2

I have a method that has to be cached. I have a SpringBoot 2.1.7 application with a JSR-107 (JCache) cache. Cache implementation used: EHCache 3.8.0.

@Override
@HystrixCommand(fallbackMethod = "fallbackGetAllUserProfiles")
@Timed(histogram = true, percentiles = {0.75, 0.9, 0.95, 0.99})
@CacheResult
public UserProfiles getAllUserProfiles(@CacheKey String accountID, @CacheKey String userID) {
    return getAllUserProfilesFromBackend(accountID, userID);
}

The class is annotated with CacheDefaults(cacheName = "profileCache") When I use the annotation: @EnableCaching on my SpringBoot starter class I get this exception when trying to access the method:

java.lang.ClassCastException: Invalid key type, expected : java.lang.String but was : org.springframework.cache.interceptor.SimpleKey
    at org.ehcache.impl.store.BaseStore.checkKey(BaseStore.java:64) ~[ehcache-3.8.0.jar:3.8.0 98c7461621c490ef009548e61849f925305a631f]
    at org.ehcache.impl.internal.store.heap.OnHeapStore.get(OnHeapStore.java:279) ~[ehcache-3.8.0.jar:3.8.0 98c7461621c490ef009548e61849f925305a631f]
    at org.ehcache.core.Ehcache.doGet(Ehcache.java:90) ~[ehcache-3.8.0.jar:3.8.0 98c7461621c490ef009548e61849f925305a631f]
    at org.ehcache.core.EhcacheBase.get(EhcacheBase.java:127) ~[ehcache-3.8.0.jar:3.8.0 98c7461621c490ef009548e61849f925305a631f]
    at org.ehcache.jsr107.Eh107Cache.get(Eh107Cache.java:90) ~[ehcache-3.8.0.jar:3.8.0 98c7461621c490ef009548e61849f925305a631f]
    at org.springframework.cache.jcache.JCacheCache.lookup(JCacheCache.java:77) ~[spring-context-support-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.cache.support.AbstractValueAdaptingCache.get(AbstractValueAdaptingCache.java:58) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.cache.interceptor.AbstractCacheInvoker.doGet(AbstractCacheInvoker.java:73) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.cache.jcache.interceptor.CacheResultInterceptor.invoke(CacheResultInterceptor.java:57) ~[spring-context-support-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.cache.jcache.interceptor.JCacheAspectSupport.execute(JCacheAspectSupport.java:135) ~[spring-context-support-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.cache.jcache.interceptor.JCacheAspectSupport.execute(JCacheAspectSupport.java:112) ~[spring-context-support-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.cache.jcache.interceptor.JCacheInterceptor.invoke(JCacheInterceptor.java:82) ~[spring-context-support-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.1.9.RELEASE.jar:5.1.9.RELEASE]

This is the cache specification:

    <cache alias="profileCache">
        <key-type copier="org.ehcache.impl.copy.SerializingCopier">java.lang.String</key-type>
        <value-type copier="org.ehcache.impl.copy.IdentityCopier">java.util.List</value-type>
        <expiry>
            <ttl unit="minutes">5</ttl>
        </expiry>
        <heap unit="entries">10000</heap>
    </cache>

When I change the annotation to @EnableCaching(mode = AdviceMode.ASPECTJ) it does work. Is this a bug or am I doing something wrong here?

Sven
  • 2,343
  • 1
  • 18
  • 29
  • Can you add the EHCache configuration? It also looks like a search. I would introduce a single bean containing the search parameters. Second, I would cache a search result separate from the profiles. – cruftex Aug 29 '19 at 05:51
  • EHCache xml added. It translates actually to a REST call where the 2 parameters are translated to the path that has to be called. – Sven Aug 29 '19 at 07:36
  • 2
    You have a compound key of two strings, but configured EHCache with key type string. Just relax that to `Object`. If you don't like that, you can use a custom key generator. Unfortunately, here is the the biggest limitation/annoyances in the JCache annotations, you cannot use String as key type, since it must implement `GeneratedCacheKey` – cruftex Aug 30 '19 at 05:33
  • But why with `AdviceMode.ASPECTJ` it does work without implementing a `GeneratedCacheKey`? – Sven Aug 31 '19 at 07:21

1 Answers1

4

This error will happen if you have caching on a method that does not have any parameters but you do not specify a key. I solved this error by adding a key:

@Cacheable(value = "SomeCacheName", key = "#root.methodName")
public List<Country> getCountries() {
    ...
    return countries;
}
Dave
  • 321
  • 5
  • 7