spring-boot icon indicating copy to clipboard operation
spring-boot copied to clipboard

Native image - HV000183: Unable to initialize 'jakarta.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead

Open Azbesciak opened this issue 2 years ago • 3 comments

Hello, After building the native image in spring boot 3.0.2, there are problems with beans annotated with @Validated. The following exception is thrown, for instance, for the fresh spring cloud project (initialzr -> spring 3.0.2, graalvm, cloud gateway, security). It runs without any problem on the normal JVM (even with spring.aot.enabled=true what unfortunately does not surprise me, since it did not change anything in none of my tests).

Caused by: org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'gatewayProperties': Could not bind properties to 'GatewayProperties' : prefix=spring.cloud.gateway, ignoreInvalidFields=false, ignoreUnknownFields=true
2023-01-26T20:38:17.644912100Z     at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.bind(ConfigurationPropertiesBindingPostProcessor.java:99) ~[com.example.spring.gateway.ApiGatewayApplicationKt:3.0.2]
2023-01-26T20:38:17.644917000Z     at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:79) ~[com.example.spring.gateway.ApiGatewayApplicationKt:3.0.2]
2023-01-26T20:38:17.644922000Z     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:420) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T20:38:17.644926900Z     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1743) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T20:38:17.644932000Z     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T20:38:17.644936700Z     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T20:38:17.644941500Z     at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T20:38:17.644947300Z     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T20:38:17.644952200Z     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T20:38:17.644956900Z     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T20:38:17.644961500Z     at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T20:38:17.644966500Z     at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1405) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T20:38:17.644972000Z     at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1325) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T20:38:17.644976900Z     at org.springframework.beans.factory.aot.BeanInstanceSupplier.resolveArgument(BeanInstanceSupplier.java:334) ~[na:na]
2023-01-26T20:38:17.644985200Z     ... 21 common frames omitted
2023-01-26T20:38:17.644989600Z Caused by: jakarta.validation.ValidationException: HV000183: Unable to initialize 'jakarta.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead
2023-01-26T20:38:17.644994600Z     at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:211) ~[na:na]

I mentioned it also in https://github.com/spring-cloud/spring-cloud-gateway/issues/2802#issuecomment-1405628494 . That exception is also thrown on JVM, but it is swallowed on some step, whereas it is not in the native run - some try catch is missing, maybe connected with @ConfigurationProperties processing.

Also, I faced another problem when I replaced every bean with that annotation, which is connected with ValidationAutoConfiguration

Caused by: jakarta.validation.ValidationException: HV000183: Unable to initialize 'jakarta.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead
2023-01-26T21:20:21.808504200Z 	at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:211) ~[na:na]
2023-01-26T21:20:21.808508600Z 	at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:97) ~[na:na]
2023-01-26T21:20:21.808512600Z 	at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getDefaultMessageInterpolator(AbstractConfigurationImpl.java:575) ~[com.example.spring.gateway.ApiGatewayApplicationKt:8.0.0.Final]
2023-01-26T21:20:21.808516400Z 	at org.springframework.boot.validation.MessageInterpolatorFactory.getMessageInterpolator(MessageInterpolatorFactory.java:79) ~[na:na]
2023-01-26T21:20:21.808519500Z 	at org.springframework.boot.validation.MessageInterpolatorFactory.getObject(MessageInterpolatorFactory.java:70) ~[na:na]
2023-01-26T21:20:21.808523000Z 	at org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration.defaultValidator(ValidationAutoConfiguration.java:64) ~[com.example.spring.gateway.ApiGatewayApplicationKt:na]
2023-01-26T21:20:21.808531400Z 	at org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration__BeanDefinitions.lambda$getDefaultValidatorInstanceSupplier$0(ValidationAutoConfiguration__BeanDefinitions.java:33) ~[na:na]
2023-01-26T21:20:21.808535000Z 	at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:68) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T21:20:21.808538100Z 	at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:54) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T21:20:21.808554900Z 	at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$get$2(BeanInstanceSupplier.java:208) ~[na:na]
2023-01-26T21:20:21.808558000Z 	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:59) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T21:20:21.808597500Z 	at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:47) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T21:20:21.808631500Z 	at org.springframework.beans.factory.aot.BeanInstanceSupplier.invokeBeanSupplier(BeanInstanceSupplier.java:220) ~[na:na]
2023-01-26T21:20:21.808636000Z 	at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:208) ~[na:na]
2023-01-26T21:20:21.808640500Z 	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[com.example.spring.gateway.ApiGatewayApplicationKt:6.0.4]
2023-01-26T21:20:21.808643900Z 	... 18 common frames omitted
2023-01-26T21:20:21.808646900Z Caused by: java.lang.NoClassDefFoundError: jakarta.el.ELManager
2023-01-26T21:20:21.808649900Z 	at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:194) ~[na:na]
2023-01-26T21:20:21.808653100Z 	... 32 common frames omitted
2023-01-26T21:20:21.808656100Z 

