Quarkus 和 JDBI 集成:类型 javax.sql.DataSource 和限定符 [@Default] 的不满足依赖性

Quarkus and JDBI integration: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]

我正在尝试使用 Quarkus 和 JDBI — 我想说的是,这方面的例子不多 :/

Gradle 脚本具有以下依赖项:

dependencies {
  implementation(enforcedPlatform("io.quarkus:quarkus-universe-bom:2.1.3.Final"))
  implementation(enforcedPlatform("org.jdbi:jdbi3-bom:3.21.0"))

  implementation("org.jdbi:jdbi3-core")
  implementation("org.jdbi:jdbi3-sqlobject")

  runtimeOnly("io.quarkus:quarkus-config-yaml")
  runtimeOnly("io.quarkus:quarkus-flyway")
  runtimeOnly("io.quarkus:quarkus-jdbc-h2")
  ...
}

我有一个 class 来配置(和集成)JDBI:

@ApplicationScoped
public class PersistenceConfig {
  @Inject
  DataSource dataSource;

  @Singleton
  public Jdbi jdbi() {
    return Jdbi.create(dataSource)
        .installPlugin(new SqlObjectPlugin());
  }

  @Produces
  public ActorRepository actorRepository(final Jdbi jdbi) {
    return jdbi.onDemand(ActorRepository.class);
  }
}

而且我认为问题出在那个(和数据源)中,因为我目前在启动应用程序时遇到此错误:

2021-08-27 11:31:32,852 ERROR [io.qua.dep.dev.IsolatedDevModeMain] (main) Failed to start quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
    [error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]
    - java member: org.acme.config.PersistenceConfig#dataSource
    - declared on CLASS bean [types=[java.lang.Object, org.acme.config.PersistenceConfig], qualifiers=[@Default, @Any], target=org.acme.config.PersistenceConfig]
    at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:1094)
    at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:259)
    at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:129)
    at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:418)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at io.quarkus.deployment.ExtensionLoader.execute(ExtensionLoader.java:820)
    at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
    at org.jboss.threads.ContextHandler.runWith(ContextHandler.java:18)
    at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
    at java.base/java.lang.Thread.run(Thread.java:829)
    at org.jboss.threads.JBossThread.run(JBossThread.java:501)
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]

    - java member: org.acme.config.PersistenceConfig#dataSource
    - declared on CLASS bean [types=[java.lang.Object, org.acme.config.PersistenceConfig], qualifiers=[@Default, @Any], target=org.acme.config.PersistenceConfig]
    at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:492)
    at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:463)
    at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:247)
    ... 13 more

    at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:415)
    at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:275)
    at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:66)
    at io.quarkus.deployment.dev.IsolatedDevModeMain.firstStart(IsolatedDevModeMain.java:91)
    at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:424)
    at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:64)
    at io.quarkus.bootstrap.app.CuratedApplication.runInCl(CuratedApplication.java:136)
    at io.quarkus.bootstrap.app.CuratedApplication.runInAugmentClassLoader(CuratedApplication.java:93)
    at io.quarkus.deployment.dev.DevModeMain.start(DevModeMain.java:145)
    at io.quarkus.deployment.dev.DevModeMain.main(DevModeMain.java:63)
Caused by: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
Caused by: io.quarkus.builder.BuildException: Build failure: Build failed due to errors

    [error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]
    - java member: org.acme.config.PersistenceConfig#dataSource
    - declared on CLASS bean [types=[java.lang.Object, org.acme.config.PersistenceConfig], qualifiers=[@Default, @Any], target=org.acme.config.PersistenceConfig]
    at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:1094)
    at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:259)
    at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:129)
    at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:418)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at io.quarkus.deployment.ExtensionLoader.execute(ExtensionLoader.java:820)
    at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
    at org.jboss.threads.ContextHandler.runWith(ContextHandler.java:18)
    at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
    at java.base/java.lang.Thread.run(Thread.java:829)
    at org.jboss.threads.JBossThread.run(JBossThread.java:501)
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]

    - java member: org.acme.config.PersistenceConfig#dataSource
    - declared on CLASS bean [types=[java.lang.Object, org.acme.config.PersistenceConfig], qualifiers=[@Default, @Any], target=org.acme.config.PersistenceConfig]
    at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:492)
    at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:463)
    at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:247)
    ... 13 more

    at io.quarkus.builder.Execution.run(Execution.java:116)
    at io.quarkus.builder.BuildExecutionBuilder.execute(BuildExecutionBuilder.java:79)
    at io.quarkus.deployment.QuarkusAugmentor.run(QuarkusAugmentor.java:151)
    at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:413)
    ... 9 more
