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

Misleading error message when no constructor or factory method can be found #29052

Closed
CynanX opened this issue Sep 1, 2022 · 7 comments
Closed
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) theme: aot An issue related to Ahead-of-time processing type: bug A general bug
Milestone

Comments

@CynanX
Copy link

CynanX commented Sep 1, 2022

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"
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Sep 1, 2022
@wilkinsona
Copy link
Member

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.

@bclozel bclozel transferred this issue from spring-projects/spring-boot Sep 1, 2022
@CynanX
Copy link
Author

CynanX commented Sep 1, 2022

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.

@CynanX
Copy link
Author

CynanX commented Sep 2, 2022

Sample application created here.

@sbrannen sbrannen added in: core Issues in core modules (aop, beans, core, context, expression) theme: aot An issue related to Ahead-of-time processing labels Sep 2, 2022
@sbrannen sbrannen added this to the Triage Queue milestone Sep 2, 2022
@sreenath-tm
Copy link
Contributor

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.

@snicoll
Copy link
Member

snicoll commented Sep 5, 2022

@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

@snicoll snicoll self-assigned this Sep 5, 2022
@snicoll snicoll changed the title AoT processing error - Cannot invoke "java.lang.reflect.Executable.getDeclaringClass()" because "executable" is null Misleading error message when no constructor or factory method can be found Sep 6, 2022
@snicoll snicoll added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Sep 6, 2022
@snicoll snicoll modified the milestones: Triage Queue, 6.0.0-M6 Sep 6, 2022
@snicoll snicoll closed this as completed in 903078a Sep 6, 2022
@snicoll
Copy link
Member

snicoll commented Sep 6, 2022

@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 #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)

@CynanX
Copy link
Author

CynanX commented Sep 6, 2022

Thanks @snicoll !

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) theme: aot An issue related to Ahead-of-time processing type: bug A general bug
Projects
None yet
Development

No branches or pull requests

6 participants