BTW does org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration should be possible to exclude via springautoconfigure.exclude? It is annotated with @AutoConfiguration, but it even runs on JVM when excluded there...

Azbesciak avatar Jan 27 '23 05:01 Azbesciak

I don't think we need a Spring Boot issue for this in addition to the existing Spring Cloud issue. @OlgaMaciaszek has re-opened the Spring Cloud issue and is investigating. Closing in favour of the Cloud issue for now at least.

wilkinsona avatar Jan 27 '23 08:01 wilkinsona

We have a smoke test for validation that covers @Validated on a @ConfigurationProperties class that is passing. Therefore, we know that this works in the general case. I suspect there's something different about Spring Cloud or your application which is causing a failure. Olga's investigating that and there's no point in us duplicating her effort. If she discovers a problem in Boot we can re-open this issue to fix it. Until then, please be patient and allow Olga to look into things.

wilkinsona avatar Jan 27 '23 08:01 wilkinsona

https://github.com/spring-cloud/spring-cloud-gateway/issues/2802#issuecomment-1405628494 describes multiple problems and Olga's going to focus on the ReactiveOAuth2AuthorizedClientManager side of things.

@Azbesciak As I said above, we believe that validation of configuration properties works in a native image. If you'd like us to investigate why it is not working for you, please provide a minimal sample that reproduces the NoClassDefFoundError for jakarta.el.ELManager. You can share such a sample with us by zipping it up and attaching it to this issue or by pushing it to a separate repository on Github.

wilkinsona avatar Jan 27 '23 11:01 wilkinsona

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

spring-projects-issues avatar Feb 03 '23 11:02 spring-projects-issues

From boot 3.0.5, gateway 2022.0.2 and during processAot:

Exception in thread "main" java.lang.ExceptionInInitializerError                                                                                                          
        at org.springframework.validation.beanvalidation.BeanValidationBeanRegistrationAotProcessor.processAheadOfTime(BeanValidationBeanRegistrationAotProcessor.java:67)
        at org.springframework.beans.factory.aot.BeanDefinitionMethodGeneratorFactory.getAotContributions(BeanDefinitionMethodGeneratorFactory.java:151)                  
        at org.springframework.beans.factory.aot.BeanDefinitionMethodGeneratorFactory.getBeanDefinitionMethodGenerator(BeanDefinitionMethodGeneratorFactory.java:99)      
        at org.springframework.beans.factory.aot.BeanDefinitionMethodGeneratorFactory.getBeanDefinitionMethodGenerator(BeanDefinitionMethodGeneratorFactory.java:115)     
        at org.springframework.beans.factory.aot.BeanRegistrationsAotProcessor.processAheadOfTime(BeanRegistrationsAotProcessor.java:48)                                  
        at org.springframework.beans.factory.aot.BeanRegistrationsAotProcessor.processAheadOfTime(BeanRegistrationsAotProcessor.java:36)                                  
        at org.springframework.context.aot.BeanFactoryInitializationAotContributions.getContributions(BeanFactoryInitializationAotContributions.java:67)                  
        at org.springframework.context.aot.BeanFactoryInitializationAotContributions.<init>(BeanFactoryInitializationAotContributions.java:49)                            
        at org.springframework.context.aot.BeanFactoryInitializationAotContributions.<init>(BeanFactoryInitializationAotContributions.java:44)                            
        at org.springframework.context.aot.ApplicationContextAotGenerator.lambda$processAheadOfTime$0(ApplicationContextAotGenerator.java:58)
        at org.springframework.context.aot.ApplicationContextAotGenerator.withCglibClassHandler(ApplicationContextAotGenerator.java:67)
        at org.springframework.context.aot.ApplicationContextAotGenerator.processAheadOfTime(ApplicationContextAotGenerator.java:53)
        at org.springframework.context.aot.ContextAotProcessor.performAotProcessing(ContextAotProcessor.java:106)
        at org.springframework.context.aot.ContextAotProcessor.doProcess(ContextAotProcessor.java:84)
        at org.springframework.context.aot.ContextAotProcessor.doProcess(ContextAotProcessor.java:49)
        at org.springframework.context.aot.AbstractAotProcessor.process(AbstractAotProcessor.java:82)
        at org.springframework.boot.SpringApplicationAotProcessor.main(SpringApplicationAotProcessor.java:80)
