From 61197d6fc122bf71c394820b734a8d59805119c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E8=B6=8A?= <1939455790@qq.com> Date: Sat, 11 Jul 2026 12:01:00 +0000 Subject: [PATCH] [ISSUE #9341] Fix NamespaceV2 not isolating resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When only namespaceV2 is set, topics and consumer/producer groups are not wrapped on the client side, because ClientConfig.getNamespace() β€” the single value used by withNamespace/withoutNamespace and every resource wrapping call site β€” only returns the deprecated V1 namespace, which stays empty. namespaceV2 was intended to be resolved server-side via the nsd/ns extension fields attached by NamespaceRpcHook, but the broker never consumes those fields; instead it derives the namespace from already-wrapped resource names (NamespaceUtil.getNamespaceFromResource). With neither side wrapping the resource, producers and consumers configured with different namespaces operate on the same physical topic, so a namespace can consume messages from another namespace. Make getNamespace() fall back to namespaceV2 when the V1 namespace is unset, so that resources are wrapped with the namespaceV2 value and isolated correctly. The V1 namespace still takes precedence when both are set. Signed-off-by: ηŽ‹θΆŠ <1939455790@qq.com> --- .../apache/rocketmq/client/ClientConfig.java | 4 +++ .../rocketmq/client/ClientConfigTest.java | 32 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java index 9e012254329..d7db54e96c7 100644 --- a/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java +++ b/client/src/main/java/org/apache/rocketmq/client/ClientConfig.java @@ -414,6 +414,10 @@ public String getNamespace() { return namespace; } + if (StringUtils.isNotEmpty(namespaceV2)) { + return namespaceV2; + } + if (StringUtils.isNotEmpty(this.namesrvAddr)) { if (NameServerAddressUtils.validateInstanceEndpoint(namesrvAddr)) { namespace = NameServerAddressUtils.parseInstanceIdFromEndpoint(namesrvAddr); diff --git a/client/src/test/java/org/apache/rocketmq/client/ClientConfigTest.java b/client/src/test/java/org/apache/rocketmq/client/ClientConfigTest.java index 5afe9cc011d..89bcf7a7d38 100644 --- a/client/src/test/java/org/apache/rocketmq/client/ClientConfigTest.java +++ b/client/src/test/java/org/apache/rocketmq/client/ClientConfigTest.java @@ -65,6 +65,38 @@ public void testQueuesWithNamespace() { assertEquals("lmq%defaultTopic", messageQueues.iterator().next().getTopic()); } + @Test + public void testGetNamespaceFallbackToNamespaceV2() { + ClientConfig config = new ClientConfig(); + config.setNamespaceV2("InstanceTest"); + assertEquals("InstanceTest", config.getNamespace()); + } + + @Test + public void testWithNamespaceUsesNamespaceV2() { + ClientConfig config = new ClientConfig(); + config.setNamespaceV2("InstanceTest"); + assertEquals("InstanceTest%resource", config.withNamespace(resource)); + assertEquals("InstanceTest%resource", + config.withNamespace("InstanceTest%resource")); + } + + @Test + public void testWithoutNamespaceUsesNamespaceV2() { + ClientConfig config = new ClientConfig(); + config.setNamespaceV2("InstanceTest"); + assertEquals(resource, config.withoutNamespace("InstanceTest%resource")); + } + + @Test + public void testNamespaceV1PrecedesNamespaceV2() { + ClientConfig config = new ClientConfig(); + config.setNamespace("lmq"); + config.setNamespaceV2("InstanceTest"); + assertEquals("lmq", config.getNamespace()); + assertEquals("lmq%resource", config.withNamespace(resource)); + } + private ClientConfig createClientConfig() { ClientConfig result = new ClientConfig(); result.setUnitName("unitName");