Spring boot 3 ehcache config setup issue
Asked Answered
G

5

6

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.

Garate answered 24/7, 2023 at 1:12 Comment(2)
In springframework.guru/using-ehcache-3-in-spring-boot 'dependencies.dependency.version' is missing. In howtodoinjava.com/spring-boot/spring-boot-ehcache-example there is no for jakarta ones. With <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>org.ehcache</groupId> <artifactId>ehcache</artifactId> <version>3.10.8</version> <classifier>jakarta</classifier> </dependency> Repository decommissioned. Please refer to netbeans.apache.org/about/oracle-transition.html..Centra
If not mixed with dummy or any other ones, then the previously mentioned issue is fixable by adding ones in https://mcmap.net/q/2030235/-how-do-i-resolve-could-not-find-artifact-javax-xml-bind-jaxb-api-pom-2-3-0-b161121-1438-in-central-https-repo1-maven-org-maven2 .Centra
I
3

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();
        }
        
    }
It answered 19/12, 2023 at 15:22 Comment(0)
B
3

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:

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).

Burning answered 1/2 at 20:49 Comment(1)
implementation 'org.ehcache:ehcache::jakarta' for GradleFutile
L
2

https://groups.google.com/g/ehcache-users/c/sKfxWuTpY-U

   implementation('org.ehcache:ehcache:3.10.8') {
      capabilities {
        requireCapability('org.ehcache:ehcache-jakarta')
      }
    }
Lily answered 13/11, 2023 at 21:51 Comment(1)
implementation 'org.ehcache:ehcache::jakarta' worked for me.Futile
H
2

javax.xml.bind no longer included in java 11+, you need to include the JAXB dependencies in your gradle or pom.xml.

  <dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.3</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-core</artifactId>
    <version>2.3.0.1</version>
</dependency>

or

implementation 'javax.xml.bind:jaxb-api:2.3.1'
implementation 'org.glassfish.jaxb:jaxb-runtime:2.3.3'
implementation 'org.glassfish.jaxb:jaxb-core:2.3.0.1'
Harakiri answered 11/9 at 15:34 Comment(0)
D
1

you miss some dependency about Validation add below dependency in your project


    <dependency>
      <groupId>jakarta.xml.bind</groupId>
      <artifactId>jakarta.xml.bind-api</artifactId>
      <version>4.0.0</version>
      <scope>compile</scope>
    </dependency>
Drunk answered 24/7, 2023 at 2:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.