stormpath-sdk-java icon indicating copy to clipboard operation
stormpath-sdk-java copied to clipboard

Spring Boot application startup fails when an existing cache exists (e.g. EhCache)

Open mraible opened this issue 7 years ago • 11 comments

When an existing cache configuration exists and Stormpath caches are not configured, startup fails with:

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stormpathApplication' defined in class path resource [com/stormpath/spring/boot/autoconfigure/StormpathAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.stormpath.sdk.application.Application]: Factory method 'stormpathApplication' threw exception; nested exception is java.lang.IllegalArgumentException: spring cache instance cannot be null.
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1128)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1023)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    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:202)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:207)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1128)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1056)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
    ... 35 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.stormpath.sdk.application.Application]: Factory method 'stormpathApplication' threw exception; nested exception is java.lang.IllegalArgumentException: spring cache instance cannot be null.
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
    ... 47 common frames omitted
Caused by: java.lang.IllegalArgumentException: spring cache instance cannot be null.
    at com.stormpath.sdk.lang.Assert.notNull(Assert.java:80)
    at com.stormpath.spring.cache.SpringCache.<init>(SpringCache.java:38)
    at com.stormpath.spring.cache.SpringCacheManager.getCache(SpringCacheManager.java:72)

At the very least, we should print the name of the cache that's missing so users can add this to their existing cache configuration. See https://github.com/mraible/jhipster-stormpath-example/issues/2 for more information.

mraible avatar Oct 07 '16 18:10 mraible

I'm confused - Spring's CacheManager, if one exists, will lazily create caches by name automatically - there is no need to define/pre-configure cache objects within the cache manager.

If no Spring CacheManager exists, we should default to the DisabledCacheManager.

2 separate issues, no?

lhazlewood avatar Oct 07 '16 19:10 lhazlewood

Maybe Spring's default cache manager does this, but JHipster uses EhCache and EhCacheCacheManager appears to be the CacheManager in play. It doesn't seem to create caches by name automatically. See the example app's CacheConfiguration.java to see how it's configured. If there's a way to configure it so it auto-creates caches, great!

mraible avatar Oct 07 '16 19:10 mraible

Ehcache supports this automatically - it's called a defaultCache. It sounds like JHipster should probably want to ensure that's enabled? Most EHCache users I've seen have it enabled because it's often painful without it.

http://www.ehcache.org/documentation/2.8/configuration/configuration.html

While a defaultCache configuration is not required, an error is generated if caches are created by name (programmatically) with no defaultCache loaded.

lhazlewood avatar Oct 07 '16 22:10 lhazlewood

The ehcache.xml generated by JHipster seems to have a defaultCache.

mraible avatar Oct 07 '16 22:10 mraible

@lhazlewood Here's how to reproduce this issue in examples/spring-boot-webmvc-angular:

  1. Add dependencies for Spring Boot's caching autoconfiguration and EhCache:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache-core</artifactId>
        <version>2.6.10</version>
    </dependency>
    
  2. Add an ehcache.xml file to src/main/resources:

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
             name="CM1"
             updateCheck="false"
             maxBytesLocalHeap="16M">
    
        <diskStore path="java.io.tmpdir"/>
    
        <defaultCache
                eternal="false"
                overflowToDisk="false"
        />
    </ehcache>
    
  3. Add a CacheConfiguration.java class that configures EhCache:

    package com.stormpath.spring.boot.examples;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.annotation.EnableCaching;
    import org.springframework.cache.ehcache.EhCacheCacheManager;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import javax.annotation.PreDestroy;
    
    @Configuration
    @EnableCaching
    public class CacheConfiguration {
    
        private final Logger log = LoggerFactory.getLogger(CacheConfiguration.class);
    
        private net.sf.ehcache.CacheManager cacheManager;
    
        @PreDestroy
        public void destroy() {
            cacheManager.shutdown();
        }
    
        @Bean
        public CacheManager cacheManager() {
            log.debug("Starting Ehcache");
            cacheManager = net.sf.ehcache.CacheManager.create();
            cacheManager.getConfiguration().setMaxBytesLocalHeap("16M");
            EhCacheCacheManager ehCacheManager = new EhCacheCacheManager();
            ehCacheManager.setCacheManager(cacheManager);
            return ehCacheManager;
        }
    }
    
  4. Start the app and watch it blow up.

mraible avatar Oct 10 '16 16:10 mraible

FYI: I tried generating a JHipster application with Hazelcast instead of EhCache and everything works w/o additional configuration.

mraible avatar Oct 20 '16 19:10 mraible

To get auto creation, you can do this