Caused by: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]
Caused by: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]

    - java member: org.acme.config.PersistenceConfig#dataSource
    - declared on CLASS bean [types=[java.lang.Object, org.acme.config.PersistenceConfig], qualifiers=[@Default, @Any], target=org.acme.config.PersistenceConfig]
    at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:1094)
    at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:259)
    at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:129)
    at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:418)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at io.quarkus.deployment.ExtensionLoader.execute(ExtensionLoader.java:820)
    at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
    at org.jboss.threads.ContextHandler.runWith(ContextHandler.java:18)
    at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
    at java.base/java.lang.Thread.run(Thread.java:829)
    at org.jboss.threads.JBossThread.run(JBossThread.java:501)
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]

    - java member: org.acme.config.PersistenceConfig#dataSource
    - declared on CLASS bean [types=[java.lang.Object, org.acme.config.PersistenceConfig], qualifiers=[@Default, @Any], target=org.acme.config.PersistenceConfig]
    at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:492)
    at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:463)
    at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:247)
    ... 13 more

我无法完全理解为什么 datasource 无法注入,因为我已经在 YAML 文件中配置了它:

quarkus:
  datasource:
    db-kind: "h2"
    jdbc:
      url: "jdbc:h2:mem:java_quarkus_graphql;DB_CLOSE_DELAY=-1;MODE=PostgreSQL"
    username: "sa"
  flyway:
    clean-disabled: true
    locations: "classpath:database/migration"
    migrate-at-start: true
    validate-on-migrate: true

我阅读了关于这个主题的 the guide,它应该以 AgroalDataSource 的形式提供——或者只是 DataSource


更新#1

顺便说一下,如果我使用 Quarkus 的旧版本 (1.13.4.Final),这个 setup/configuration 可以工作:

> Task :quarkusDev
Listening for transport dt_socket at address: 5005
__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
2021-08-27 12:55:39,840 |- INFO  in io.quarkus:88 [Quarkus Main Thread] - java-quarkus-graphql 0.1.2-SNAPSHOT on JVM (powered by Quarkus 1.13.4.Final) started in 0.770s. Listening on: http://localhost:8080
2021-08-27 12:55:39,843 |- INFO  in io.quarkus:91 [Quarkus Main Thread] - Profile dev activated. Live Coding activated.
2021-08-27 12:55:39,843 |- INFO  in io.quarkus:92 [Quarkus Main Thread] - Installed features: [agroal, cdi, config-yaml, flyway, hibernate-validator, jdbc-h2, mutiny, narayana-jta, smallrye-context-propagation, smallrye-graphql]

更新#2

版本2.2.1.Final在启动应用程序时没有问题,但在运行测试用例时不知何故失败:

@Stereotype
@QuarkusTest
@Transactional
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface QuarkusTransactionalTest {
  // ...
}
@QuarkusTransactionalTest
final class ActorRepositoryTest {
  @Inject
  ActorRepository repository;

  @Test
  void findById_WhenActorDoesNotExist() {
    Assertions.assertThat(repository.findById(UUID.fromString("c6b1d415-77ee-49c2-b912-fbd00e07702b"))).isNotPresent();
  }

  @Test
  void findById_WhenActorExist() {
    Assertions.assertThat(repository.findById(UUID.fromString("3bea7318-bb7a-4232-9343-59579dd5b2a2")))
        .contains(ActorFactory.penelopeGuiness());
  }
}
ActorRepositoryTest > findById_WhenActorExist() FAILED
    java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
        [error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]
        - java member: org.acme.config.PersistenceConfig#dataSource
        - declared on CLASS bean [types=[java.lang.Object, org.acme.config.PersistenceConfig], qualifiers=[@Default, @Any], target=org.acme.config.PersistenceConfig]
        at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:1100)
        at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:265)
        at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:129)
        at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:418)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at io.quarkus.deployment.ExtensionLoader.execute(ExtensionLoader.java:820)
        at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
        at org.jboss.threads.ContextHandler.runWith(ContextHandler.java:18)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
        at java.base/java.lang.Thread.run(Thread.java:829)
        at org.jboss.threads.JBossThread.run(JBossThread.java:501)
    Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type javax.sql.DataSource and qualifiers [@Default]
        - java member: org.acme.config.PersistenceConfig#dataSource
        - declared on CLASS bean [types=[java.lang.Object, org.acme.config.PersistenceConfig], qualifiers=[@Default, @Any], target=org.acme.config.PersistenceConfig]
        at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:492)
        at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:471)
        at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:253)
        ... 13 more

是的,它适用于 AgroalDataSource

已修复最新 (2.2.3.Final) 版本。