Caused by: jakarta.validation.ValidationException: HV000183: Unable to initialize 'jakarta.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead
        at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:211)
        at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:97)
        at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getDefaultMessageInterpolator(AbstractConfigurationImpl.java:575)
        at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getDefaultMessageInterpolatorConfiguredWithClassLoader(AbstractConfigurationImpl.java:834)
        at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getMessageInterpolator(AbstractConfigurationImpl.java:485)
        at org.hibernate.validator.internal.engine.ValidatorFactoryImpl.<init>(ValidatorFactoryImpl.java:155)
        at org.hibernate.validator.HibernateValidator.buildValidatorFactory(HibernateValidator.java:38)
        at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.buildValidatorFactory(AbstractConfigurationImpl.java:453)
        at jakarta.validation.Validation.buildDefaultValidatorFactory(Validation.java:103)
        at org.springframework.validation.beanvalidation.BeanValidationBeanRegistrationAotProcessor$BeanValidationDelegate.getValidatorIfAvailable(BeanValidationBeanRegistrationAotProcessor.java:81)
        at org.springframework.validation.beanvalidation.BeanValidationBeanRegistrationAotProcessor$BeanValidationDelegate.<clinit>(BeanValidationBeanRegistrationAotProcessor.java:76)
        ... 17 more
Caused by: java.lang.NoClassDefFoundError: jakarta/el/ELManager

Still occurs.

Azbesciak avatar Apr 03 '23 04:04 Azbesciak

The Spring Cloud Gateway issue is still open, so I wouldn't expect this situation to have changed.

scottfrederick avatar Apr 03 '23 12:04 scottfrederick

https://github.com/spring-cloud/spring-cloud-gateway/issues/2802 was closed on 30th Jan.

OlgaMaciaszek avatar Apr 11 '23 13:04 OlgaMaciaszek

@Azbesciak As far as I can tell, we're still where we were back in January when I made this comment:

As I said above, we believe that validation of configuration properties works in a native image. If you'd like us to investigate why it is not working for you, please provide a minimal sample that reproduces the NoClassDefFoundError for jakarta.el.ELManager. You can share such a sample with us by zipping it up and attaching it to this issue or by pushing it to a separate repository on Github.

You haven't provided the requested sample so no further progress has been made.

wilkinsona avatar Apr 11 '23 14:04 wilkinsona

@Azbesciak As far as I can tell, we're still where we were back in January when I made this comment:

As I said above, we believe that validation of configuration properties works in a native image. If you'd like us to investigate why it is not working for you, please provide a minimal sample that reproduces the for . You can share such a sample with us by zipping it up and attaching it to this issue or by pushing it to a separate repository on Github.NoClassDefFoundError``jakarta.el.ELManager

You haven't provided the requested sample so no further progress has been made.

I also encountered the same problem: https://github.com/vicasong/valid-error-demo But I don't want to introduce a class that doesn't use: "jakarta.el.ExpressionFactory"

vicasong avatar Jun 27 '23 08:06 vicasong

@vicasong, thanks for the sample. Please open a Spring Framework issue for this. During AOT processing, Framework's BeanValidationBeanRegistrationAotProcessor.BeanValidationDelegate is calling Validation.buildDefaultValidatorFactory().getValidator(). This fails because there's no EL implementation on the classpath and it does not take into account your custom Validator configuration where you've configured the use of a ParameterMessageInterpolator such that EL should not be required.

wilkinsona avatar Jun 27 '23 09:06 wilkinsona

Is there any news? Have you found a solution to the problem? Or at least, do you know where it is? Please share any new information with us. @wilkinsona @vicasong @Azbesciak

ZadeAbderrahmane avatar Nov 26 '23 08:11 ZadeAbderrahmane

I needed to override the whole GatewayAutoConfiguration with dependencies to avoid loading beans validation, same as all beans which require it... for instance HttpClientProperties or GatewayProperties (even in 3.1.x).

