Quarkus JDBC Generic
Connect a Quarkus Agroal datasource to any database via a JDBC driver resolved with reflection at runtime.
Why
The JDBC driver of an Agroal datasource is normally fixed at build time: it is either derived from db-kind by a quarkus-jdbc-* extension or set explicitly with the build-time property quarkus.datasource.jdbc.driver (db-kind=other).
This prevents shipping a single build artifact that is pointed at different databases per deployment, where the driver can only be decided at startup, like the JDBC URL or the pool sizing already can.
Typical use cases:
-
Resolve a driver in JVM mode which is not provided in the default image, for example a Pod with an init container copying the driver into the classpath using an
emptyDirvolume, e.g. because the license of the driver forbids redistributing it. -
Use the same image and switch the driver depending on the environment or customer, i.e. standard Java JDBC usage.
Usage
Add the extension:
<dependency>
<groupId>io.quarkiverse.jdbc</groupId>
<artifactId>quarkus-jdbc-generic</artifactId>
<version>999-SNAPSHOT</version>
</dependency>
Then use the generic database kind and set the driver class at runtime:
quarkus.datasource.db-kind=generic (1)
quarkus.datasource.jdbc-generic.driver=oracle.jdbc.driver.OracleDriver (2)
quarkus.datasource.jdbc.url=jdbc:oracle:thin:@192.168.1.12:1521/ORCL_SVC
quarkus.datasource.username=scott
quarkus.datasource.password=tiger
| 1 | Build-time property selecting the runtime-resolved driver support. |
| 2 | Runtime property; the class is loaded with reflection from the application classpath when the datasource is created. |
The rest of the datasource configuration (JDBC URL, credentials, pool sizing, and so on) is unchanged and read at runtime as usual.
Depending on the actual type of the configured class (java.sql.Driver, javax.sql.DataSource, or javax.sql.XADataSource when quarkus.datasource.jdbc.transactions=xa), the matching Agroal connection provider implementation is used.
| The driver JAR must be part of the application classpath; only the choice of the driver class is deferred to runtime. |
Configuration reference
| Property | Type | Phase | Default |
|---|---|---|---|
|
string (fully qualified class name) |
runtime |
none, required for active |
Native executables
In a native executable, the closed-world assumption still applies: every candidate driver must be part of the application classpath when the native image is built, and the classes actually used with reflection must be registered at build time. With a runtime-resolved driver:
-
When
quarkus.datasource[."datasource-name"].jdbc-generic.driveris set in a configuration source visible at build time, such asapplication.properties, the configured class is automatically registered for reflection in the native image. -
java.sql.Driverimplementations declared through the standardMETA-INF/services/java.sql.Driverfile of the driver JAR are registered automatically in all cases. -
When the property is only provided at runtime, for example through an environment variable, and the class is not a service-declared
java.sql.Driver(typically ajavax.sql.DataSourceorjavax.sql.XADataSourceimplementation), register the candidate classes yourself with@RegisterForReflection(targets = …)or areflection-config.jsonfile.
Reflection registration is often not enough for a JDBC driver in native mode: drivers may also require runtime initialization of some classes, bundled resources, or JNI configuration, which the dedicated quarkus-jdbc-* extensions normally provide. Prefer an existing Quarkus JDBC extension when building native executables.
|
How it works
The extension registers the generic database kind with build-time placeholder driver classes satisfying the build-time validation of the Agroal extension.
At runtime, before the datasource is created, the placeholder entry is substituted with the driver class configured with quarkus.datasource[."datasource-name"].jdbc-generic.driver:
-
eagerly at runtime init, so misconfiguration (missing property, class not loadable, wrong type) aborts the boot with an actionable error;
-
lazily right before Agroal reads the driver class of the datasource it creates, which makes the substitution independent of the startup ordering of datasource consumers such as schema migration tools.
This standalone extension relies on Quarkus Agroal internals (io.quarkus.agroal.runtime.AgroalDataSourceSupport) and is tested against the Quarkus version of its build. A cleaner runtime SPI was proposed upstream in quarkusio/quarkus#55677; if it gets merged this extension will only be needed for older Quarkus versions.
|