Describe the bug
Given a simple application with a RestController backed by JPA/Jdbc connected database.
This application uses following configuration in "application.properties"
quarkus.datasource.url=jdbc:mariadb://localhost:3306/testdb
quarkus.datasource.driver=org.mariadb.jdbc.Driver
quarkus.datasource.username=test
quarkus.datasource.password=1234
quarkus.hibernate-orm.dialect=org.hibernate.dialect.MariaDBDialect
quarkus.hibernate-orm.database.generation = update%test.greeting.message=hello again
%test.quarkus.datasource.url=jdbc:h2:mem:default
%test.quarkus.datasource.driver=org.h2.Driver
%test.quarkus.datasource.username=admin%dev.greeting.message=hello again
%dev.quarkus.datasource.url=jdbc:h2:mem:default
%dev.quarkus.datasource.driver=org.h2.Driver
%dev.quarkus.datasource.username=admin
Expected behavior
Successful build and start of application
mvn clean package
java -Dquarkus.profile=dev -jar ./target/evl-quarkus-runner.jar
Actual behavior
Starting application failed with error
mvn clean package
java -Dquarkus.profile=dev -jar ./target/evl-quarkus-runner.jar
...
Caused by: java.sql.SQLException: Driver does not support the provided URL: jdbc:h2:mem:default
...
It seems that property "quarkus.datasource.driver" is still "filled" with build time value (MySql-Jdbc driver) and this one can't handle this type of url of course.
Looking to code it seems that this property is missing in classes DataSourceRuntimeConfig
and DataSourceRuntimeConfig$$accessor
.
Additionally method AbstractDataSourceProducer.createDataSource()
should be changed slightly to give the runtime values priority over build time
DataSourceRuntimeConfig dataSourceRuntimeConfig =
dataSourceRuntimeConfigOptional.get();
String driverName;
if( dataSourceRuntimeConfig.driver.isPresent() ) {
driverName = dataSourceRuntimeConfig.driver.get();
} else {
driverName = dataSourceBuildTimeConfig.driver.get();
}
To Reproduce
Steps to reproduce the behavior:
see above
Configuration
see above
Screenshots
(If applicable, add screenshots to help explain your problem.)
Environment (please complete the following information):
uname -a
Darwin Bernds-MBP.fritz.box 17.7.0 Darwin Kernel Version 17.7.0: Sun Jun 2 20:31:42 PDT 2019; root:xnu-4570.71.46~1/RELEASE_X86_64 x86_64
java -version
openjdk version "1.8.0_232"
OpenJDK Runtime Environment (build 1.8.0_232-20191009173705.graal.jdk8u-src-tar-gz-b07)
OpenJDK 64-Bit GraalVM CE 19.2.1 (build 25.232-b07-jvmci-19.2-b03, mixed mode)
GraalVM 19.2.1
Quarkus 0.27.0
Additional context
(Add any other context about the problem here.)
Hi @berndfischer63 the quarkus.datasource.url
quarkus.hibernate-orm.dialect
and quarkus.datasource.driver
are build time properties. Once set, they cannot be overridden in runtime.
Running mvn clean package
will build the application with the prod
file thus taking the following configurations
quarkus.datasource.url=jdbc:mariadb://localhost:3306/testdb
quarkus.datasource.driver=org.mariadb.jdbc.Driver
quarkus.datasource.username=test
quarkus.datasource.password=1234
quarkus.hibernate-orm.dialect=org.hibernate.dialect.MariaDBDialect
quarkus.hibernate-orm.database.generation = update
With only these three
quarkus.datasource.url=jdbc:mariadb://localhost:3306/testdb
quarkus.datasource.username=test
quarkus.datasource.password=1234
being overridable during runtime.
Hi @machi1990,
thanks for your fast and detailed answer/explanations - leading me to new questions ;-)
Why does this constraint exist? Because of "compiling" to native executables via SubstrateVM?
From point of view of a user of Quarkus I it still looks more or less confusing - because property quarkus.datasource.url
is overridable during runtime. It is visible from my example above (Quarkus complains about overriden url which isn't the one from prod profile). Additionally this property is present in class DataSourceRuntimeConfig
(making it overridable). Finally it looks possible to override all this properties via environment variables:
# usual java way
QUARKUS_DATASOURCE_DRIVER=org.h2.Driver \
QUARKUS_DATASOURCE_URL=jdbc:h2:mem:default \
java -jar ./target/evl-quarkus-runner.jar
Had no time to test what happens with native executables which is for sure a completely different environment (H2::mem doesn't work in this environment -> have to change my example to use another database).
- Why does this constraint exist? Because of "compiling" to native executables via SubstrateVM?
My short version answer to this is: quarkus.datasource.driver
is build time property (and only visible) at runtime because Hibernate extensions uses during build (where most of optimisations occur) to guess the right dialect to use. Maybe @gsmet, @Sanne or @emmanuelbernard could chim in with a more detailed/elaborative answer.
- From point of view of a user of Quarkus I it still looks more or less confusing - because property
quarkus.datasource.url
is overridable during runtime. It is visible from my example above (Quarkus complains about overriden url which isn't the one from prod profile). Additionally this property is present in classDataSourceRuntimeConfig
(making it overridable). Finally it looks possible to override all this properties via environment variables:
Sorry, I just realized that my reply caused confusion since I copied / mentioned the wrong property quarkus.datasource.url
which is indeed overridable at runtime. It was supposed to be quarkus.hibernate-orm.dialect
. I have corrected my initial reply.
Indeed the dialect
configuration property is encoded as a constant at build time as documented here:
quarkus.hibernate-orm.dialect
Same for the JDBC driver.
Sorry if that's still confusing; we improved the doc about this and I'm looking forward for this to produce an actual warning or error at boot, but that wasn't done yet.
The reason is simple: the more we can "hardcode" during build time, the more we can make very strong optimisations. It's a tradeoff, sometimes the benefit is small, but in this case the benefit is really high as it implies completely swapping out all of the JDBC driver code and all the implications it has on both Hibernate's code and the consequences this has on the metamodel of your application (details such as using a sequence for some ID generation has profound consequences all over).
Clearly we don't want to encode the URL and login/passwords though, that would make the binary way too inconvenient to use - and not safe.
Most configuration options related to tuning, performance etc.. are also typically exposed so that you can change them at runtime - that help to run the application on different server sizes than were it was built - but application design choices are often not useful to be changed after the build - actually it's safer if they are not, so that integration tests have less permutations to cover.
For example, testing with H2 is useful but you should really be ready to test with your "real" database as well, as there's actually many thing that change when you swap DB.
Thanks @machi1990 and @Sanne for detailed and deep explanations - now I understand the intended behaviour (it's not a bug) and the reason(s) behind.
You are welcome @berndfischer63 .
If you wish to generating an executable jar using dev
configurations, you can try building the app with mvn clean install -Dquarkus.profile=dev
. _PS: do not ship the jar in prod_ ;-)
Most helpful comment
Indeed the
dialect
configuration property is encoded as a constant at build time as documented here:quarkus.hibernate-orm.dialect
Same for the JDBC driver.
Sorry if that's still confusing; we improved the doc about this and I'm looking forward for this to produce an actual warning or error at boot, but that wasn't done yet.
The reason is simple: the more we can "hardcode" during build time, the more we can make very strong optimisations. It's a tradeoff, sometimes the benefit is small, but in this case the benefit is really high as it implies completely swapping out all of the JDBC driver code and all the implications it has on both Hibernate's code and the consequences this has on the metamodel of your application (details such as using a sequence for some ID generation has profound consequences all over).
Clearly we don't want to encode the URL and login/passwords though, that would make the binary way too inconvenient to use - and not safe.
Most configuration options related to tuning, performance etc.. are also typically exposed so that you can change them at runtime - that help to run the application on different server sizes than were it was built - but application design choices are often not useful to be changed after the build - actually it's safer if they are not, so that integration tests have less permutations to cover.
For example, testing with H2 is useful but you should really be ready to test with your "real" database as well, as there's actually many thing that change when you swap DB.