I'm getting what seems to be a strange error when I run my Play app (which seems to be the story of my life right now). The other day, I ran into this issue , solved that, was able to run the evolutions and create the tables, and then ran into the following:
java.lang.RuntimeException: Property driver does not exist on target class com.zaxxer.hikari.HikariConfig
Here is the relevant section from my current application.conf:
db.default {
dataSourceClassName = org.postgresql.ds.PGSimpleDataSource
url = "jdbc:postgresql://localhost:5432/app-users?user=root&password=root"
driver = org.postgresql.Driver
username = root
password = root
databaseName = app-users
portNumber = 5432
serverName = localhost
connectionTimeout = 30000
}
I did some digging and found that Hikari expects driverClassName
(along with a few other differences). The Hikari docs and the Quill docs say that something like this should be in the application.conf:
dataSourceClassName=org.postgresql.ds.PGSimpleDataSource
dataSource.user=root
dataSource.password=root
dataSource.databaseName=app-users
dataSource.portNumber=5432
dataSource.serverName=localhost
However, when I have that, the evolutions won't run. They will only run when I have it as I currently do. Since the evolutions are running, it seems like it is connecting to the db. So why would I get a message saying that it can't? Is there a way for me to have a separate db config for Hikari and Postgres/Quill?
Full error message:
play.api.UnexpectedException: Unexpected exception[IllegalStateException: Failed to load data source for config: 'Config(SimpleConfigObject({"connectionTimeout":30000,"dataSourceClassName":"org.postgresql.ds.PGSimpleDataSource","databaseName":"mack-users","driver":"org.postgresql.Driver","password":"root","portNumber":5432,"serverName":"localhost","url":"jdbc:postgresql://localhost:5432/mack-users?user=root&password=root","username":"root"}))']
at play.core.server.DevServerStart$$anon$1.reload(DevServerStart.scala:186)
at play.core.server.DevServerStart$$anon$1.get(DevServerStart.scala:124)
at play.core.server.AkkaHttpServer.modelConversion(AkkaHttpServer.scala:183)
at play.core.server.AkkaHttpServer.handleRequest(AkkaHttpServer.scala:189)
at play.core.server.AkkaHttpServer.$anonfun$createServerBinding$3(AkkaHttpServer.scala:106)
at akka.stream.impl.fusing.MapAsync$$anon$24.onPush(Ops.scala:1191)
at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:512)
at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:475)
at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:371)
at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:584)
Caused by: java.lang.IllegalStateException: Failed to load data source for config: 'Config(SimpleConfigObject({"connectionTimeout":30000,"dataSourceClassName":"org.postgresql.ds.PGSimpleDataSource","databaseName":"mack-users","driver":"org.postgresql.Driver","password":"root","portNumber":5432,"serverName":"localhost","url":"jdbc:postgresql://localhost:5432/mack-users?user=root&password=root","username":"root"}))'
at io.getquill.JdbcContextConfig.dataSource(JdbcContextConfig.scala:24)
at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:17)
at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:18)
at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:19)
at db.db.package$DBContext.<init>(package.scala:6)
at MyComponents.ctx$lzycompute(MyApplicationLoader.scala:25)
at MyComponents.ctx(MyApplicationLoader.scala:25)
at MyComponents.userService$lzycompute(MyApplicationLoader.scala:28)
at MyComponents.userService(MyApplicationLoader.scala:28)
at MyComponents.applicationController$lzycompute(MyApplicationLoader.scala:35)
Caused by: java.lang.RuntimeException: Property driver does not exist on target class com.zaxxer.hikari.HikariConfig
at com.zaxxer.hikari.util.PropertyElf.setProperty(PropertyElf.java:131)
at com.zaxxer.hikari.util.PropertyElf.lambda$setTargetFromProperties$0(PropertyElf.java:57)
at java.util.Hashtable.forEach(Hashtable.java:879)
at com.zaxxer.hikari.util.PropertyElf.setTargetFromProperties(PropertyElf.java:52)
at com.zaxxer.hikari.HikariConfig.<init>(HikariConfig.java:132)
at io.getquill.JdbcContextConfig.dataSource(JdbcContextConfig.scala:21)
at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:17)
at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:18)
at io.getquill.PostgresJdbcContext.<init>(PostgresJdbcContext.scala:19)
at db.db.package$DBContext.<init>(package.scala:6)
db/package.scala
import io.getquill.{PostgresJdbcContext, SnakeCase}
package object db {
class DBContext(config: String) extends PostgresJdbcContext(SnakeCase, config)
trait Repository {
val ctx: DBContext
}
}
Any ideas on what could cause this? Or what I am missing?
Using:
Error message when I put what Quill/Hikari expect:
! @776d39n6c - Internal server error, for (GET) [/] ->
play.api.Configuration$$anon$1: Configuration error[Cannot connect to database [default]]
at play.api.Configuration$.configError(Configuration.scala:156)
at play.api.Configuration.reportError(Configuration.scala:990)
at play.api.db.DefaultDBApi.$anonfun$connect$1(DefaultDBApi.scala:48)
at play.api.db.DefaultDBApi.$anonfun$connect$1$adapted(DefaultDBApi.scala:42)
at scala.collection.immutable.List.foreach(List.scala:389)
at play.api.db.DefaultDBApi.connect(DefaultDBApi.scala:42)
at play.api.db.DBApiProvider.get$lzycompute(DBModule.scala:86)
at play.api.db.DBApiProvider.get(DBModule.scala:75)
at play.api.db.DBComponents.dbApi(DBModule.scala:49)
at play.api.db.DBComponents.dbApi$(DBModule.scala:49)
Caused by: play.api.Configuration$$anon$1: Configuration error[dataSource or dataSourceClassName or jdbcUrl is required.]
at play.api.Configuration$.configError(Configuration.scala:156)
at play.api.Configuration.reportError(Configuration.scala:990)
at play.api.db.HikariCPConnectionPool.create(HikariCPModule.scala:63)
at play.api.db.PooledDatabase.createDataSource(Databases.scala:199)
at play.api.db.DefaultDatabase.dataSource$lzycompute(Databases.scala:123)
at play.api.db.DefaultDatabase.dataSource(Databases.scala:121)
at play.api.db.DefaultDatabase.getConnection(Databases.scala:142)
at play.api.db.DefaultDatabase.getConnection(Databases.scala:138)
at play.api.db.DefaultDBApi.$anonfun$connect$1(DefaultDBApi.scala:44)
at play.api.db.DefaultDBApi.$anonfun$connect$1$adapted(DefaultDBApi.scala:42)
Caused by: java.lang.IllegalArgumentException: dataSource or dataSourceClassName or jdbcUrl is required.
at com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:997)
at play.api.db.HikariCPConfig.toHikariConfig(HikariCPModule.scala:136)
at play.api.db.HikariCPConnectionPool.$anonfun$create$1(HikariCPModule.scala:50)
at scala.util.Try$.apply(Try.scala:209)
at play.api.db.HikariCPConnectionPool.create(HikariCPModule.scala:47)
at play.api.db.PooledDatabase.createDataSource(Databases.scala:199)
at play.api.db.DefaultDatabase.dataSource$lzycompute(Databases.scala:123)
at play.api.db.DefaultDatabase.dataSource(Databases.scala:121)
at play.api.db.DefaultDatabase.getConnection(Databases.scala:142)
at play.api.db.DefaultDatabase.getConnection(Databases.scala:138)
Unfortunately Hikari and Play don't use quite the same naming conventions for setting up their data source, for instance Quill expects a bare dataSourceClassName
but Play wants it in a format like db.default.dataSourceClassName
. As far as I can tell there is no way to rework your config so that it will satisfy both of them and you may not want to for the following reason:
Play actually uses Hikari as it's pooling data source, so when you create a db via db.default
you're actually already creating a pooled data source. When you call PostgresJdbcContext
with a bare config you're actually asking Quill to create a totally separate connection pool. Not sure if this is what you want but I'd assume you'd want only one connection pool.
Quill actually exposes a constructor that takes in a DataSource
, so what you can do is use the Database
that Play has created and just pass it in directly to Quill:
import io.getquill.{PostgresJdbcContext, SnakeCase}
import com.zaxxer.hikari.HikariDataSource
import play.api.db.Database
package object db {
class DBContext(db: Database) extends PostgresJdbcContext(SnakeCase, db.dataSource.asInstanceOf[HikariDataSource])
}
This should solve your problem and will only create one connection pool. You can get at a Database
object via dependency injection.
You have to do an ugly asInstanceOf
here because the PostgresJdbcContext
requires the dataSource
to implement Closeable
, which the bare DataSource
class does not implement. I've ran into a similar issue and haven't found a more elegant way to do this.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.