Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AOT processing for bean validation fails with NoClassDefFoundError #33940

Closed
rkudryashov opened this issue Nov 22, 2024 · 3 comments
Closed

AOT processing for bean validation fails with NoClassDefFoundError #33940

rkudryashov opened this issue Nov 22, 2024 · 3 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: superseded An issue that has been superseded by another theme: aot An issue related to Ahead-of-time processing type: regression A bug that is also a regression

Comments

@rkudryashov
Copy link

rkudryashov commented Nov 22, 2024

If I use such a config:

screen

the generated project fails with:

2024-11-22T10:33:43.774+03:00  INFO 21892 --- [demo] [           main] com.example.demo.DemoApplicationKt       : Starting DemoApplicationKt using Java 21.0.1 with PID 21892 (...)
2024-11-22T10:33:43.776+03:00  INFO 21892 --- [demo] [           main] com.example.demo.DemoApplicationKt       : No active profile set, falling back to 1 default profile: "default"
2024-11-22T10:33:44.027+03:00  INFO 21892 --- [demo] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2024-11-22T10:33:44.037+03:00  INFO 21892 --- [demo] [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 5 ms. Found 0 JPA repository interfaces.
Exception in thread "main" java.lang.NoClassDefFoundError: org/reactivestreams/Publisher
        at java.base/java.lang.Class.getDeclaredFields0(Native Method)
        at java.base/java.lang.Class.privateGetDeclaredFields(Class.java:3473)
        at java.base/java.lang.Class.getDeclaredFields(Class.java:2542)
        at org.hibernate.validator.internal.util.privilegedactions.GetDeclaredFields.run(GetDeclaredFields.java:30)
        at org.hibernate.validator.internal.util.privilegedactions.GetDeclaredFields.run(GetDeclaredFields.java:17)
        at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.run(AnnotationMetaDataProvider.java:602)
        at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getFieldMetaData(AnnotationMetaDataProvider.java:217)
        at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.retrieveBeanConfiguration(AnnotationMetaDataProvider.java:130)
        at org.hibernate.validator.internal.metadata.provider.AnnotationMetaDataProvider.getBeanConfiguration(AnnotationMetaDataProvider.java:121)
        at org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl.getBeanConfigurationForHierarchy(BeanMetaDataManagerImpl.java:234)
        at org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl.createBeanMetaData(BeanMetaDataManagerImpl.java:201)
        at org.hibernate.validator.internal.metadata.BeanMetaDataManagerImpl.getBeanMetaData(BeanMetaDataManagerImpl.java:165)
        at org.hibernate.validator.internal.engine.ValidatorImpl.getConstraintsForClass(ValidatorImpl.java:316)
        at org.springframework.validation.beanvalidation.BeanValidationBeanRegistrationAotProcessor$BeanValidationDelegate.processAheadOfTime(BeanValidationBeanRegistrationAotProcessor.java:125)
        at org.springframework.validation.beanvalidation.BeanValidationBeanRegistrationAotProcessor$BeanValidationDelegate.lambda$processAheadOfTime$0(BeanValidationBeanRegistrationAotProcessor.java:170)
        at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:728)
        at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:707)
        at org.springframework.validation.beanvalidation.BeanValidationBeanRegistrationAotProcessor$BeanValidationDelegate.processAheadOfTime(BeanValidationBeanRegistrationAotProcessor.java:150)
        at org.springframework.validation.beanvalidation.BeanValidationBeanRegistrationAotProcessor$BeanValidationDelegate.processAheadOfTime(BeanValidationBeanRegistrationAotProcessor.java:110)
        at org.springframework.validation.beanvalidation.BeanValidationBeanRegistrationAotProcessor.processAheadOfTime(BeanValidationBeanRegistrationAotProcessor.java:75)
        at org.springframework.beans.factory.aot.BeanDefinitionMethodGeneratorFactory.getAotContributions(BeanDefinitionMethodGeneratorFactory.java:155)
        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:49)
        at org.springframework.beans.factory.aot.BeanRegistrationsAotProcessor.processAheadOfTime(BeanRegistrationsAotProcessor.java:37)
        at org.springframework.context.aot.BeanFactoryInitializationAotContributions.processAheadOfTime(BeanFactoryInitializationAotContributions.java:82)
        at org.springframework.context.aot.BeanFactoryInitializationAotContributions.getContributions(BeanFactoryInitializationAotContributions.java:69)
        at org.springframework.context.aot.BeanFactoryInitializationAotContributions.<init>(BeanFactoryInitializationAotContributions.java:52)
        at org.springframework.context.aot.BeanFactoryInitializationAotContributions.<init>(BeanFactoryInitializationAotContributions.java:47)
        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: java.lang.ClassNotFoundException: org.reactivestreams.Publisher
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
        ... 37 more

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':processAot'.
> Process 'command '...'' finished with non-zero exit value 1

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 2s
5 actionable tasks: 3 executed, 2 up-to-date

There is no error if I comment out any of the following lines:

implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-validation")

If needed, the repro project is here.

@odrotbohm
Copy link
Member

I wonder if we could skip BeanDefinitions with role BeanDefinition.ROLE_INFRASTRUCTURE from the Hibernate Validator scanning, as they're unlikely to carry any validation annotations in the first place.

@hpoettker
Copy link
Contributor

hpoettker commented Nov 22, 2024

JPA is not required to reproduce the issue. At least, I also see it with spring-boot-starter-jdbc and spring-boot-starter-validation.

The root cause seems to be that the BeanValidationBeanRegistrationAotProcessor processes TransactionInterceptor, which extends TransactionAspectSupport and has field of type ConcurrentMap<Method, ReactiveTransactionSupport>. And the reference to org.reactivestreams.Publisher seems to come from here.

The processor is prepared to just carry on when it encounters a TypeNotPresentException, maybe it should do the same for NoClassDefFoundError: https://github.com/spring-projects/spring-framework/blob/main/spring-context/src/main/java/org/springframework/validation/beanvalidation/BeanValidationBeanRegistrationAotProcessor.java#L133

@sbrannen sbrannen changed the title Failed build of a project genereated with Spring Initializr AOT processing for bean validation fails with NoClassDefFoundError Nov 23, 2024
@sbrannen sbrannen added type: regression A bug that is also a regression in: core Issues in core modules (aop, beans, core, context, expression) theme: aot An issue related to Ahead-of-time processing and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Nov 23, 2024
@sbrannen sbrannen added this to the 6.2.1 milestone Nov 23, 2024
@sbrannen sbrannen self-assigned this Nov 23, 2024
@sbrannen
Copy link
Member

@sbrannen sbrannen closed this as not planned Won't fix, can't repro, duplicate, stale Nov 23, 2024
@sbrannen sbrannen removed this from the 6.2.1 milestone Nov 23, 2024
@sbrannen sbrannen added status: superseded An issue that has been superseded by another type: bug A general bug type: regression A bug that is also a regression and removed type: regression A bug that is also a regression type: bug A general bug labels Nov 23, 2024
sbrannen added a commit that referenced this issue Nov 27, 2024
Prior to this commit, AOT processing for bean validation failed with a
NoClassDefFoundError for constraints with missing dependencies.

With this commit, the processing no longer fails, and a warning is
logged instead.

See gh-33940
Closes gh-33949

Co-authored-by: Sam Brannen <sam.brannen@broadcom.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: superseded An issue that has been superseded by another theme: aot An issue related to Ahead-of-time processing type: regression A bug that is also a regression
Projects
None yet
5 participants