diff --git a/CHANGELOG.md b/CHANGELOG.md index ab70ea343..16c430e2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ ### Bug Fixes +- **[clickhouse-client]** Fixed JPMS/module-path service loading for `ClickHouseRequestManager` by loading client + services from the `com.clickhouse.client` module, which declares the required `uses` directives. This avoids + `ServiceConfigurationError` failures from `com.clickhouse.data` when applications run on the module path. + (https://github.com/ClickHouse/clickhouse-java/issues/2669) + - **[client-v2]** Fixed binary varint decoding for length and count fields so overflowing or overlong values fail with an `IOException` instead of being decoded into corrupted or negative `int` values. (https://github.com/ClickHouse/clickhouse-java/issues/2902) - **[client-v2]** Fixed container query parameters being sent unquoted, so `Client.query(sql, params, settings)` binding diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseDnsResolver.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseDnsResolver.java index d3b949842..8acb16542 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseDnsResolver.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseDnsResolver.java @@ -1,10 +1,10 @@ package com.clickhouse.client; import java.net.InetSocketAddress; +import java.util.ServiceLoader; import com.clickhouse.client.config.ClickHouseDefaults; import com.clickhouse.client.naming.SrvResolver; -import com.clickhouse.data.ClickHouseUtils; import com.clickhouse.logging.Logger; import com.clickhouse.logging.LoggerFactory; @@ -17,8 +17,18 @@ public class ClickHouseDnsResolver { private static final Logger log = LoggerFactory.getLogger(ClickHouseDnsResolver.class); - private static final ClickHouseDnsResolver instance = ClickHouseUtils.getService(ClickHouseDnsResolver.class, - new ClickHouseDnsResolver()); + private static final ClickHouseDnsResolver instance = loadResolver(); + + private static ClickHouseDnsResolver loadResolver() { + for (ClickHouseDnsResolver resolver : ServiceLoader.load(ClickHouseDnsResolver.class, + ClickHouseDnsResolver.class.getClassLoader())) { + if (resolver != null) { + return resolver; + } + } + + return new ClickHouseDnsResolver(); + } protected static ClickHouseDnsResolver newInstance() { ClickHouseDnsResolver resolver = null; diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseRequestManager.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseRequestManager.java index d0e0e69f4..f9bf9113b 100644 --- a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseRequestManager.java +++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseRequestManager.java @@ -1,9 +1,9 @@ package com.clickhouse.client; +import java.util.ServiceLoader; import java.util.UUID; import com.clickhouse.data.ClickHouseChecker; -import com.clickhouse.data.ClickHouseUtils; /** * Request manager is responsible for generating query and session ID, as well @@ -17,13 +17,23 @@ public class ClickHouseRequestManager { * Inner class for static initialization. */ static final class InstanceHolder { - private static final ClickHouseRequestManager instance = ClickHouseUtils - .getService(ClickHouseRequestManager.class, ClickHouseRequestManager::new); + private static final ClickHouseRequestManager instance = loadManager(); private InstanceHolder() { } } + private static ClickHouseRequestManager loadManager() { + for (ClickHouseRequestManager manager : ServiceLoader.load(ClickHouseRequestManager.class, + ClickHouseRequestManager.class.getClassLoader())) { + if (manager != null) { + return manager; + } + } + + return new ClickHouseRequestManager(); + } + /** * Gets instance of request manager. * diff --git a/clickhouse-client/src/main/java11/module-info.java b/clickhouse-client/src/main/java11/module-info.java index a503f3d6a..d4a095dd4 100644 --- a/clickhouse-client/src/main/java11/module-info.java +++ b/clickhouse-client/src/main/java11/module-info.java @@ -11,5 +11,6 @@ uses com.clickhouse.client.ClickHouseClient; uses com.clickhouse.client.ClickHouseDnsResolver; + uses com.clickhouse.client.ClickHouseRequestManager; uses com.clickhouse.client.ClickHouseSslContextProvider; } diff --git a/clickhouse-client/src/main/java9/module-info.java b/clickhouse-client/src/main/java9/module-info.java index a503f3d6a..d4a095dd4 100644 --- a/clickhouse-client/src/main/java9/module-info.java +++ b/clickhouse-client/src/main/java9/module-info.java @@ -11,5 +11,6 @@ uses com.clickhouse.client.ClickHouseClient; uses com.clickhouse.client.ClickHouseDnsResolver; + uses com.clickhouse.client.ClickHouseRequestManager; uses com.clickhouse.client.ClickHouseSslContextProvider; } diff --git a/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseClientTest.java b/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseClientTest.java index eb6d2add8..a43c8cefd 100644 --- a/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseClientTest.java +++ b/clickhouse-client/src/test/java/com/clickhouse/client/ClickHouseClientTest.java @@ -5,6 +5,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.concurrent.ExecutionException; import com.clickhouse.client.ClickHouseRequest.Mutation; @@ -65,4 +68,19 @@ public void testMutation() throws ExecutionException, InterruptedException { Assert.assertNull(req.sql); Assert.assertNull(req.table("my_table").format(ClickHouseFormat.RowBinary).execute().get()); } + + @Test(groups = { "unit" }) + public void testClientModuleDeclaresLoadedServices() throws IOException { + Assert.assertNotNull(ClickHouseDnsResolver.getInstance()); + Assert.assertNotNull(ClickHouseRequestManager.getInstance()); + assertModuleInfoDeclaresUses("src/main/java9/module-info.java"); + assertModuleInfoDeclaresUses("src/main/java11/module-info.java"); + } + + private static void assertModuleInfoDeclaresUses(String moduleInfo) throws IOException { + String baseDir = System.getProperty("basedir", "."); + String content = new String(Files.readAllBytes(Paths.get(baseDir, moduleInfo)), StandardCharsets.UTF_8); + Assert.assertTrue(content.contains("uses com.clickhouse.client.ClickHouseDnsResolver;"), moduleInfo); + Assert.assertTrue(content.contains("uses com.clickhouse.client.ClickHouseRequestManager;"), moduleInfo); + } }