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

Flyway-specific DataSource cannot be created in a native image due to missing reflection hints #33692

Closed
mishraomp opened this issue Jan 5, 2023 · 8 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@mishraomp
Copy link

Hi Team,
could anyone please look into this and let me know the workaround for the issue? or if there is a fix planned for this one.
Spring Boot Version: 3.0.1
Sample GitHub Repo:- https://github.com/mishraomp/spring-reactive
On JVM mode the app starts fine but in native mode it throws exception during startup. I have pasted the log outputs for the same.

JVM mode

2023-01-04T14:59:14.678-08:00  INFO 20988 --- [           main] com.om.example.SbReactiveApplication     : Starting SbReactiveApplication using Java 17 with PID 20988 (C:\projects\personal\spring-reactive\target\classes started by ompra in C:\projects\personal\spring-reactive)
2023-01-04T14:59:14.681-08:00  INFO 20988 --- [           main] com.om.example.SbReactiveApplication     : No active profile set, falling back to 1 default profile: "default"
2023-01-04T14:59:15.231-08:00  INFO 20988 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data R2DBC repositories in DEFAULT mode.
2023-01-04T14:59:15.331-08:00  INFO 20988 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 96 ms. Found 1 R2DBC repository interfaces.
2023-01-04T14:59:16.958-08:00  INFO 20988 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 14 endpoint(s) beneath base path ''
2023-01-04T14:59:17.189-08:00  INFO 20988 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 9.5.1 by Redgate
2023-01-04T14:59:17.189-08:00  INFO 20988 --- [           main] o.f.c.internal.license.VersionPrinter    : See what's new here: https://flywaydb.org/documentation/learnmore/releaseNotes#9.5.1
2023-01-04T14:59:17.190-08:00  INFO 20988 --- [           main] o.f.c.internal.license.VersionPrinter    :
2023-01-04T14:59:17.468-08:00  INFO 20988 --- [           main] o.f.c.i.database.base.BaseDatabaseType   : Database: jdbc:postgresql://localhost:5432/default (PostgreSQL 15.1)
2023-01-04T14:59:17.518-08:00  INFO 20988 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.020s)
2023-01-04T14:59:17.547-08:00  INFO 20988 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table "public"."flyway_schema_history" ...
2023-01-04T14:59:17.645-08:00  INFO 20988 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema "public": << Empty Schema >>
2023-01-04T14:59:17.659-08:00  INFO 20988 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "public" to version "1.0.0 - API"
2023-01-04T14:59:17.711-08:00  INFO 20988 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema "public", now at version v1.0.0 (execution time 00:00.079s)
2023-01-04T14:59:18.023-08:00  INFO 20988 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 3000
2023-01-04T14:59:18.043-08:00  INFO 20988 --- [           main] com.om.example.SbReactiveApplication     : Started SbReactiveApplication in 3.78 seconds (process running for 4.213)

Native Mode

