spring-boot
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
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...
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.
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.
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.
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.
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.
The Spring Cloud Gateway issue is still open, so I wouldn't expect this situation to have changed.
https://github.com/spring-cloud/spring-cloud-gateway/issues/2802 was closed on 30th Jan.
@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
NoClassDefFoundErrorforjakarta.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.
@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.ELManagerYou 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, 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.
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
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).
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.
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 Judging by your dependencies, your problem doesn't have anything to do with Spring Boot. Please ask on Stack Overflow.