I have a fairly complex application that I've been testing with SB3 milestones, and now snapshots.
It builds and runs fine, except when I switch on the native profile.
2022-09-01T09:49:53.671+01:00 INFO 41206 --- [ main] u.c.m.Application : Starting Application using Java 17.0.4 on mark.Home with PID 41206 (/Users/mark/git/application/target/classes started by mark in /Users/mark/git/application)
2022-09-01T09:49:53.674+01:00 INFO 41206 --- [ main] u.c.m.Application : No active profile set, falling back to 1 default profile: "default"
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.reflect.Executable.getDeclaringClass()" because "executable" is null
at org.springframework.beans.factory.aot.DefaultBeanRegistrationCodeFragments.extractDeclaringClass(DefaultBeanRegistrationCodeFragments.java:84)
at org.springframework.beans.factory.aot.DefaultBeanRegistrationCodeFragments.getTarget(DefaultBeanRegistrationCodeFragments.java:75)
at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:97)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$generateRegisterMethod$2(BeanRegistrationsAotContribution.java:83)
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.generateRegisterMethod(BeanRegistrationsAotContribution.java:81)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$applyTo$1(BeanRegistrationsAotContribution.java:67)
at org.springframework.aot.generate.GeneratedMethod.<init>(GeneratedMethod.java:48)
at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:85)
at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:72)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.applyTo(BeanRegistrationsAotContribution.java:66)
at org.springframework.context.aot.BeanFactoryInitializationAotContributions.applyTo(BeanFactoryInitializationAotContributions.java:78)
at org.springframework.context.aot.ApplicationContextAotGenerator.lambda$processAheadOfTime$0(ApplicationContextAotGenerator.java:58)
at org.springframework.context.aot.ApplicationContextAotGenerator.withGeneratedClassHandler(ApplicationContextAotGenerator.java:66)
at org.springframework.context.aot.ApplicationContextAotGenerator.processAheadOfTime(ApplicationContextAotGenerator.java:53)
at org.springframework.boot.AotProcessor.performAotProcessing(AotProcessor.java:144)
at org.springframework.boot.AotProcessor.process(AotProcessor.java:105)
at org.springframework.boot.AotProcessor.main(AotProcessor.java:213)
As the application is quite large it's quite difficult to try and isolate which part is causing this.
I will keep trying to find the issue however and report back.
I thought it best to raise this as soon as however so you guys are aware, and perhaps you have already seen this issue? I could not find an existing issue raised for it however.
I'm running this with:
openjdk 17.0.4 2022-07-19 LTS
OpenJDK Runtime Environment Corretto-17.0.4.8.1 (build 17.0.4+8-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.4.8.1 (build 17.0.4+8-LTS, mixed mode, sharing)
Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63)
Maven home: /opt/homebrew/Cellar/maven/3.8.6/libexec
Java version: 17.0.4, vendor: Amazon.com Inc., runtime: /Users/mark/.sdkman/candidates/java/17.0.4-amzn
Default locale: en_GB, platform encoding: UTF-8
OS name: "mac os x", version: "12.5", arch: "aarch64", family: "Mac"
Comment From: wilkinsona
Thanks for the report and for trying out our snapshots. I don't recall seeing this problem before.
It would appear that org.springframework.beans.factory.aot.ConstructorOrFactoryMethodResolver.resolve(RegisteredBean)
has returned null
. The method is annotated with @Nullable
so returning null
is reasonable there. It looks like BeanDefinitionMethodGenerator
and the classes that it calls do not then handle the constructorOrFactoryMethod
Executable
being null
. This code is all in Spring Framework so I'll transfer the issue accordingly.
@CynanX, if you're unable to reproduce the problem in a minimal sample it would be interesting to know more about the bean for which the register method cannot be generated. Could you debug your failing application and identify the RegisteredBean
that's causing the problem? It will tell us the bean's name which will then hopefully allow you to provide some more information about how it's defined.
Comment From: CynanX
After a lot of trial & error I've managed to get to the bottom of this, and it was caused by one class in my application.
This particular class has a combination of field and constructor autowired Spring beans, along with a second constructor used by a test class which could override them all.
I've not got time right now, so here is a knocked up example. I'll get a working sample put together later and provide a link if required.
E.g. code scenario: -
@Component("SampleClass")
@Scope("prototype")
public class SampleClass {
private final BeanA beanA;
private final BeanB beanB;
@Autowired
private BeanC beanC;
public SampleClass(BeanA beanA, BeanB beanB) {
this.beanA = beanA;
this.beanB = beanB;
}
@VisibleForTesting
protected SampleClass(BeanA beanA, BeanB beanB, BeanC beanC) {
this.beanA = beanA;
this.beanB = beanB;
this.beanC = beanC;
}
}
Once I commented out the second constructor the application built as expected.
I totally get this is bad code, and I'm not expecting any fixes for it (that said non-native does work with it). However if the error message could indicate the class with the issue in that would be nice.
Comment From: CynanX
Sample application created here.
Comment From: sreenath-tm
I'm interested in contributing to this issue, would you mind sparing your time explaining what the fix would exactly be and pointing me to some resources to get started.
Comment From: snicoll
@CynanX thanks for the sample.
@sreenath-tm thanks for the offer but this one is a little tricky and I am afraid I won't be able to provide direction until I get to the bottom of it. This might be a duplicate of #27920
Comment From: snicoll
@CynanX this fix the error message, not the underlying issue of resolving the constructor. As I was suspecting, the proper fix will happen once we work on https://github.com/spring-projects/spring-framework/issues/27920.
The exception on your sample is now:
Exception in thread "main" java.lang.IllegalStateException: No constructor or factory method candidate found for Root bean: class [com.example.springboot.DemoComponent]; scope=singleton; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodNames=null; destroyMethodNames=null; defined in file [/Users/snicoll/workspace/temp/SpringBoot3AotErrorDemo/target/classes/com/example/springboot/DemoComponent.class] and argument types []
at org.springframework.beans.factory.aot.ConstructorOrFactoryMethodResolver.resolve(ConstructorOrFactoryMethodResolver.java:108)
at org.springframework.beans.factory.aot.ConstructorOrFactoryMethodResolver.resolve(ConstructorOrFactoryMethodResolver.java:394)
Comment From: CynanX
Thanks @snicoll !