Hibernate 5.3 with Ehcache 3.5.2 configuration problem

I try to migrate our application from Hibernate 5.2 with Ehcache 2 to Hibernate 5.3 with Jcache and Ehcache 3.

I have a problem to get Hibernate (EntityManagerFactory) started with enabled Jcache/Ehcache in my Tomcat webserver. The problem is: The configuration file ehcache.xml is not found.
I don’t know how to configure the location of this configuration file. Probably it’s a problem with the URI.The result is a (catched) javax.cache.CacheException: org.ehcache.xml.exceptions.XmlConfigurationException: Error parsing XML configuration at file:/META-INF/ehcache.xml in in AbstractRegionFactory.start().

These are my relevant JARs:
cache-api-1.0.0.jar
ehcache-3.5.2.jar
hibernate-commons-annotations-5.0.3.Final.jar
hibernate-core-5.3.0.Final.jar
hibernate-jcache-5.3.0.Final.jar

This is my configuration for the second level cache:
“hibernate.cache.region.factory_class”, “jcache”
“hibernate.javax.cache.provider”, “org.ehcache.jsr107.EhcacheCachingProvider”
“hibernate.javax.cache.uri”, “file:///META-INF/ehcache.xml” // tried many alternative values

The location of my ehcache.xml is
<TOMCAT_HOME>/webapps/myApp/WEB-INF/classes/META-INF/ehcache.xml

What is the correct value of the property “hibernate.javax.cache.uri”?

  • When I put this ehcache.xml in my root directory C: and configure “file:///ehcache.xml”, the configuration file is found and parsed and everything seems to work fine. But that is not the correct location…

Thank you very much in advance!

Sounds like the file was found but it couldn’t be parsed. Try the suggestion in this StackOverflow answer.

Thank you Vlad, but the ehcache.xml is ok.
If I put the ehcache.xml to “C:” (windows) and set property “hibernate.javax.cache.uri” to “file:///ehcache.xml”, it works

Maybe this bug is the problem
https://hibernate.atlassian.net/browse/HHH-12531

So I haven’t found a way to configure a relative path to the ehcache.xml yet.

That might explain why it does not work for you. Most likely, it’s a bug.

This workaround seems to work:

Map<String, String> configuration = new HashMap<>(); 
configuration.put("hibernate.cache.region.factory_class", "jcache");
configuration.put("hibernate.javax.cache.provider", "org.ehcache.jsr107.EhcacheCachingProvider");
URL uRL = getClass().getResource("/META-INF/ehcache.xml");
String ehcache = "file:///" + uRL.getFile();
configuration.put("hibernate.javax.cache.uri", ehcache);

EntityManagerFactory = Persistence.createEntityManagerFactory(persistencemanager, configuration);

If someone has a better idea…

Did you try a classpath:// prefixed URL?

I know there are many libraries out there supporting this.

I tried with “classpath://META-INF/ecache.xml”, in this case the result is a
javax.cache.CacheException: java.net.MalformedURLException: unknown protocol: classpath

The stacktrace is
URI.toURL() line: 1089 [local variables unavailable]
EhcacheCachingProvider$ConfigSupplier.getConfiguration() line: 327
EhcacheCachingProvider.getCacheManager(EhcacheCachingProvider$ConfigSupplier, Properties) line: 127
EhcacheCachingProvider.getCacheManager(URI, ClassLoader, Properties) line: 78
EhcacheCachingProvider.getCacheManager(URI, ClassLoader) line: 186
JCacheRegionFactory.resolveCacheManager(SessionFactoryOptions, Map) line: 143

I wrote a fix for this bug.Just copy to your project file org.hibernate.cache.jcache.internal.JCacheRegionFactory.java and rewrite that method:

@SuppressWarnings("WeakerAccess")
protected CacheManager resolveCacheManager(SessionFactoryOptions settings, Map properties) {
	final Object explicitCacheManager = properties.get( ConfigSettings.CACHE_MANAGER );
	if ( explicitCacheManager != null ) {
		return useExplicitCacheManager( settings, explicitCacheManager );
	}

	final CachingProvider cachingProvider = getCachingProvider( properties );
	final CacheManager cacheManager;
	final URI cacheManagerUri = getUri( properties );
	// ***** begin patch ******
	URI uri = cacheManagerUri;
	URL url = null;
	try {
		uri.toURL();
	} catch (Exception e) {
		try {
			url = getClassLoader(cachingProvider).getResource(cacheManagerUri.toString());
			uri = url.toURI();
		} catch (Exception e1) {
			throw new IllegalArgumentException("Resource not found: " + uri, e1);
		}
	}
	// ****** end patch ******
	if ( cacheManagerUri != null ) {
		cacheManager = cachingProvider.getCacheManager( uri, getClassLoader( cachingProvider ));
	}
	else {
		cacheManager = cachingProvider.getCacheManager();
	}
	return cacheManager;
}

You can now set

<property name="hibernate.javax.cache.uri" value="ehcache.xml"/>

and place ehcache.xml on root of classpath.

Please send a Pull Request to the Hibernate project. Thanks.

Hello @vlad,

Did anyone reported this bug and provided a pull request ?
I didn’t find it searching jira… if you could point to it :slight_smile:

This one was fixed by HHH-12979. You need to upgrade to 5.4.1.

1 Like

Yes, I can confirm this is fixed.

Sadly, hibernate and spring use different classpath syntaxes.

Before this was fixed, I used TomcatURLStreamHandlerFactory.register() and could use the following spring boot configuration:

spring.cache.jcache.config=classpath:META-INF/ehcache-jsr107-config-spring.xml
spring.jpa.properties.hibernate.javax.cache.uri=classpath:META-INF/ehcache-jsr107-config-hibernate.xml

Now although the issue is fixed, if I remove the TomcatURLStreamHandlerFactory.register() my application will not start. This is because:

  • Hibernate requires prefix: “classpath://”
  • Spring requires prefix “classpath:” (without double slash)

Therefore I had to adjust my spring boot application.properties as follows:

spring.cache.jcache.config=classpath:META-INF/ehcache-jsr107-config-spring.xml
spring.jpa.properties.hibernate.javax.cache.uri=classpath://META-INF/ehcache-jsr107-config-hibernate.xml

I don’t like it that I have to use different classpath url syntaxes.
But it is still better then the TomcatURLStreamHandlerFactory workaround.

@vlad What do you think. Any chance to have the syntaxes aligned?

UPDATE

Everything I said above is true in our test environment.

As soon as the application is deployed to tomcat, the following Exception occurs:

Caused by: java.io.FileNotFoundException: Unable to load the resource [classpath://META-INF/ehcache-jsr107-config-hibernate.xml] using the thread context class loader or the current class’s class loader
at org.apache.catalina.webresources.ClasspathURLStreamHandler.openConnection(ClasspathURLStreamHandler.java:45)

So, it would be great if hibernate would also support the other classpath syntax.
For now, I will have to use the TomcatURLStreamHandlerFactory workaround again.