2023-01-04 14:54:47  :: Spring Boot ::                (v3.0.1)
2023-01-04 14:54:47 
2023-01-04 14:54:47 2023-01-04T22:54:47.534Z  INFO 1 --- [           main] com.om.example.SbReactiveApplication     : Starting AOT-processed SbReactiveApplication using Java 17.0.5 with PID 1 (/workspace/com.om.example.SbReactiveApplication started by cnb in /workspace)
2023-01-04 14:54:47 2023-01-04T22:54:47.534Z  INFO 1 --- [           main] com.om.example.SbReactiveApplication     : No active profile set, falling back to 1 default profile: "default"
2023-01-04 14:54:47 2023-01-04T22:54:47.637Z  INFO 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 14 endpoint(s) beneath base path ''
2023-01-04 14:54:47 2023-01-04T22:54:47.672Z  WARN 1 --- [           main] .r.c.ReactiveWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flyway': Unexpected exception during bean creation
2023-01-04 14:54:47 2023-01-04T22:54:47.673Z ERROR 1 --- [           main] o.s.boot.SpringApplication               : Application run failed
2023-01-04 14:54:47 
2023-01-04 14:54:47 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flyway': Unexpected exception during bean creation
2023-01-04 14:54:47     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:534) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[com.om.example.SbReactiveApplication:3.0.1]
2023-01-04 14:54:47     at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) ~[com.om.example.SbReactiveApplication:3.0.1]
2023-01-04 14:54:47     at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) ~[com.om.example.SbReactiveApplication:3.0.1]
2023-01-04 14:54:47     at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[com.om.example.SbReactiveApplication:3.0.1]
2023-01-04 14:54:47     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) ~[com.om.example.SbReactiveApplication:3.0.1]
2023-01-04 14:54:47     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) ~[com.om.example.SbReactiveApplication:3.0.1]
2023-01-04 14:54:47     at com.om.example.SbReactiveApplication.main(SbReactiveApplication.java:21) ~[com.om.example.SbReactiveApplication:na]
2023-01-04 14:54:47 Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.jdbc.datasource.SimpleDriverDataSource]: No default constructor found
2023-01-04 14:54:47     at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:146) ~[na:na]
2023-01-04 14:54:47     at org.springframework.boot.jdbc.DataSourceBuilder.build(DataSourceBuilder.java:175) ~[com.om.example.SbReactiveApplication:3.0.1]
2023-01-04 14:54:47     at org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration$FlywayConfiguration.getMigrationDataSource(FlywayAutoConfiguration.java:162) ~[com.om.example.SbReactiveApplication:na]
2023-01-04 14:54:47     at org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration$FlywayConfiguration.configureDataSource(FlywayAutoConfiguration.java:149) ~[com.om.example.SbReactiveApplication:na]
2023-01-04 14:54:47     at org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration$FlywayConfiguration.flyway(FlywayAutoConfiguration.java:138) ~[com.om.example.SbReactiveApplication:na]
2023-01-04 14:54:47     at org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration__BeanDefinitions$FlywayConfiguration__BeanDefinitions.lambda$getFlywayInstanceSupplier$0(FlywayAutoConfiguration__BeanDefinitions.java:99) ~[na:na]
2023-01-04 14:54:47     at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:68) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.util.function.ThrowingBiFunction.apply(ThrowingBiFunction.java:54) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.beans.factory.aot.BeanInstanceSupplier.lambda$get$2(BeanInstanceSupplier.java:208) ~[na:na]
2023-01-04 14:54:47     at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:59) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:47) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.beans.factory.aot.BeanInstanceSupplier.invokeBeanSupplier(BeanInstanceSupplier.java:220) ~[na:na]
2023-01-04 14:54:47     at org.springframework.beans.factory.aot.BeanInstanceSupplier.get(BeanInstanceSupplier.java:208) ~[na:na]
2023-01-04 14:54:47     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainInstanceFromSupplier(AbstractAutowireCapableBeanFactory.java:1225) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1210) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1157) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[com.om.example.SbReactiveApplication:6.0.3]
2023-01-04 14:54:47     ... 14 common frames omitted
2023-01-04 14:54:47 Caused by: java.lang.NoSuchMethodException: org.springframework.jdbc.datasource.SimpleDriverDataSource.<init>()
2023-01-04 14:54:47     at java.base@17.0.5/java.lang.Class.getConstructor0(DynamicHub.java:3585) ~[com.om.example.SbReactiveApplication:na]
2023-01-04 14:54:47     at java.base@17.0.5/java.lang.Class.getDeclaredConstructor(DynamicHub.java:2754) ~[com.om.example.SbReactiveApplication:na]
2023-01-04 14:54:47     at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:141) ~[na:na]
2023-01-04 14:54:47     ... 31 common frames omitted
2023-01-04 14:54:47
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jan 5, 2023
@wilkinsona
Copy link
Member

Thanks for the report. We're missing some reflection hints that allow the Flyway-specific DataSource to be created. You can work around this by providing the necessary hints manually:

class DataSourceBuilderHints implements RuntimeHintsRegistrar {

    @Override
    public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
      hints.reflection().registerType(SimpleDriverDataSource.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
    }

}

This registrar can be imported using @ImportRuntimeHints on your SbReactiveApplication class:

@ImportRuntimeHints(DataSourceBuilderHints.class)

@wilkinsona wilkinsona changed the title Spring Webflux with flyway fails to start in native mode. Flyway-specific DataSource cannot be created in a native image due to missing reflection hints Jan 5, 2023
@wilkinsona wilkinsona added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Jan 5, 2023
@wilkinsona wilkinsona added this to the 3.0.x milestone Jan 5, 2023
@mishraomp
Copy link
Author

Thank you so much @wilkinsona for the quick response, the app now works in native mode.