<?xml version="1.0" encoding="UTF-8"?>
<config
    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    xmlns='http://www.ehcache.org/v3'
    xmlns:jsr107='http://www.ehcache.org/v3/jsr107'
    xsi:schemaLocation="
        http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.0.xsd
        http://www.ehcache.org/v3/jsr107 http://www.ehcache.org/schema/ehcache-107-ext-3.0.xsd">

    <service>
        <jsr107:defaults default-template="simple"/>
    </service>

    <cache-template name="simple">
        <expiry>
            <ttl unit="seconds">3600</ttl>
        </expiry>
        <heap>100</heap>
    </cache-template>

</config>

More details in Ehcache documentation

henri-tremblay avatar Nov 01 '16 20:11 henri-tremblay

Thanks for the tip @henri-tremblay! I tried this ehcache.xml config in your JHipster fullstack sample (after integrating Stormpath). Unfortunately, it doesn't work. Not sure if this is a Stormpath issue or caused by EhCache.

Caused by: java.lang.IllegalArgumentException: spring cache instance cannot be null.
    at com.stormpath.sdk.lang.Assert.notNull(Assert.java:80)
    at com.stormpath.spring.cache.SpringCache.<init>(SpringCache.java:38)
    at com.stormpath.spring.cache.SpringCacheManager.getCache(SpringCacheManager.java:72)
    at com.stormpath.sdk.impl.ds.cache.DefaultCacheResolver.getCache(DefaultCacheResolver.java:40)
    at com.stormpath.sdk.impl.ds.cache.AbstractCacheFilter.getCache(AbstractCacheFilter.java:74)
    at com.stormpath.sdk.impl.ds.cache.AbstractCacheFilter.getCachedValue(AbstractCacheFilter.java:48)
    at com.stormpath.sdk.impl.ds.cache.ReadCacheFilter.getCachedResourceData(ReadCacheFilter.java:91)
    at com.stormpath.sdk.impl.ds.cache.ReadCacheFilter.filter(ReadCacheFilter.java:55)
    at com.stormpath.sdk.impl.ds.DefaultFilterChain.filter(DefaultFilterChain.java:52)
    at com.stormpath.sdk.impl.ds.api.DecryptApiKeySecretFilter.filter(DecryptApiKeySecretFilter.java:63)
    at com.stormpath.sdk.impl.ds.DefaultFilterChain.filter(DefaultFilterChain.java:52)
    at com.stormpath.sdk.impl.ds.EnlistmentFilter.filter(EnlistmentFilter.java:42)
    at com.stormpath.sdk.impl.ds.DefaultFilterChain.filter(DefaultFilterChain.java:52)
    at com.stormpath.sdk.impl.ds.DefaultDataStore.getResourceData(DefaultDataStore.java:330)
    at com.stormpath.sdk.impl.ds.DefaultDataStore.getResource(DefaultDataStore.java:245)
    at com.stormpath.sdk.impl.ds.DefaultDataStore.getResource(DefaultDataStore.java:233)
    at com.stormpath.sdk.impl.client.DefaultClient.getCurrentTenant(DefaultClient.java:103)
    at com.stormpath.sdk.impl.client.DefaultClient.getApplications(DefaultClient.java:220)
    at com.stormpath.spring.config.AbstractStormpathConfiguration.stormpathApplication(AbstractStormpathConfiguration.java:134)
    at com.stormpath.spring.boot.autoconfigure.StormpathAutoConfiguration.stormpathApplication(StormpathAutoConfiguration.java:44)
    at com.stormpath.spring.boot.autoconfigure.StormpathAutoConfiguration$$EnhancerBySpringCGLIB$$1a69bbf2.CGLIB$stormpathApplication$1(<generated>)
    at com.stormpath.spring.boot.autoconfigure.StormpathAutoConfiguration$$EnhancerBySpringCGLIB$$1a69bbf2$$FastClassBySpringCGLIB$$ac7a5be0.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356)
    at com.stormpath.spring.boot.autoconfigure.StormpathAutoConfiguration$$EnhancerBySpringCGLIB$$1a69bbf2.stormpathApplication(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)

mraible avatar Nov 01 '16 20:11 mraible

I'm just not sure about something. Are you using Ehcache3 and JSR107?

henri-tremblay avatar Nov 01 '16 21:11 henri-tremblay

Yes, because I'm producing this problem in the fullstack example you posted. I can create a branch with PR to show the problem if you like.

mraible avatar Nov 01 '16 21:11 mraible

Please do. I meant: "Is stormpath ready to use Ehcache 3 or JCache?"

On 1 November 2016 at 17:30, Matt Raible [email protected] wrote:

Yes, because I'm producing this problem in the fullstack example you posted. I can create a branch with PR to show the problem if you like.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/stormpath/stormpath-sdk-java/issues/1024#issuecomment-257704312, or mute the thread https://github.com/notifications/unsubscribe-auth/ABKRM3ItQDYEklWtkJlP7ruzi7x3mKh-ks5q569sgaJpZM4KRWQj .

henri-tremblay avatar Nov 01 '16 21:11 henri-tremblay