This is an automated email from the ASF dual-hosted git repository.

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 97affed698 [type:fix] Preserve copied API bean paths during 
registration (#7256)
97affed698 is described below

commit 97affed6985384983e9025072fd34729dc0e4011
Author: Liming Deng <[email protected]>
AuthorDate: Wed Sep 30 11:37:58 2026 +0800

    [type:fix] Preserve copied API bean paths during registration (#7256)
    
    * fix(client): bind copied API definitions to their copied bean
    
    * test(client): clarify independent registration state in API copies
---
 .../shenyu/client/core/register/ApiBean.java       |  6 +-
 .../client/core/register/ApiBeanCopyTest.java      | 67 ++++++++++++++++++++++
 2 files changed, 71 insertions(+), 2 deletions(-)

diff --git 
a/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/register/ApiBean.java
 
b/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/register/ApiBean.java
index a50cdfa5ae..afa1c9de94 100644
--- 
a/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/register/ApiBean.java
+++ 
b/shenyu-client/shenyu-client-core/src/main/java/org/apache/shenyu/client/core/register/ApiBean.java
@@ -238,7 +238,8 @@ public class ApiBean {
     }
     
     /**
-     * deep copy.
+     * Copy API metadata for independent processing by another registrar.
+     * Bean and definition registration states intentionally restart at INIT; 
the bean instance and Methods are shared.
      *
      * @return ApiBean
      */
@@ -246,7 +247,7 @@ public class ApiBean {
         final ApiBean copy = new ApiBean(clientName, beanName, beanInstance, 
beanPath);
         beanProperties.forEach((k, v) -> copy.addProperties(k.toString(), 
Objects.toString(v)));
         for (ApiDefinition definition : apiDefinitions) {
-            final ApiDefinition newDefinition = new ApiDefinition(this, 
definition.apiMethod, definition.methodPath);
+            final ApiDefinition newDefinition = new ApiDefinition(copy, 
definition.apiMethod, definition.methodPath);
             definition.apiProperties.forEach((k, v) -> 
newDefinition.addProperties(k.toString(), Objects.toString(v)));
             copy.apiDefinitions.add(newDefinition);
         }
@@ -266,6 +267,7 @@ public class ApiBean {
         
         /**
          * The instance of the class in which the function resides.
+         * Assigned later when an initially unbound definition is supplied to 
the ApiBean list constructor.
          */
         private ApiBean apiBean;
         
diff --git 
a/shenyu-client/shenyu-client-core/src/test/java/org/apache/shenyu/client/core/register/ApiBeanCopyTest.java
 
b/shenyu-client/shenyu-client-core/src/test/java/org/apache/shenyu/client/core/register/ApiBeanCopyTest.java
new file mode 100644
index 0000000000..8a52c4fb83
--- /dev/null
+++ 
b/shenyu-client/shenyu-client-core/src/test/java/org/apache/shenyu/client/core/register/ApiBeanCopyTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.shenyu.client.core.register;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+/**
+ * Tests ownership and mutation isolation of copied API definitions.
+ */
+public class ApiBeanCopyTest {
+
+    @Test
+    public void testCopiedDefinitionsUseCopiedBeanPath() throws 
NoSuchMethodException {
+        ApiBean original = new ApiBean("http", "bean", new Object(), 
"/original");
+        original.addProperties("bean-property", "original");
+        original.addApiDefinition(Object.class.getMethod("toString"), 
"/first");
+        original.addApiDefinition(Object.class.getMethod("hashCode"), 
"/second");
+        original.getApiDefinitions().get(0).addProperties("api-property", 
"original");
+        original.setStatus(ApiBean.Status.REGISTERED);
+        
original.getApiDefinitions().get(0).setStatus(ApiBean.Status.REGISTERED);
+        ApiBean copy = original.copy();
+        assertEquals(ApiBean.Status.INIT, copy.getStatus());
+        assertEquals(ApiBean.Status.REGISTERED, original.getStatus());
+        assertEquals(ApiBean.Status.REGISTERED, 
original.getApiDefinitions().get(0).getStatus());
+        assertNotSame(copy.getApiDefinitions().get(0), 
copy.getApiDefinitions().get(1));
+        copy.setBeanPath("/processed");
+        copy.addProperties("bean-property", "copied");
+        copy.getApiDefinitions().get(0).addProperties("api-property", 
"copied");
+        copy.getApiDefinitions().get(0).setMethodPath("/changed");
+        assertSame(original.getBeanInstance(), copy.getBeanInstance());
+        for (int i = 0; i < original.getApiDefinitions().size(); i++) {
+            ApiBean.ApiDefinition copiedDefinition = 
copy.getApiDefinitions().get(i);
+            ApiBean.ApiDefinition originalDefinition = 
original.getApiDefinitions().get(i);
+            assertNotSame(originalDefinition, copiedDefinition);
+            assertSame(copy, copiedDefinition.getApiBean());
+            assertEquals(ApiBean.Status.INIT, copiedDefinition.getStatus());
+            assertSame(original, originalDefinition.getApiBean());
+            assertEquals("/processed", copiedDefinition.getBeanPath());
+            assertEquals("/original", originalDefinition.getBeanPath());
+            assertEquals(originalDefinition.getApiMethod(), 
copiedDefinition.getApiMethod());
+        }
+        assertEquals("original", original.getPropertiesValue("bean-property"));
+        assertEquals("original", 
original.getApiDefinitions().get(0).getPropertiesValue("api-property"));
+        assertEquals("/first", 
original.getApiDefinitions().get(0).getMethodPath());
+        assertEquals("/second", 
copy.getApiDefinitions().get(1).getMethodPath());
+    }
+}

Reply via email to