Using Spring Boot 3, Spring 6, Java 17 and gradle, when performing a nativeCompile, the compilation fails in the processAot task:

...
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception with message: Failed to determine suitable jdbc url
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:171)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653)
        ... 87 more
...

It seems that the @ConfigurationProperties(prefix = "spring.datasource") is not processed in this case. Typically, when h2 is added to the classpath, then the error does not occur (no other changes required), however I suspect that the postgresql classes will not be present in the native build.

I would've expected the datasource to be present, so the JDBC connection can be used in the native image.

I've created a sample to see this behaviour, see https://github.com/RutgerLubbers/native-acl-jdbc

Comment From: marcusdacoregio

Hi @RutgerLubbers, since that is a Spring Boot application, can't you let Spring Boot create the DataSource for you instead?

Comment From: RutgerLubbers

Hi @marcusdacoregio ,

If native compilation is disabled, then ./gradlew bootRun works. If native compilation is enabled, then it does not seem to get a proper datasource during AOT compilation.

In the example the datasource is defined in the application.yaml. There is a com.ilionx.poc.DataSourceConfig which is just for debugging puposes, its presence does not change the outcome in any manner.

The example does a native compilation which results in an error, so doing a ./gradlew bootRun fails. If the org.graalvm.buildtools.native plugin were to be removed from the build.gradle.kts, then the ./gradlew bootRun works (though not natively).

Adding the h2 database to the dependencies, native compilation does work. However the application does connect to the postgresl database afterwards. Adding a "random" in-memory database to the application is not something I want to do, however it is a workaround (at best).

So, the issue is, why does native compilation fail (without H2)?

(Where I say "bootRun", this also goes for "compileNative", only native compilation without the native compilation plugin fails ;-))

Comment From: wilkinsona

Generally speaking, beans shouldn't be created during AOT processing as it's only bean definitions that are important. There are a few exceptions, for example BeanFactoryPostProcessors are created. Beans related to proxying will also be created as proxy creation has to be performed at build time. It's proxy creation that appears to be the cause of the problem here:

Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'preFilterAuthorizationMethodInterceptor' defined in class path resource [org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.class]: Failed to instantiate [org.springframework.aop.Advisor]: Factory method 'preFilterAuthorizationMethodInterceptor' threw exception with message: Error creating bean with name 'methodSecurityExpressionHandler' defined in class path resource [com/ilionx/poc/SpringSecurityAclConfig.class]: Unsatisfied dependency expressed through method 'methodSecurityExpressionHandler' parameter 0: Error creating bean with name 'aclPermissionEvaluator' defined in class path resource [com/ilionx/poc/SpringSecurityAclConfig.class]: Unsatisfied dependency expressed through method 'aclPermissionEvaluator' parameter 0: Error creating bean with name 'mutableAclService' defined in class path resource [com/ilionx/poc/SpringSecurityAclConfig.class]: Unsatisfied dependency expressed through method 'mutableAclService' parameter 1: Error creating bean with name 'basicLookupStrategy' defined in class path resource [com/ilionx/poc/SpringSecurityAclConfig.class]: Unsatisfied dependency expressed through method 'basicLookupStrategy' parameter 0: Error creating bean with name 'dataSource' defined in class path resource [com/ilionx/poc/DataSourceConfig.class]: Failed to instantiate [javax.sql.DataSource]: Factory method 'dataSource' threw exception with message: Failed to determine a suitable driver class
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:659)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:647)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1332)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1162)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205)
        at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:91)
        at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:111)
        at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:96)
        at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:78)
        at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.determineBeanType(AbstractAutoProxyCreator.java:249)
        at org.springframework.context.support.GenericApplicationContext.preDetermineBeanTypes(GenericApplicationContext.java:431)
        at org.springframework.context.support.GenericApplicationContext.refreshForAotProcessing(GenericApplicationContext.java:413)
        at org.springframework.context.aot.ApplicationContextAotGenerator.lambda$processAheadOfTime$0(ApplicationContextAotGenerator.java:54)
        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)

The link between preFilterAuthorizationMethodInterceptor and the DataSource needs to be broken somehow. Ideally that would happen as close as possible to preFilterAuthorizationMethodInterceptor so that the number of beans created during AOT processing is kept to a minimum.

Comment From: marcusdacoregio

Hi @RutgerLubbers, thanks for the report.

I tried the latest version of your repository and it seems that the error is not happening in Spring Boot 3.1.1. Can you confirm if it was fixed or if the steps to reproduce changed?

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: RutgerLubbers

Hi @marcusdacoregio , sorry, I left the sample in a state where it did work (it included the H2 database), so building did not trigger the error.

I've updated the build file to include all latest versions and the sample now triggers the erroneous behaviour. It is now on Spring Boot 3.1.2.

Comment From: marcusdacoregio

Hi, @RutgerLubbers. Sorry for the delay on this.

The reason why it works when adding the H2 dependency is because the DataSourceProperties tries to resolve the driver class name from the embedded database connection if there is no spring.datasource.driver-class-name property, therefore, the DataSource bean can be created at build-time. When you remove the dependency, the driver cannot be resolved anymore and the error is thrown.

Based on @wilkinsona comment, I think the best option here is to defer the initialization of the MethodSecurityExpressionHandler, similar to what is done with DeferringObservationAuthorizationManager.

I'll reach out to @jzheaux to make sure that there are no obvious side-effects on doing that and then I'll push a fix.

Comment From: RutgerLubbers

Thanks Marcus, Andy! (and others?)