Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot 2 war file attempts to load el-api v3.0 class (NoClassDefFoundError: javax/el/ELManager) on tomcat 7 (el-api 2.2)

I have a Spring boot 2 gradle project That I hope to deploy as a (non-executable) war file to a tomcat 7 instance (RHEL).

I am receiving a NoClassDefFoundError when deploying the war to tomcat on the server:

...
Caused by: org.hibernate.cfg.beanvalidation.IntegrationException: Error activating Bean Validation integration
        at org.hibernate.cfg.beanvalidation.BeanValidationIntegrator.integrate(BeanValidationIntegrator.java:138)
        at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:281)
        at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:462)
        at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:892)
        at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:57)
        at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365)
        at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:390)
        ... 34 more
Caused by: java.lang.NoClassDefFoundError: javax/el/ELManager
        at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:88)
        at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:47)
        at org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultMessageInterpolator(ConfigurationImpl.java:474)
        at org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultMessageInterpolatorConfiguredWithClassLoader(ConfigurationImpl.java:650)
        at org.hibernate.validator.internal.engine.ConfigurationImpl.getMessageInterpolator(ConfigurationImpl.java:397)
        at org.hibernate.validator.internal.engine.ValidatorFactoryImpl.<init>(ValidatorFactoryImpl.java:183)
        at org.hibernate.validator.HibernateValidator.buildValidatorFactory(HibernateValidator.java:38)
        at org.hibernate.validator.internal.engine.ConfigurationImpl.buildValidatorFactory(ConfigurationImpl.java:364)
        at javax.validation.Validation.buildDefaultValidatorFactory(Validation.java:103)
        at org.hibernate.cfg.beanvalidation.TypeSafeActivator.getValidatorFactory(TypeSafeActivator.java:501)
        at org.hibernate.cfg.beanvalidation.TypeSafeActivator.activate(TypeSafeActivator.java:84)
        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:498)
        at org.hibernate.cfg.beanvalidation.BeanValidationIntegrator.integrate(BeanValidationIntegrator.java:132)
        ... 40 more

On inspection I find that the hibernate bean validation library has failed to find this particular class (javax.el.ElManager) during initialization.

The solution here suggests adding the correct el-api v3.0 dependency to the runtime but I'm not sure this is a wise solution because the el-api v2.2 already exists amongst the shared (providedRuntime in gradle vernacular) libraries in Tomcat. I'm concerned about ClassLoader issues if I have 2 versions of the same API (Is this a reasonable concern?).

Upgrading to tomcat 8 is a no-go, as we run tomcat7 on RHEL which currently only supports tomcat 7.

How do I tell Spring to use javax el-api v2.2?

Additional Notes

The default tomcat.version when depending on spring-boot-starter-tomcat seems to be 8.5.31 according to the gradlew dependencies command:

+--- org.springframework.boot:spring-boot-starter-tomcat:2.0.2.RELEASE
|    +--- javax.annotation:javax.annotation-api:1.3.2
|    +--- org.apache.tomcat.embed:tomcat-embed-core:8.5.31
|    +--- org.apache.tomcat.embed:tomcat-embed-el:8.5.31
|    \--- org.apache.tomcat.embed:tomcat-embed-websocket:8.5.31

As I understand from another post, settings the gradle ext['tomcat.version'] property to 7.0.76 (our server's version) resolves these dependencies correctly:

+--- org.springframework.boot:spring-boot-starter-tomcat:2.0.2.RELEASE
|    +--- javax.annotation:javax.annotation-api:1.3.2
|    +--- org.apache.tomcat.embed:tomcat-embed-core:8.5.31 -> 7.0.76
|    +--- org.apache.tomcat.embed:tomcat-embed-el:8.5.31 -> 7.0.76
|    \--- org.apache.tomcat.embed:tomcat-embed-websocket:8.5.31 -> 7.0.76
|         \--- org.apache.tomcat.embed:tomcat-embed-core:7.0.76

However I still run into this NoClassDefFoundError. It seems to me that Spring does not recognise the correct api version and continues assuming the ElManager is present.

Thank you for your time.

like image 403
coderatchet Avatar asked May 24 '18 01:05

coderatchet


1 Answers

Spring Boot 2.X only supports Tomcat >= 8.5.X

After trying to modify the transitive dependencies of the default spring configs (namely hibernate-validator), I came across documentation for Spring Boot 2's minimum server requirements: Tomcat 8.5.X. Alongside that, only servlet APIs of 3.1+ are supported

The fundamental problem I am fighting against here - which will undoubtedly produce problems down the line if I changed the dependencies - is that Tomcat 7 is not supported by Spring Boot 2. Any transitive library I downgrade may break some other dependency which requires its updated functionality.

Spring Boot 1.5.X does however support Tomcat 7 and Servlet 3.0 application servers. So the solution is to downgrade to Spring Boot 1.5.X (currently at 1.5.13 at time of writing).

Alternatively - and the solution I will be pressing with the systems team here at my workplace - Is to instead use embedded servlet containers (i.e. tomcat 8.5/9 embedded). Unfortunately for me, That means a long discussion into the modification of existing enterprise processes that assumes a deployment mechanism. But that is besides the point :P

like image 123
coderatchet Avatar answered Oct 20 '22 07:10

coderatchet