Spring Ehcache3 cause exception with with key-type and value-type

狂风中的少年 提交于 2019-12-06 07:28:21

Spring cache is not typed, so it's not using the typed API of Jcache (javax.cache / JSR-107 caching API)

Now since you specified types in your ehcache.xml, Ehcache refused to let Spring use the non typed signature of getCache()

When you think about it, if you let Spring use Ehcache (via @CacheResult and other JCache annotations for example), you have to let it choose for you what are the key and value types - it's no longer you who should specify types.

As you can see in sources of org.springframework.cache.jcache.JCacheCacheManager Spring doesn't understand that it should use method getCache(String, Class, Class) instead of simple getCache(String). More precisely this class doesn't know anything about getCache(String, Class, Class).

So you have three ways:

  1. Do nothing as during get and put operations cache uses equals() and may be hashCode() methods from real class of your key. Only discomfort is in explicit type casting if you use direct access to cache instead of declarative access via annotations.

  2. Extends this class and study it to understand these cache config features.

  3. Look at another CacheManager that might know these settings.

Ok you have to hack a little bit:

write a custom CacheManager and use it in you configuration xml:

<bean id="cacheManager" class="your.path.MyCustomLongObjectJCacheManager">
        <property name="cacheManager">
            <bean class="org.springframework.cache.jcache.JCacheManagerFactoryBean">
               <property name="cacheManagerUri" value="classpath:ehcache.xml"/>
            </bean>
        </property>
</bean>

Here is some (pseudo) code:

public class MyCustomLongObjectJCacheManager extends JCacheCacheManager{

    @Override
    protected Collection<Cache> loadCaches() {

        javax.cache.CacheManager cacheManager = getCacheManager();

        Collection<Cache> caches = new LinkedHashSet<Cache>();
        for (String cacheName : getCacheManager().getCacheNames()) {

            if("customerSettings".equals(cacheName)){ // or manager instance of Eh107CacheManager...
                javax.cache.Cache<Long, Object> jcache = cacheManager.getCache(cacheName, Long.class, Object.class);
                caches.add(new MyCustomAdaptingCache(jcache, isAllowNullValues()));
            } else {
                javax.cache.Cache<Object, Object> jcache = cacheManager.getCache(cacheName);
                caches.add(new JCacheCache(jcache, isAllowNullValues()));
            }

        }
        return caches;
    }

    @Override
    protected Cache getMissingCache(String cacheName) {
        // Check the JCache cache again (in case the cache was added at runtime)

        javax.cache.CacheManager cacheManager = getCacheManager();

        if("customerSettings".equals(cacheName)){
            javax.cache.Cache<Long, Object> jcache = cacheManager.getCache(cacheName, Long.class, Object.class);
            return new MyCustomAdaptingCache(jcache, isAllowNullValues());
        }

        javax.cache.Cache<Object, Object> jcache = getCacheManager().getCache(cacheName);
        if (jcache != null) {
            return new JCacheCache(jcache, isAllowNullValues());
        }
        return null;
    }


}


public static class MyCustomAdaptingCache extends AbstractValueAdaptingCache {

    private final javax.cache.Cache<Long, Object> cache;

    public MyCustomAdaptingCache(javax.cache.Cache<Long, Object> jcache) {
        this(jcache, true);
    }

    public MyCustomAdaptingCache(javax.cache.Cache<Long, Object> jcache, boolean allowNullValues) {
        super(allowNullValues);
        Assert.notNull(jcache, "Cache must not be null");
        this.cache = jcache;
    }

    @Override
    public final String getName() {
        return this.cache.getName();
    }

    @Override
    public final javax.cache.Cache<Long, Object> getNativeCache() {
        return this.cache;
    }

    @Override
    protected Object lookup(Object key) {
        return this.cache.get((Long)key);
    }

    @Override
    public <T> T get(Object key, Callable<T> valueLoader) {
        try {
            return this.cache.invoke((Long)key, new ValueLoaderEntryProcessor<T>(), valueLoader);
        }
        catch (EntryProcessorException ex) {
            throw new ValueRetrievalException(key, valueLoader, ex.getCause());
        }
    }

    @Override
    public void put(Object key, Object value) {
        this.cache.put((Long)key, toStoreValue(value));
    }

    @Override
    public ValueWrapper putIfAbsent(Object key, Object value) {
        boolean set = this.cache.putIfAbsent((Long)key, toStoreValue(value));
        return (set ? null : get(key));
    }

    @Override
    public void evict(Object key) {
        this.cache.remove((Long)key);
    }

    @Override
    public void clear() {
        this.cache.removeAll();
    }

    private class ValueLoaderEntryProcessor<T> implements EntryProcessor<Long, Object, T> {

        @SuppressWarnings("unchecked")
        @Override
        public T process(MutableEntry<Long, Object> entry, Object... arguments)
                throws EntryProcessorException {
            Callable<T> valueLoader = (Callable<T>) arguments[0];
            if (entry.exists()) {
                return (T) fromStoreValue(entry.getValue());
            }
            else {
                T value;
                try {
                    value = valueLoader.call();
                }
                catch (Exception ex) {
                    throw new EntryProcessorException("Value loader '" + valueLoader + "' failed " +
                            "to compute  value for key '" + entry.getKey() + "'", ex);
                }
                entry.setValue(toStoreValue(value));
                return value;
            }
        }
    }

}

good luck.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!