From d324006a34065cb9957af2dc26856ae1d1f4973a Mon Sep 17 00:00:00 2001 From: Roman Makeev Date: Fri, 1 Nov 2024 02:58:13 -0700 Subject: [PATCH] fix class loader --- .../topics/Getting-Started-with-Exposed.topic | 4 ++ .../topics/Working-with-Database.md | 3 ++ .../org/jetbrains/exposed/sql/Database.kt | 39 ++++++++++++------- gradle.properties | 2 +- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/documentation-website/Writerside/topics/Getting-Started-with-Exposed.topic b/documentation-website/Writerside/topics/Getting-Started-with-Exposed.topic index 914118a1e9..cbddc93fe7 100644 --- a/documentation-website/Writerside/topics/Getting-Started-with-Exposed.topic +++ b/documentation-website/Writerside/topics/Getting-Started-with-Exposed.topic @@ -194,6 +194,10 @@ Every database access using Exposed is started by obtaining a connection and creating a transaction. To configure the database connection, use the Database.connect() function.

+

+ By default, Exposed using `ServiceLoader` to get `DatabaseConnectionAutoRegistration`. + It can be modified when calling `Database.connect` method by providing `connectionAutoRegistration` in parameter list. +

diff --git a/documentation-website/Writerside/topics/Working-with-Database.md b/documentation-website/Writerside/topics/Working-with-Database.md index 445505534c..ade063f5a8 100644 --- a/documentation-website/Writerside/topics/Working-with-Database.md +++ b/documentation-website/Writerside/topics/Working-with-Database.md @@ -12,6 +12,9 @@ Every database access using Exposed is started by obtaining a connection and cre First of all, you have to tell Exposed how to connect to a database by using the `Database.connect` function. It won't create a real database connection but will only provide a descriptor for future usage. +By default, Exposed using `ServiceLoader` to get `DatabaseConnectionAutoRegistration`. +It can be modified when calling `Database.connect` method by providing `connectionAutoRegistration` in parameter list. + A real connection will be instantiated later by calling the `transaction` lambda (see [Transactions](Transactions.md) for more details). diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Database.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Database.kt index d55c7dae28..16762b33e8 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Database.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Database.kt @@ -112,9 +112,11 @@ class Database private constructor( companion object { internal val dialects = ConcurrentHashMap DatabaseDialect>() - private val connectionInstanceImpl: DatabaseConnectionAutoRegistration = - ServiceLoader.load(DatabaseConnectionAutoRegistration::class.java, Database::class.java.classLoader).firstOrNull() + private val connectionInstanceImpl: DatabaseConnectionAutoRegistration by lazy { + ServiceLoader.load(DatabaseConnectionAutoRegistration::class.java, Database::class.java.classLoader) + .firstOrNull() ?: error("Can't load implementation for ${DatabaseConnectionAutoRegistration::class.simpleName}") + } private val driverMapping = mutableMapOf( "jdbc:h2" to "org.h2.Driver", @@ -162,12 +164,13 @@ class Database private constructor( private fun doConnect( explicitVendor: String?, config: DatabaseConfig?, + connectionAutoRegistration: DatabaseConnectionAutoRegistration, getNewConnection: () -> Connection, setupConnection: (Connection) -> Unit = {}, manager: (Database) -> TransactionManager = { ThreadLocalTransactionManager(it) } ): Database { return Database(explicitVendor, config ?: DatabaseConfig.invoke()) { - connectionInstanceImpl(getNewConnection().apply { setupConnection(this) }) + connectionAutoRegistration(getNewConnection().apply { setupConnection(this) }) }.apply { TransactionManager.registerManager(this, manager(this)) } @@ -180,12 +183,14 @@ class Database private constructor( * but instead provides the details necessary to do so whenever a connection is required by a transaction. * * @param datasource The [DataSource] object to be used as a means of getting a connection. + * @param connectionAutoRegistration The connection provider for database. If not provided, will use ServiceLoaded [connectionInstanceImpl] * @param setupConnection Any setup that should be applied to each new connection. * @param databaseConfig Configuration parameters for this [Database] instance. * @param manager The [TransactionManager] responsible for new transactions that use this [Database] instance. */ fun connect( datasource: DataSource, + connectionAutoRegistration: DatabaseConnectionAutoRegistration = connectionInstanceImpl, setupConnection: (Connection) -> Unit = {}, databaseConfig: DatabaseConfig? = null, manager: (Database) -> TransactionManager = { ThreadLocalTransactionManager(it) } @@ -195,7 +200,8 @@ class Database private constructor( config = databaseConfig, getNewConnection = { datasource.connection!! }, setupConnection = setupConnection, - manager = manager + manager = manager, + connectionAutoRegistration = connectionAutoRegistration ).apply { connectsViaDataSource = true } @@ -223,6 +229,7 @@ class Database private constructor( ) fun connectPool( datasource: ConnectionPoolDataSource, + connectionAutoRegistration: DatabaseConnectionAutoRegistration = connectionInstanceImpl, setupConnection: (Connection) -> Unit = {}, databaseConfig: DatabaseConfig? = null, manager: (Database) -> TransactionManager = { ThreadLocalTransactionManager(it) } @@ -232,7 +239,8 @@ class Database private constructor( config = databaseConfig, getNewConnection = { datasource.pooledConnection.connection!! }, setupConnection = setupConnection, - manager = manager + manager = manager, + connectionAutoRegistration = connectionAutoRegistration ) } @@ -243,11 +251,13 @@ class Database private constructor( * but instead provides the details necessary to do so whenever a connection is required by a transaction. * * @param getNewConnection A function that returns a new connection. + * @param connectionAutoRegistration The connection provider for database. If not provided, will use ServiceLoaded [connectionInstanceImpl] * @param databaseConfig Configuration parameters for this [Database] instance. * @param manager The [TransactionManager] responsible for new transactions that use this [Database] instance. */ fun connect( getNewConnection: () -> Connection, + connectionAutoRegistration: DatabaseConnectionAutoRegistration = connectionInstanceImpl, databaseConfig: DatabaseConfig? = null, manager: (Database) -> TransactionManager = { ThreadLocalTransactionManager(it) } ): Database { @@ -255,7 +265,8 @@ class Database private constructor( explicitVendor = null, config = databaseConfig, getNewConnection = getNewConnection, - manager = manager + manager = manager, + connectionAutoRegistration = connectionAutoRegistration ) } @@ -266,6 +277,7 @@ class Database private constructor( * but instead provides the details necessary to do so whenever a connection is required by a transaction. * * @param url The URL that represents the database when getting a connection. + * @param connectionAutoRegistration The connection provider for database. If not provided, will use ServiceLoaded [connectionInstanceImpl] * @param driver The JDBC driver class. If not provided, the specified [url] will be used to find * a match from the existing driver mappings. * @param user The database user that owns the new connections. @@ -274,8 +286,10 @@ class Database private constructor( * @param databaseConfig Configuration parameters for this [Database] instance. * @param manager The [TransactionManager] responsible for new transactions that use this [Database] instance. */ + @Suppress("UnusedParameter", "LongParameterList") fun connect( url: String, + connectionAutoRegistration: DatabaseConnectionAutoRegistration = connectionInstanceImpl, driver: String = getDriver(url), user: String = "", password: String = "", @@ -286,13 +300,12 @@ class Database private constructor( Class.forName(driver).getDeclaredConstructor().newInstance() val dialectName = getDialectName(url) ?: error("Can't resolve dialect for connection: $url") return doConnect( - dialectName, - databaseConfig, - { - DriverManager.getConnection(url, user, password) - }, - setupConnection, - manager + explicitVendor = dialectName, + config = databaseConfig, + getNewConnection = { DriverManager.getConnection(url, user, password) }, + setupConnection = setupConnection, + manager = manager, + connectionAutoRegistration = connectionAutoRegistration, ) } diff --git a/gradle.properties b/gradle.properties index b0bfb74d7c..2d8d635a81 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,4 +4,4 @@ org.gradle.configuration.cache=true org.gradle.caching=true group=org.jetbrains.exposed -version=0.56.0 +version=0.57.0