Issue
I have a problem implementing a second cache manager. At the moment I'm using EhCache, which is working fine. Additionally, I would like to implement Java Simple Cache.
My CacheConfiguration
looks like this:
CacheConfiguration.java
@Configuration
@EnableCaching
@AutoConfigureAfter(value = { MetricsConfiguration.class })
@AutoConfigureBefore(value = { WebConfigurer.class, DatabaseConfiguration.class })
public class CacheConfiguration {
private final javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration;
public CacheConfiguration(JHipsterProperties jHipsterProperties) {
JHipsterProperties.Cache.Ehcache ehcache =
jHipsterProperties.getCache().getEhcache();
jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class,
ResourcePoolsBuilder.heap(ehcache.getMaxEntries()))
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(ehcache.getTimeToLiveSeconds(), TimeUnit.SECONDS)))
.build());
}
/**
* EhCache configuration
*
* @return
*/
@Bean
@Primary
public JCacheManagerCustomizer cacheManagerCustomizer() {
return cm -> {
cm.createCache(com.david.coinlender.domain.News.class.getName(), jcacheConfiguration);
// ...More caches
}
/**
* Java Simple Cache configuration
* @return
*/
@Bean
@Qualifier("simpleCacheManager")
public CacheManager simpleCacheManager() {
SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
simpleCacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("bitfinexAuthCache")));
return simpleCacheManager;
}
}
With Simple Cache I want to cache objects. I.e.:
@Cacheable(cacheManager = "simpleCacheManager", cacheNames = "bitfinexAuthCache", key = "#apiKey.apiKey")
private Exchange createBitfinexAuthenticatedExchange(ApiKeys apiKey) {
ExchangeSpecification exSpec = new BitfinexExchange().getDefaultExchangeSpecification();
exSpec.setApiKey(apiKey.getApiKey());
exSpec.setSecretKey(apiKey.getSecret());
Exchange bfx = ExchangeFactory.INSTANCE.createExchange(BitfinexExchange.class.getName());
bfx.applySpecification(exSpec);
return bfx;
}
However, on Server startup liquibase gives me an error stating:
Caused by: java.lang.IllegalStateException: All Hibernate caches should be created upfront. Please update CacheConfiguration.java to add com.david.coinlender.domain.News
at io.github.jhipster.config.jcache.NoDefaultJCacheRegionFactory.createCache(NoDefaultJCacheRegionFactory.java:37)
at org.hibernate.cache.jcache.JCacheRegionFactory.getOrCreateCache(JCacheRegionFactory.java:190)
at org.hibernate.cache.jcache.JCacheRegionFactory.buildEntityRegion(JCacheRegionFactory.java:113)
at org.hibernate.cache.spi.RegionFactory.buildEntityRegion(RegionFactory.java:132)
at org.hibernate.internal.CacheImpl.determineEntityRegionAccessStrategy(CacheImpl.java:439)
at org.hibernate.metamodel.internal.MetamodelImpl.initialize(MetamodelImpl.java:120)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:297)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:445)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:889)
... 25 common frames omitted
I'm using the Jhipster framework for my appication. I googled this issue for hours now and haven't found a solution yet.
Is this error due to wrong configuration? Can someone please point me in the right direction?
Solution
In JHipster (I did the code), there is in fact two layers of cache. You have Spring Cache and Hibernate Second Level Cache. Both are using the same actual Ehcache CacheManager
.
In your case, you've replaced Ehcache with a simple cache for Spring. But since the NoDefaultJCacheRegionFactory
is still configured on Hibernate, it is still Ehcache that is used for Hibernate. But the customizer isn't used anymore. So it fails.
You would like to have a simple cache for Spring and Ehcache for Hibernate. This means that in fact to don't need to have bean registered for Ehcache in Spring.
The easiest is then to do the following.
First, configure Ehcache in DatabaseConfiguration
. So when the hibernate JCache factory will retrieve it, it will be correctly configured.
public DatabaseConfiguration(Environment env, JHipsterProperties jHipsterProperties) {
this.env = env;
JHipsterProperties.Cache.Ehcache ehcache =
jHipsterProperties.getCache().getEhcache();
CachingProvider provider = Caching.getCachingProvider();
javax.cache.CacheManager cacheManager = provider.getCacheManager();
javax.cache.configuration.Configuration<Object, Object> jcacheConfiguration = Eh107Configuration.fromEhcacheCacheConfiguration(
CacheConfigurationBuilder.newCacheConfigurationBuilder(Object.class, Object.class,
ResourcePoolsBuilder.heap(ehcache.getMaxEntries()))
.withExpiry(Expirations.timeToLiveExpiration(Duration.of(ehcache.getTimeToLiveSeconds(), TimeUnit.SECONDS)))
.build());
cacheManager.createCache(com.mycompany.myapp.domain.User.class.getName(), jcacheConfiguration);
cacheManager.createCache(com.mycompany.myapp.domain.Authority.class.getName(), jcacheConfiguration);
cacheManager.createCache(com.mycompany.myapp.domain.User.class.getName() + ".authorities", jcacheConfiguration);
}
Then, configure Spring Cache.
public class CacheConfiguration {
public CacheConfiguration() {
}
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
Collection<Cache> caches = Arrays.asList(
new ConcurrentMapCache("mycache")
// ...
);
cacheManager.setCaches(caches);
return cacheManager;
}
}
Answered By - Henri