2 votes

Spring Ehcache3 provoque une exception avec le type de clé et de valeur.

Je essaie d'utiliser ehcache3 sur un projet avec spring 4.3. J'ai configuré un gestionnaire de cache :

Et ehcache.xml :

        java.lang.Long

            500

Mais lorsque je déploie le projet, j'obtiens une exception :

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheManager' defined in ServletContext resource [/WEB-INF/spring/root-context.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Cache [customerSettings] specifies key/value types. Use getCache(String, Class, Class)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
    ... 100 more
Caused by: java.lang.IllegalArgumentException: Cache [customerSettings] specifies key/value types. Use getCache(String, Class, Class)
    at org.ehcache.jsr107.Eh107CacheManager.getCache(Eh107CacheManager.java:297)
    at org.springframework.cache.jcache.JCacheCacheManager.loadCaches(JCacheCacheManager.java:105)
    at org.springframework.cache.support.AbstractCacheManager.initializeCaches(AbstractCacheManager.java:61)
    at org.springframework.cache.support.AbstractCacheManager.afterPropertiesSet(AbstractCacheManager.java:50)
    at org.springframework.cache.jcache.JCacheCacheManager.afterPropertiesSet(JCacheCacheManager.java:97)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
    ... 107 more

Si je supprime :

java.lang.Long

Tout fonctionne bien, mais le keyType du cache est Object. Que dois-je faire pour pouvoir utiliser mes propres types de clé et de valeur ?

5voto

Anthony Dahanne Points 1314

Spring cache n'est pas typé, donc il n'utilise pas l'API typée de Jcache (javax.cache / JSR-107 caching API)

Maintenant, comme vous avez spécifié des types dans votre ehcache.xml, Ehcache a refusé de laisser Spring utiliser la signature non typée de getCache()

Quand vous y pensez, si vous laissez Spring utiliser Ehcache (via @CacheResult et d'autres annotations JCache par exemple), vous devez lui laisser choisir pour vous quels sont les types de clé et de valeur - ce n'est plus à vous de spécifier les types.

2voto

Donz Points 592

Comme vous pouvez le voir dans les sources de org.springframework.cache.jcache.JCacheCacheManager, Spring ne comprend pas qu'il devrait utiliser la méthode getCache(String, Class, Class) au lieu de simplement getCache(String). Plus précisément, cette classe ne sait rien de getCache(String, Class, Class).

Donc, vous avez trois options:

  1. Ne rien faire car, lors des opérations de récupération et de stockage dans le cache, le cache utilise les méthodes equals() et éventuellement hashCode() de la vraie classe de votre clé. Le seul inconvénient est le transtypage explicite si vous utilisez un accès direct au cache au lieu d'un accès déclaratif via des annotations.

  2. Étendre cette classe et l'étudier pour comprendre ces fonctionnalités de configuration du cache.

  3. Regarder un autre CacheManager qui pourrait connaître ces paramètres.

0voto

dit Points 5514

D'accord, vous devez pirater un peu :

écrivez un CacheManager personnalisé et utilisez-le dans votre configuration xml :

Voici un peu de code (pseudo) :

public class MyCustomLongObjectJCacheManager extends JCacheCacheManager{

    @Override
    protected Collection loadCaches() {

        javax.cache.CacheManager cacheManager = getCacheManager();

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

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

        }
        return caches;
    }

    @Override
    protected Cache getMissingCache(String cacheName) {
        // Vérifiez à nouveau le cache JCache (au cas où le cache aurait été ajouté à l'exécution)

        javax.cache.CacheManager cacheManager = getCacheManager();

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

        javax.cache.Cache 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 cache;

    public MyCustomAdaptingCache(javax.cache.Cache jcache) {
        this(jcache, true);
    }

    public MyCustomAdaptingCache(javax.cache.Cache jcache, boolean allowNullValues) {
        super(allowNullValues);
        Assert.notNull(jcache, "Le cache ne doit pas être nul");
        this.cache = jcache;
    }

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

    @Override
    public final javax.cache.Cache getNativeCache() {
        return this.cache;
    }

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

    @Override
    public  T get(Object key, Callable valueLoader) {
        try {
            return this.cache.invoke((Long)key, new ValueLoaderEntryProcessor(), 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 implements EntryProcessor {

        @SuppressWarnings("unchecked")
        @Override
        public T process(MutableEntry entry, Object... arguments)
                throws EntryProcessorException {
            Callable valueLoader = (Callable) arguments[0];
            if (entry.exists()) {
                return (T) fromStoreValue(entry.getValue());
            }
            else {
                T value;
                try {
                    value = valueLoader.call();
                }
                catch (Exception ex) {
                    throw new EntryProcessorException("Le chargeur de valeur '" + valueLoader + "' a échoué " +
                            "à calculer la valeur pour la clé '" + entry.getKey() + "'", ex);
                }
                entry.setValue(toStoreValue(value));
                return value;
            }
        }
    }

}

Bonne chance.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X