Azbesciak avatar Nov 26 '23 10:11 Azbesciak

I found two ways to address this issue:

Add the jakarta-el dependency seems obvious, but the only version that worked was the one from glassfish: jakarta-el v4.0.2

The second workaround was to explicitly specify a message interpolator to work along with jakarta Validator, in this case, I used the ParameterMessageInterpolator from hibernate validator that was already being used as validator for the project sent by @vicasong. The code below is an example implementation:

import jakarta. validation.*;
import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator;

public class MyValidator {

    public void validate() {
        ValidatorFactory factory = Validation.byDefaultProvider()
                .configure()
                .messageInterpolator(new ParameterMessageInterpolator())
                .buildValidatorFactory();
         Validator validator = factory.usingContext()
                .getValidator();

        Set<ConstraintViolation<Customer>> violations = validator.validate(bean);
    }
}


The main problem to address in this issue was the message interpolator that has been used since Bean Validation v2.0 . Although Hibernate Validator is the most commonly used validator alongside Bean Validator (ref), the default message interpolator is provided by jakarta-el, which was not adequately loaded, leading to the error when instantiating ValidatorFactoryImpl in HibernateValidator.buildValidatorFactory(ConfigurationState configurationState). The error occurs because configurationState.defaultMessageInterpolator value should be an implementation of MessageInterpolator interface but ended up null.

image

image

gabcamilo avatar Jan 05 '24 06:01 gabcamilo

I have to upgrade mongo drivers to use time series collection in my java application.

build.sbt have below entries

  "org.mongodb" % "mongodb-driver-sync" % "4.9.0",
  "org.mongodb" % "mongodb-driver-legacy" % "4.9.0",
  "dev.morphia.morphia" % "morphia" % "2.4.2",
  "dev.morphia.morphia" % "entityscanner-plug" % "1.6.1",
  "dev.morphia.morphia" % "logging-slf4j" % "1.6.1",
  "dev.morphia.morphia" % "morphia-validation" % "2.4.13",

  "jakarta.validation" % "jakarta.validation-api" % "3.1.0",
  "org.hibernate.validator" % "hibernate-validator" % "8.0.1.Final",
  "jakarta.el" % "jakarta.el-api" % "4.0.0",
  "org.glassfish" % "jakarta.el" % "4.0.2" % "test",
  "org.glassfish.jaxb" % "jaxb-runtime" % "2.3.1" % "runtime",

I am creating morphia validator as below

		morphia = new Morphia(new Mapper(options));
		// Configure validator
		new ValidationExtension();`

getting below error on run

jakarta.validation.ValidationException: HV000183: Unable to initialize 'jakarta.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead
	at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:211)
	at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:97)
	at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getDefaultMessageInterpolator(AbstractConfigurationImpl.java:575)
	at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getDefaultMessageInterpolatorConfiguredWithClassLoader(AbstractConfigurationImpl.java:834)
	at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getMessageInterpolator(AbstractConfigurationImpl.java:485)
Caused by: java.lang.NoClassDefFoundError: com/sun/el/ExpressionFactoryImpl
	at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:203)
	at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:97)
	at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getDefaultMessageInterpolator(AbstractConfigurationImpl.java:575)
	at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getDefaultMessageInterpolatorConfiguredWithClassLoader(AbstractConfigurationImpl.java:834)
	at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getMessageInterpolator(AbstractConfigurationImpl.java:485)
Caused by: java.lang.ClassNotFoundException: com.sun.el.ExpressionFactoryImpl
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
	at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:203)
	at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.<init>(ResourceBundleMessageInterpolator.java:97)

on debug I found this exception is coming from - dev.morphia.validation.ValidationExtension class on below code

public ValidationExtension() {
        validationFactory = Validation.byDefaultProvider()
                .configure()
                .buildValidatorFactory();}

this class also have errors regarding interface methods - Class 'ValidationExtension' must either be declared abstract or implement abstract method 'postLoad(Object, DBObject, Mapper)' in 'EntityInterceptor'

any suggestion to solve this please.

Chenramvijay avatar Jun 06 '24 13:06 Chenramvijay

@Chenramvijay Judging by your dependencies, your problem doesn't have anything to do with Spring Boot. Please ask on Stack Overflow.

wilkinsona avatar Jun 06 '24 14:06 wilkinsona