2023-01-05 09:32:46  :: Spring Boot ::                (v3.0.1)
2023-01-05 09:32:46 
2023-01-05 09:32:46 2023-01-05T17:32:46.735Z  INFO 1 --- [           main] com.om.example.SbReactiveApplication     : Starting AOT-processed SbReactiveApplication using Java 17.0.5 with PID 1 (/workspace/com.om.example.SbReactiveApplication started by cnb in /workspace)
2023-01-05 09:32:46 2023-01-05T17:32:46.735Z  INFO 1 --- [           main] com.om.example.SbReactiveApplication     : No active profile set, falling back to 1 default profile: "default"
2023-01-05 09:32:46 2023-01-05T17:32:46.809Z  INFO 1 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 14 endpoint(s) beneath base path ''
2023-01-05 09:32:46 2023-01-05T17:32:46.837Z  INFO 1 --- [           main] o.f.c.internal.license.VersionPrinter    : Flyway Community Edition 9.5.1 by Redgate
2023-01-05 09:32:46 2023-01-05T17:32:46.837Z  INFO 1 --- [           main] o.f.c.internal.license.VersionPrinter    : See what's new here: https://flywaydb.org/documentation/learnmore/releaseNotes#9.5.1
2023-01-05 09:32:46 2023-01-05T17:32:46.837Z  INFO 1 --- [           main] o.f.c.internal.license.VersionPrinter    : 
2023-01-05 09:32:46 2023-01-05T17:32:46.837Z  WARN 1 --- [           main] o.f.core.internal.util.FeatureDetector   : Unable to scan location: /db/migration (unsupported protocol: resource)
2023-01-05 09:32:46 2023-01-05T17:32:46.837Z  WARN 1 --- [           main] o.f.c.i.s.classpath.ClassPathScanner     : Unable to scan location: /db/migration (unsupported protocol: resource)
2023-01-05 09:32:46 2023-01-05T17:32:46.850Z  INFO 1 --- [           main] o.f.c.i.database.base.BaseDatabaseType   : Database: jdbc:postgresql://sb-reactive-db:5432/default (PostgreSQL 15.1)
2023-01-05 09:32:46 2023-01-05T17:32:46.855Z  INFO 1 --- [           main] o.f.core.internal.command.DbValidate     : Successfully validated 1 migration (execution time 00:00.001s)
2023-01-05 09:32:46 2023-01-05T17:32:46.860Z  INFO 1 --- [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table "public"."flyway_schema_history" ...
2023-01-05 09:32:46 2023-01-05T17:32:46.896Z  INFO 1 --- [           main] o.f.core.internal.command.DbMigrate      : Current version of schema "public": << Empty Schema >>
2023-01-05 09:32:46 2023-01-05T17:32:46.897Z  INFO 1 --- [           main] o.f.core.internal.command.DbMigrate      : Migrating schema "public" to version "1.0.0 - API"
2023-01-05 09:32:46 2023-01-05T17:32:46.915Z  INFO 1 --- [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema "public", now at version v1.0.0 (execution time 00:00.020s)
2023-01-05 09:32:46 2023-01-05T17:32:46.917Z  WARN 1 --- [           main] i.m.c.i.binder.jvm.JvmGcMetrics          : GC notifications will not be available because MemoryPoolMXBeans are not provided by the JVM
2023-01-05 09:32:46 2023-01-05T17:32:46.924Z  INFO 1 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 3000
2023-01-05 09:32:46 2023-01-05T17:32:46.925Z  INFO 1 --- [           main] com.om.example.SbReactiveApplication     : Started SbReactiveApplication in 0.204 seconds (process running for 0.208)

@wilkinsona
Copy link
Member

There are a couple of ways that we could fix this:

  1. Provide a hint for SimpleDriverDataSource when Flyway's in the picture
  2. Update DataSourceBuilder to provide a method that takes a Supplier<D extends DataSource> to avoid reflectively creating the DataSource instance.

The second option is a more general solution. This would benefit org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration.LiquibaseConfiguration, and org.springframework.boot.autoconfigure.sql.init.DataSourceInitializationConfiguration which all rely on reflection at the moment and I suspect will have a similar problem.

@wilkinsona wilkinsona self-assigned this Jan 10, 2023
@wilkinsona
Copy link
Member

https://github.com/wilkinsona/spring-boot/tree/gh-33692 contains an implementation of the second option. There are a couple of further considerations that I would like to discuss with the team:

  1. Should we update the documentation to use the new method rather than type(Class)?
  2. Should we even go as far as deprecating the type(Class) method?

@wilkinsona wilkinsona added the for: team-meeting An issue we'd like to discuss as a team to make progress label Jan 10, 2023
@philwebb
Copy link
Member

Team discussion: 1) yes. 2) also yes

@philwebb philwebb removed the for: team-meeting An issue we'd like to discuss as a team to make progress label Jan 11, 2023
@philwebb philwebb self-assigned this Jan 11, 2023
@wilkinsona
Copy link
Member

wilkinsona commented Jan 12, 2023

The failures in this comment are interesting in the context of DataSourceBuilder and reflection. The sample does this:

@Bean(name = "db1ServerDataSource")
@ConfigurationProperties("db1")
DataSource db1ServerDataSource() {
    return DataSourceBuilder.create().build();
}

Hikari's on the classpath so DataSourceBuilder tries to use it. It then fails to reflectively create a HikariDataSource instance. With a reflection hint for this in place, it then fails to call setJdbcUrl during configuration property binding. This is due to the bean method's return type being DataSource so no hints are generated for binding to HikariDataSource. While related to this issue, I think a different solution will be needed so perhaps this should be handled as a separate issue or pair of issues?

@philwebb
Copy link
Member

I wonder if adding hints might be a safer and less invasive option at this point? It's slightly annoying that the onus is on the caller to add the supplier. Hints might also allow the example above to work unchanged.

Here's something I think might work https://github.com/philwebb/spring-boot/tree/gh-33692-2

@philwebb
Copy link
Member

We're going to go with the hints approach for now since it doesn't require any API changes. Longer term, we may well look into adding supplier support.

@philwebb philwebb modified the milestones: 3.0.x, 3.0.2 Jan 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

4 participants