Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot 3 ehcache config setup issue

I'm trying to setup ehcache in my Spring boot application. I have the following ehcache.xml and configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.ehcache.org/v3'>
    <cache alias="myCache">
        <expiry>
            <ttl unit="minutes">60</ttl>
        </expiry>
        <heap>20</heap>
    </cache>
</config>
import org.ehcache.jsr107.EhcacheCachingProvider;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.jcache.JCacheCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.cache.CacheManager;
import javax.cache.Caching;
import java.net.URI;
import java.net.URISyntaxException;

@Configuration
@EnableCaching
public class CacheConfig {
  @Bean
  public JCacheCacheManager cacheManager() throws URISyntaxException {
    ClassLoader classLoader = getClass().getClassLoader();
    URI ehcacheURI = classLoader.getResource("ehcache.xml").toURI();
    CacheManager cacheManager = Caching.getCachingProvider(EhcacheCachingProvider.class.getName()).getCacheManager(ehcacheURI, classLoader);

    return new JCacheCacheManager(cacheManager);
  }
}

However, when I start up my application, I get the following error message:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cacheManager' defined in class path resource [com/webservice/config/CacheConfig.class]: Failed to instantiate [org.springframework.cache.jcache.JCacheCacheManager]: Factory method 'cacheManager' threw exception with message: javax/xml/bind/ValidationEventHandler
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:652)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:488)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1324)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1161)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
    at com.webservice.Application.main(Application.java:15)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.cache.jcache.JCacheCacheManager]: Factory method 'cacheManager' threw exception with message: javax/xml/bind/ValidationEventHandler
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:171)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:648)
    ... 22 common frames omitted
Caused by: java.lang.NoClassDefFoundError: javax/xml/bind/ValidationEventHandler
    at org.ehcache.xml.XmlConfiguration.<init>(XmlConfiguration.java:114)
    at org.ehcache.xml.XmlConfiguration.<init>(XmlConfiguration.java:90)
    at org.ehcache.jsr107.EhcacheCachingProvider$ConfigSupplier.getConfiguration(EhcacheCachingProvider.java:328)
    at org.ehcache.jsr107.EhcacheCachingProvider.getCacheManager(EhcacheCachingProvider.java:134)
    at org.ehcache.jsr107.EhcacheCachingProvider.getCacheManager(EhcacheCachingProvider.java:85)
    at org.ehcache.jsr107.EhcacheCachingProvider.getCacheManager(EhcacheCachingProvider.java:194)
    at com.webservice.config.CacheConfig.cacheManager(CacheConfig.java:29)
    at com.webservice.config.CacheConfig$$SpringCGLIB$$0.CGLIB$cacheManager$0(<generated>)
    at com.webservice.config.CacheConfig$$SpringCGLIB$$2.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:257)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
    at com.webservice.config.CacheConfig$$SpringCGLIB$$0.cacheManager(<generated>)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139)
    ... 23 common frames omitted
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.ValidationEventHandler
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    ... 40 common frames omitted

Does anyone know what I'm doing wrong? It looks like it has something to do with validation. So I'm assuming my ehcache.xml file might be incorrect. I'm using org.ehcache.ehcache version 3.10.2. Any help would be appreciated.

like image 653
syy Avatar asked Jul 18 '26 05:07

syy


2 Answers

There is more behind the answer from @m-sinan-Şahin than the eye meets! I didn't understand it because it was Gradle-only, and I didn't bother to follow his link (:facepalm:), but after hours I connected the dots:

  • https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide#ehcache3

To support Jakarta EE 9 and later, dependency management for Ehcache’s ehcache and ehcache-transactions modules are now declared with a jakarta classifier. Dependency declarations in your pom.xml or build.gradle scripts should be similarly updated.

The releases page also hints to availability of jakarta classifier versions: https://github.com/ehcache/ehcache3/releases

Therefore the ehcache3 dependency has to be declared with the jakarta classifier:

    <dependency>
      <groupId>org.ehcache</groupId>
      <artifactId>ehcache</artifactId>
      <scope>runtime</scope>
      <classifier>jakarta</classifier>
    </dependency>

PS
In this example the dependency has no version because I use the version declared by the used Spring Boot version (in parent POM or in BOM).

like image 139
t0r0X Avatar answered Jul 19 '26 19:07

t0r0X


Since Spring Boot 3, the EhCacheCacheManager implementation of org.springframework.cache.CacheManager as a @Bean is no longer supported.

Instead, you can utilize the JCacheCacheManager which implements CacheManager with similar configuration properties to the old one. Here is an example of how you can set it up:

Add the following dependencies to your pom.xml file:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>

    <dependency>
        <groupId>org.ehcache</groupId>
        <artifactId>ehcache</artifactId>
    </dependency>

and the code:

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.ehcache.config.CacheConfiguration;
    import org.ehcache.config.builders.CacheConfigurationBuilder;
    import org.ehcache.config.builders.ExpiryPolicyBuilder;
    import org.ehcache.config.builders.ResourcePoolsBuilder;
    import org.ehcache.config.units.MemoryUnit;
    import org.ehcache.core.config.DefaultConfiguration;
    import org.ehcache.expiry.ExpiryPolicy;
    import org.ehcache.jsr107.EhcacheCachingProvider;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.cache.jcache.JCacheCacheManager;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    import javax.cache.Caching;
    import java.time.Duration;
    import java.util.HashMap;
    import java.util.Map;

    @Configuration
    @EnableCaching
    public class CachingConfig {

        private static final Logger logger = LogManager.getLogger(CachingConfig.class);

        private static final String MY_CACHE = "MY_CACHE";

        @Bean
        public CacheManager jCacheCacheManager() {
            Map<String, CacheConfiguration<?, ?>> cacheMap = new HashMap<>();

            ResourcePoolsBuilder resourcePoolsBuilder = ResourcePoolsBuilder
                    .heap(3)
                    .offheap(1, MemoryUnit.MB) //min value is 1MB
                    ;

            ExpiryPolicy<Object, Object> expiryPolicy = createExpiryPolicy(Duration.ofMinutes(10), Duration.ofMinutes(5));

            CacheConfiguration<Object, Object> cacheConfiguration = CacheConfigurationBuilder
                    .newCacheConfigurationBuilder(Object.class, Object.class, resourcePoolsBuilder)
                    .withExpiry(expiryPolicy)
                    .build();

            cacheMap.put(MY_CACHE, cacheConfiguration);
            EhcacheCachingProvider ehcacheCachingProvider = (EhcacheCachingProvider) Caching.getCachingProvider(EhcacheCachingProvider.class.getName());
            DefaultConfiguration defaultConfiguration = new DefaultConfiguration(cacheMap, ehcacheCachingProvider.getDefaultClassLoader());
            javax.cache.CacheManager cacheManager = ehcacheCachingProvider.getCacheManager(ehcacheCachingProvider.getDefaultURI(), defaultConfiguration);
            return new JCacheCacheManager(cacheManager);
        }

        private static ExpiryPolicy<Object, Object> createExpiryPolicy(Duration timeToLive, Duration timeToIdle) {
            return ExpiryPolicyBuilder
                    .expiry()
                    .create(timeToLive)
                    .access(timeToIdle)
                    .build();
        }
        
    }
like image 26
Reuven Eliezer Avatar answered Jul 19 '26 17:07

Reuven Eliezer



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!