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...

Comment From: wilkinsona

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.

Comment From: 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.

Comment From: 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.

Comment From: spring-projects-issues

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.

Comment From: Azbesciak

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.

Comment From: scottfrederick

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

Comment From: OlgaMaciaszek

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

Comment From: 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 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.

Comment From: vicasong

@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"

Comment From: wilkinsona

@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.

Comment From: ZadeAbderrahmane

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

Comment From: 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).

Comment From: gabcamilo

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.

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

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

Comment From: Chenramvijay

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.

Comment From: wilkinsona

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