From fd2cf5d0c662ad3811444d2c8ef1c2cc4bff4f27 Mon Sep 17 00:00:00 2001 From: 014-code <2402143478@qq.com> Date: Mon, 20 Jul 2026 21:36:20 +0800 Subject: [PATCH] fix(clickhouse-client): load services from client module Load ClickHouseRequestManager and ClickHouseDnsResolver providers from the com.clickhouse.client module instead of delegating through ClickHouseUtils in com.clickhouse.data. This keeps JPMS ServiceLoader uses checks aligned with the module that owns the service types. Add the missing ClickHouseRequestManager uses directives to the Java 9 and Java 11 module descriptors and cover the fallback/module descriptor contract in ClickHouseClientTest. Fixes #2669 --- CHANGELOG.md | 5 +++++ .../client/ClickHouseDnsResolver.java | 16 +++++++++++++--- .../client/ClickHouseRequestManager.java | 16 +++++++++++++--- .../src/main/java11/module-info.java | 1 + .../src/main/java9/module-info.java | 1 + .../client/ClickHouseClientTest.java | 18 ++++++++++++++++++ 6 files changed, 51 insertions(+), 6 deletions(-) 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); + } }