Description
During AOT processing, the constructor detection for AOT fails for configuration properties classes that do not declare a default constructor. An example can be found in Spring RESTBucks for MomentsProperties
.
Steps to reproduce:
$ git clone https://github.com/odrotbohm/spring-restbucks
$ cd spring-restbucks/server
$ git checkout hacking/aot-properties
$ ./mvnw -Paot
The output is the following stack trace:
Exception in thread "main" java.lang.IllegalStateException: No constructor or factory method candidate found for Root bean: class [org.springframework.modulith.moments.support.MomentsProperties]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null and argument types []
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorOrFactoryMethod(ConstructorResolver.java:993)
at org.springframework.beans.factory.support.RegisteredBean.resolveConstructorOrFactoryMethod(RegisteredBean.java:212)
at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.<init>(BeanDefinitionMethodGenerator.java:86)
at org.springframework.beans.factory.aot.BeanDefinitionMethodGeneratorFactory.getBeanDefinitionMethodGenerator(BeanDefinitionMethodGeneratorFactory.java:100)
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.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)
ConstructorResolver.resolveConstructor(…)
is given an empty list of value type, as the bean definition for a configuration properties class doesn't have any constructor arguments registered. It will then process the existing complex constructors and disregard them all as they do not match the empty value types.
The problem was originally reported here. To solve that I can work around the problem by adding a default constructor to MomentsProperties
. The reproducer works if built with that change in place.