This is an automated email from the ASF dual-hosted git repository.
dengliming 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 1fcecc4d19 fix(dubbo): use Dubbo @Service in ServiceProcessor to set
beanPath (#6895)
1fcecc4d19 is described below
commit 1fcecc4d19cd3513646391286aa30023df67c7c2
Author: hengyuss <[email protected]>
AuthorDate: Wed Sep 16 14:22:00 2026 +0800
fix(dubbo): use Dubbo @Service in ServiceProcessor to set beanPath (#6895)
* fix: ServiceProcessor imports Spring @Service instead of Dubbo @Service —
old-style Dubbo beans never get beanPath
* fix: ServiceProcessor uses Dubbo @Service, extract shared
DubboRpcExtBuilders
---------
Co-authored-by: zhengpeng <[email protected]>
Co-authored-by: Liming Deng <[email protected]>
---
.../dubbo/ApacheDubboServiceBeanListener.java | 37 +----
.../processor/extractor/DubboServiceProcessor.java | 28 +---
.../processor/extractor/ServiceProcessor.java | 29 +++-
.../extractor/DubboServiceProcessorTest.java | 175 +++++++++++++++++++++
.../processor/extractor/ServiceProcessorTest.java | 175 +++++++++++++++++++++
.../shenyu-client-dubbo-common/pom.xml | 6 +
.../dubbo/common/dto/DubboRpcExtBuilders.java | 65 ++++++++
.../dubbo/common/dto/DubboRpcExtBuildersTest.java | 140 +++++++++++++++++
8 files changed, 593 insertions(+), 62 deletions(-)
diff --git
a/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/ApacheDubboServiceBeanListener.java
b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/ApacheDubboServiceBeanListener.java
index c537b04c3d..4606103c86 100644
---
a/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/ApacheDubboServiceBeanListener.java
+++
b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/ApacheDubboServiceBeanListener.java
@@ -18,19 +18,14 @@
package org.apache.shenyu.client.apache.dubbo;
import org.apache.commons.lang3.StringUtils;
-import org.apache.dubbo.common.constants.CommonConstants;
-import org.apache.dubbo.config.MethodConfig;
import org.apache.dubbo.config.spring.ServiceBean;
import
org.apache.shenyu.client.core.client.AbstractContextRefreshedEventListener;
import org.apache.shenyu.client.core.constant.ShenyuClientConstants;
import org.apache.shenyu.client.dubbo.common.annotation.ShenyuDubboClient;
-import org.apache.shenyu.client.dubbo.common.dto.DubboRpcExt;
-import org.apache.shenyu.client.dubbo.common.dto.DubboRpcMethodExt;
-import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.client.dubbo.common.dto.DubboRpcExtBuilders;
import org.apache.shenyu.common.enums.ApiHttpMethodEnum;
import org.apache.shenyu.common.enums.RpcTypeEnum;
import org.apache.shenyu.common.exception.ShenyuException;
-import org.apache.shenyu.common.utils.GsonUtils;
import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
import org.apache.shenyu.register.common.config.ShenyuClientConfig;
import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
@@ -46,7 +41,6 @@ import org.springframework.util.ReflectionUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -54,8 +48,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
-import static org.apache.dubbo.remoting.Constants.DEFAULT_CONNECT_TIMEOUT;
-
/**
* The Apache Dubbo ServiceBean Listener.
*/
@@ -223,31 +215,6 @@ public class ApacheDubboServiceBeanListener extends
AbstractContextRefreshedEven
}
private String buildRpcExt(final ServiceBean<?> serviceBean, final String
methodName) {
- DubboRpcExt build = DubboRpcExt.builder()
-
.protocol(StringUtils.isNotEmpty(serviceBean.getProtocol().getName()) ?
serviceBean.getProtocol().getName() : "")
- .group(StringUtils.isNotEmpty(serviceBean.getGroup()) ?
serviceBean.getGroup() : "")
- .version(StringUtils.isNotEmpty(serviceBean.getVersion()) ?
serviceBean.getVersion() : "")
-
.loadbalance(StringUtils.isNotEmpty(serviceBean.getLoadbalance()) ?
serviceBean.getLoadbalance() : CommonConstants.DEFAULT_LOADBALANCE)
-
.retries(Optional.ofNullable(serviceBean.getRetries()).orElse(CommonConstants.DEFAULT_RETRIES))
-
.timeout(Optional.ofNullable(serviceBean.getTimeout()).orElse(DEFAULT_CONNECT_TIMEOUT))
-
.sent(Optional.ofNullable(serviceBean.getSent()).orElse(Boolean.FALSE))
- .cluster(StringUtils.isNotEmpty(serviceBean.getCluster()) ?
serviceBean.getCluster() : Constants.DEFAULT_CLUSTER)
- .url("")
- .serialization(serviceBean.getSerialization())
- .build();
- // method config: loadbalance,retries,timeout,sent
- if (Objects.nonNull(serviceBean.getMethods())) {
- build.setMethods(new ArrayList<>());
- for (MethodConfig methodConfig : serviceBean.getMethods()) {
- DubboRpcMethodExt methodExt = new DubboRpcMethodExt();
- methodExt.setName(methodConfig.getName());
- methodExt.setLoadbalance(methodConfig.getLoadbalance());
- methodExt.setRetries(methodConfig.getRetries());
- methodExt.setTimeout(methodConfig.getTimeout());
- methodExt.setSent(methodConfig.getSent());
- build.getMethods().add(methodExt);
- }
- }
- return GsonUtils.getInstance().toJson(build);
+ return DubboRpcExtBuilders.buildRpcExt(serviceBean);
}
}
diff --git
a/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/DubboServiceProcessor.java
b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/DubboServiceProcessor.java
index 71e4602c68..bfe672ac3c 100644
---
a/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/DubboServiceProcessor.java
+++
b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/DubboServiceProcessor.java
@@ -17,23 +17,16 @@
package org.apache.shenyu.client.apache.dubbo.processor.extractor;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.config.spring.ServiceBean;
import org.apache.shenyu.client.core.register.ApiBean;
import org.apache.shenyu.client.core.register.matcher.ApiAnnotationProcessor;
import org.apache.shenyu.client.core.register.matcher.ExtractorProcessor;
-import org.apache.shenyu.client.dubbo.common.dto.DubboRpcExt;
-import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.client.dubbo.common.dto.DubboRpcExtBuilders;
import org.apache.shenyu.common.enums.RpcTypeEnum;
-import org.apache.shenyu.common.utils.GsonUtils;
import org.apache.shenyu.common.utils.ListUtil;
import java.util.List;
-import java.util.Optional;
-
-import static org.apache.dubbo.remoting.Constants.DEFAULT_CONNECT_TIMEOUT;
/**
* DubboServiceProcessor.
@@ -70,7 +63,7 @@ public class DubboServiceProcessor implements
ApiAnnotationProcessor<DubboServic
private String getRpcExt(final ApiBean apiBean) {
final Object beanInstance = apiBean.getBeanInstance();
if (beanInstance instanceof ServiceBean) {
- return getRpcExt((ServiceBean<?>) beanInstance);
+ return DubboRpcExtBuilders.buildRpcExt((ServiceBean<?>)
beanInstance);
}
return "{}";
}
@@ -78,23 +71,8 @@ public class DubboServiceProcessor implements
ApiAnnotationProcessor<DubboServic
private String getRpcExt(final ApiBean.ApiDefinition definition) {
final Object beanInstance = definition.getApiBean().getBeanInstance();
if (beanInstance instanceof ServiceBean) {
- return getRpcExt((ServiceBean<?>) beanInstance);
+ return DubboRpcExtBuilders.buildRpcExt((ServiceBean<?>)
beanInstance);
}
return "{}";
}
-
- private static String getRpcExt(final ServiceBean<?> serviceBean) {
- DubboRpcExt build = DubboRpcExt.builder()
-
.protocol(StringUtils.isNotEmpty(serviceBean.getProtocol().getName()) ?
serviceBean.getProtocol().getName() : "")
- .group(StringUtils.isNotEmpty(serviceBean.getGroup()) ?
serviceBean.getGroup() : "")
- .version(StringUtils.isNotEmpty(serviceBean.getVersion()) ?
serviceBean.getVersion() : "")
-
.loadbalance(StringUtils.isNotEmpty(serviceBean.getLoadbalance()) ?
serviceBean.getLoadbalance() : CommonConstants.DEFAULT_LOADBALANCE)
-
.retries(Optional.ofNullable(serviceBean.getRetries()).orElse(CommonConstants.DEFAULT_RETRIES))
-
.timeout(Optional.ofNullable(serviceBean.getTimeout()).orElse(DEFAULT_CONNECT_TIMEOUT))
-
.sent(Optional.ofNullable(serviceBean.getSent()).orElse(Boolean.FALSE))
- .cluster(StringUtils.isNotEmpty(serviceBean.getCluster()) ?
serviceBean.getCluster() : Constants.DEFAULT_CLUSTER)
- .url("")
- .build();
- return GsonUtils.getInstance().toJson(build);
- }
}
diff --git
a/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/ServiceProcessor.java
b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/ServiceProcessor.java
index 4473573346..83c332282b 100644
---
a/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/ServiceProcessor.java
+++
b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/main/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/ServiceProcessor.java
@@ -17,12 +17,14 @@
package org.apache.shenyu.client.apache.dubbo.processor.extractor;
+import org.apache.dubbo.config.annotation.Service;
+import org.apache.dubbo.config.spring.ServiceBean;
import org.apache.shenyu.client.core.register.ApiBean;
import org.apache.shenyu.client.core.register.matcher.ApiAnnotationProcessor;
import org.apache.shenyu.client.core.register.matcher.ExtractorProcessor;
+import org.apache.shenyu.client.dubbo.common.dto.DubboRpcExtBuilders;
import org.apache.shenyu.common.enums.RpcTypeEnum;
import org.apache.shenyu.common.utils.ListUtil;
-import org.springframework.stereotype.Service;
import java.util.List;
@@ -38,7 +40,14 @@ public class ServiceProcessor implements
ApiAnnotationProcessor<Service>, Extrac
@Override
public void process(final ApiBean apiBean, final Service annotation) {
- apiBean.setBeanPath(annotation.value());
+ apiBean.setBeanPath(annotation.path());
+
+ apiBean.addProperties("rpcExt", getRpcExt(apiBean));
+ }
+
+ @Override
+ public void process(final ApiBean.ApiDefinition definition) {
+ definition.addProperties("rpcExt", getRpcExt(definition));
}
@Override
@@ -50,4 +59,20 @@ public class ServiceProcessor implements
ApiAnnotationProcessor<Service>, Extrac
public Class<Service> matchAnnotation() {
return Service.class;
}
+
+ private String getRpcExt(final ApiBean apiBean) {
+ final Object beanInstance = apiBean.getBeanInstance();
+ if (beanInstance instanceof ServiceBean) {
+ return DubboRpcExtBuilders.buildRpcExt((ServiceBean<?>)
beanInstance);
+ }
+ return "{}";
+ }
+
+ private String getRpcExt(final ApiBean.ApiDefinition definition) {
+ final Object beanInstance = definition.getApiBean().getBeanInstance();
+ if (beanInstance instanceof ServiceBean) {
+ return DubboRpcExtBuilders.buildRpcExt((ServiceBean<?>)
beanInstance);
+ }
+ return "{}";
+ }
}
diff --git
a/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/test/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/DubboServiceProcessorTest.java
b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/test/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/DubboServiceProcessorTest.java
new file mode 100644
index 0000000000..31087b93d4
--- /dev/null
+++
b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/test/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/DubboServiceProcessorTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.apache.dubbo.processor.extractor;
+
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.apache.dubbo.config.spring.ServiceBean;
+import org.apache.shenyu.client.core.register.ApiBean;
+import org.apache.shenyu.common.enums.RpcTypeEnum;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class DubboServiceProcessorTest {
+
+ private DubboServiceProcessor dubboServiceProcessor;
+
+ @Mock
+ private ServiceBean<?> serviceBean;
+
+ @Mock
+ private ProtocolConfig protocolConfig;
+
+ @BeforeEach
+ void setUp() {
+ dubboServiceProcessor = new DubboServiceProcessor();
+ }
+
+ @Test
+ void testSupportedClient() {
+ List<String> clients = dubboServiceProcessor.supportedClient();
+ assertEquals(1, clients.size());
+ assertEquals(RpcTypeEnum.DUBBO.getName(), clients.get(0));
+ }
+
+ @Test
+ void testMatchAnnotation() {
+ assertEquals(DubboService.class,
dubboServiceProcessor.matchAnnotation());
+ }
+
+ @Test
+ void testProcessWithServiceBeanSetsBeanPathAndRpcExt() throws Exception {
+ when(serviceBean.getProtocol()).thenReturn(protocolConfig);
+ when(protocolConfig.getName()).thenReturn("dubbo");
+ when(serviceBean.getGroup()).thenReturn("testGroup");
+ when(serviceBean.getVersion()).thenReturn("1.0.0");
+ when(serviceBean.getLoadbalance()).thenReturn("random");
+ when(serviceBean.getRetries()).thenReturn(3);
+ when(serviceBean.getTimeout()).thenReturn(1000);
+ when(serviceBean.getSent()).thenReturn(true);
+ when(serviceBean.getCluster()).thenReturn("failover");
+ when(serviceBean.getSerialization()).thenReturn("fastjson");
+ when(serviceBean.getMethods()).thenReturn(null);
+
+ ApiBean apiBean = new ApiBean(RpcTypeEnum.DUBBO.getName(), "testBean",
serviceBean);
+
+ DubboService dubboServiceAnnotation =
TestDubboServiceBean.class.getAnnotation(DubboService.class);
+ dubboServiceProcessor.process(apiBean, dubboServiceAnnotation);
+
+ assertEquals(dubboServiceAnnotation.path(), apiBean.getBeanPath());
+ String rpcExt = apiBean.getPropertiesValue("rpcExt");
+ assertNotNull(rpcExt);
+ assertTrue(rpcExt.contains("\"serialization\":\"fastjson\""));
+ assertTrue(rpcExt.contains("\"protocol\":\"dubbo\""));
+ assertTrue(rpcExt.contains("\"group\":\"testGroup\""));
+ }
+
+ @Test
+ void testProcessWithNonServiceBeanReturnsEmptyRpcExt() {
+ Object plainBean = new Object();
+ ApiBean apiBean = new ApiBean(RpcTypeEnum.DUBBO.getName(), "testBean",
plainBean);
+
+ DubboService dubboServiceAnnotation =
TestDubboServiceBean.class.getAnnotation(DubboService.class);
+ dubboServiceProcessor.process(apiBean, dubboServiceAnnotation);
+
+ String rpcExt = apiBean.getPropertiesValue("rpcExt");
+ assertEquals("{}", rpcExt);
+ }
+
+ @Test
+ void testProcessApiDefinitionWithServiceBean() throws Exception {
+ when(serviceBean.getProtocol()).thenReturn(protocolConfig);
+ when(protocolConfig.getName()).thenReturn("dubbo");
+ when(serviceBean.getGroup()).thenReturn("myGroup");
+ when(serviceBean.getVersion()).thenReturn("2.0.0");
+ when(serviceBean.getLoadbalance()).thenReturn(null);
+ when(serviceBean.getRetries()).thenReturn(null);
+ when(serviceBean.getTimeout()).thenReturn(null);
+ when(serviceBean.getSent()).thenReturn(null);
+ when(serviceBean.getCluster()).thenReturn(null);
+ when(serviceBean.getSerialization()).thenReturn("fastjson");
+ when(serviceBean.getMethods()).thenReturn(null);
+
+ ApiBean apiBean = new ApiBean(RpcTypeEnum.DUBBO.getName(), "testBean",
serviceBean);
+ Method method = TestDubboServiceBean.class.getMethod("testMethod");
+ ApiBean.ApiDefinition definition = new ApiBean.ApiDefinition(apiBean,
method);
+
+ dubboServiceProcessor.process(definition);
+
+ String rpcExt = definition.getPropertiesValue("rpcExt");
+ assertNotNull(rpcExt);
+ assertTrue(rpcExt.contains("\"serialization\":\"fastjson\""));
+ assertTrue(rpcExt.contains("\"protocol\":\"dubbo\""));
+ assertTrue(rpcExt.contains("\"group\":\"myGroup\""));
+ assertTrue(rpcExt.contains("\"version\":\"2.0.0\""));
+ }
+
+ @Test
+ void testProcessApiDefinitionWithNonServiceBean() throws Exception {
+ Object plainBean = new Object();
+ ApiBean apiBean = new ApiBean(RpcTypeEnum.DUBBO.getName(), "testBean",
plainBean);
+ Method method = TestDubboServiceBean.class.getMethod("testMethod");
+ ApiBean.ApiDefinition definition = new ApiBean.ApiDefinition(apiBean,
method);
+
+ dubboServiceProcessor.process(definition);
+
+ String rpcExt = definition.getPropertiesValue("rpcExt");
+ assertEquals("{}", rpcExt);
+ }
+
+ @Test
+ void testProcessWithNullProtocol() {
+ when(serviceBean.getProtocol()).thenReturn(null);
+ when(serviceBean.getGroup()).thenReturn(null);
+ when(serviceBean.getVersion()).thenReturn(null);
+ when(serviceBean.getLoadbalance()).thenReturn(null);
+ when(serviceBean.getRetries()).thenReturn(null);
+ when(serviceBean.getTimeout()).thenReturn(null);
+ when(serviceBean.getSent()).thenReturn(null);
+ when(serviceBean.getCluster()).thenReturn(null);
+ when(serviceBean.getSerialization()).thenReturn(null);
+ when(serviceBean.getMethods()).thenReturn(null);
+
+ ApiBean apiBean = new ApiBean(RpcTypeEnum.DUBBO.getName(), "testBean",
serviceBean);
+
+ DubboService dubboServiceAnnotation =
TestDubboServiceBean.class.getAnnotation(DubboService.class);
+ dubboServiceProcessor.process(apiBean, dubboServiceAnnotation);
+
+ String rpcExt = apiBean.getPropertiesValue("rpcExt");
+ assertNotNull(rpcExt);
+ assertTrue(rpcExt.contains("\"protocol\":\"\""));
+ }
+
+ @DubboService(path = "/test-dubbo-path")
+ private static class TestDubboServiceBean {
+ public void testMethod() {
+ }
+ }
+}
diff --git
a/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/test/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/ServiceProcessorTest.java
b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/test/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/ServiceProcessorTest.java
new file mode 100644
index 0000000000..3d8e1c0152
--- /dev/null
+++
b/shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/test/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/ServiceProcessorTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.apache.dubbo.processor.extractor;
+
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.annotation.Service;
+import org.apache.dubbo.config.spring.ServiceBean;
+import org.apache.shenyu.client.core.register.ApiBean;
+import org.apache.shenyu.common.enums.RpcTypeEnum;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class ServiceProcessorTest {
+
+ private ServiceProcessor serviceProcessor;
+
+ @Mock
+ private ServiceBean<?> serviceBean;
+
+ @Mock
+ private ProtocolConfig protocolConfig;
+
+ @BeforeEach
+ void setUp() {
+ serviceProcessor = new ServiceProcessor();
+ }
+
+ @Test
+ void testSupportedClient() {
+ List<String> clients = serviceProcessor.supportedClient();
+ assertEquals(1, clients.size());
+ assertEquals(RpcTypeEnum.DUBBO.getName(), clients.get(0));
+ }
+
+ @Test
+ void testMatchAnnotation() {
+ assertEquals(Service.class, serviceProcessor.matchAnnotation());
+ }
+
+ @Test
+ void testProcessWithServiceBeanSetsBeanPathAndRpcExt() throws Exception {
+ when(serviceBean.getProtocol()).thenReturn(protocolConfig);
+ when(protocolConfig.getName()).thenReturn("dubbo");
+ when(serviceBean.getGroup()).thenReturn("testGroup");
+ when(serviceBean.getVersion()).thenReturn("1.0.0");
+ when(serviceBean.getLoadbalance()).thenReturn("random");
+ when(serviceBean.getRetries()).thenReturn(3);
+ when(serviceBean.getTimeout()).thenReturn(1000);
+ when(serviceBean.getSent()).thenReturn(true);
+ when(serviceBean.getCluster()).thenReturn("failover");
+ when(serviceBean.getSerialization()).thenReturn("hessian2");
+ when(serviceBean.getMethods()).thenReturn(null);
+
+ ApiBean apiBean = new ApiBean(RpcTypeEnum.DUBBO.getName(), "testBean",
serviceBean);
+
+ Service serviceAnnotation =
TestServiceBean.class.getAnnotation(Service.class);
+ serviceProcessor.process(apiBean, serviceAnnotation);
+
+ assertEquals(serviceAnnotation.path(), apiBean.getBeanPath());
+ String rpcExt = apiBean.getPropertiesValue("rpcExt");
+ assertNotNull(rpcExt);
+ assertTrue(rpcExt.contains("\"serialization\":\"hessian2\""));
+ assertTrue(rpcExt.contains("\"protocol\":\"dubbo\""));
+ assertTrue(rpcExt.contains("\"group\":\"testGroup\""));
+ }
+
+ @Test
+ void testProcessWithNonServiceBeanReturnsEmptyRpcExt() {
+ Object plainBean = new Object();
+ ApiBean apiBean = new ApiBean(RpcTypeEnum.DUBBO.getName(), "testBean",
plainBean);
+
+ Service serviceAnnotation =
TestServiceBean.class.getAnnotation(Service.class);
+ serviceProcessor.process(apiBean, serviceAnnotation);
+
+ String rpcExt = apiBean.getPropertiesValue("rpcExt");
+ assertEquals("{}", rpcExt);
+ }
+
+ @Test
+ void testProcessApiDefinitionWithServiceBean() throws Exception {
+ when(serviceBean.getProtocol()).thenReturn(protocolConfig);
+ when(protocolConfig.getName()).thenReturn("dubbo");
+ when(serviceBean.getGroup()).thenReturn("myGroup");
+ when(serviceBean.getVersion()).thenReturn("2.0.0");
+ when(serviceBean.getLoadbalance()).thenReturn(null);
+ when(serviceBean.getRetries()).thenReturn(null);
+ when(serviceBean.getTimeout()).thenReturn(null);
+ when(serviceBean.getSent()).thenReturn(null);
+ when(serviceBean.getCluster()).thenReturn(null);
+ when(serviceBean.getSerialization()).thenReturn("fastjson");
+ when(serviceBean.getMethods()).thenReturn(null);
+
+ ApiBean apiBean = new ApiBean(RpcTypeEnum.DUBBO.getName(), "testBean",
serviceBean);
+ Method method = TestServiceBean.class.getMethod("testMethod");
+ ApiBean.ApiDefinition definition = new ApiBean.ApiDefinition(apiBean,
method);
+
+ serviceProcessor.process(definition);
+
+ String rpcExt = definition.getPropertiesValue("rpcExt");
+ assertNotNull(rpcExt);
+ assertTrue(rpcExt.contains("\"serialization\":\"fastjson\""));
+ assertTrue(rpcExt.contains("\"protocol\":\"dubbo\""));
+ assertTrue(rpcExt.contains("\"group\":\"myGroup\""));
+ assertTrue(rpcExt.contains("\"version\":\"2.0.0\""));
+ }
+
+ @Test
+ void testProcessApiDefinitionWithNonServiceBean() throws Exception {
+ Object plainBean = new Object();
+ ApiBean apiBean = new ApiBean(RpcTypeEnum.DUBBO.getName(), "testBean",
plainBean);
+ Method method = TestServiceBean.class.getMethod("testMethod");
+ ApiBean.ApiDefinition definition = new ApiBean.ApiDefinition(apiBean,
method);
+
+ serviceProcessor.process(definition);
+
+ String rpcExt = definition.getPropertiesValue("rpcExt");
+ assertEquals("{}", rpcExt);
+ }
+
+ @Test
+ void testProcessWithNullProtocol() {
+ when(serviceBean.getProtocol()).thenReturn(null);
+ when(serviceBean.getGroup()).thenReturn(null);
+ when(serviceBean.getVersion()).thenReturn(null);
+ when(serviceBean.getLoadbalance()).thenReturn(null);
+ when(serviceBean.getRetries()).thenReturn(null);
+ when(serviceBean.getTimeout()).thenReturn(null);
+ when(serviceBean.getSent()).thenReturn(null);
+ when(serviceBean.getCluster()).thenReturn(null);
+ when(serviceBean.getSerialization()).thenReturn(null);
+ when(serviceBean.getMethods()).thenReturn(null);
+
+ ApiBean apiBean = new ApiBean(RpcTypeEnum.DUBBO.getName(), "testBean",
serviceBean);
+
+ Service serviceAnnotation =
TestServiceBean.class.getAnnotation(Service.class);
+ serviceProcessor.process(apiBean, serviceAnnotation);
+
+ String rpcExt = apiBean.getPropertiesValue("rpcExt");
+ assertNotNull(rpcExt);
+ assertTrue(rpcExt.contains("\"protocol\":\"\""));
+ }
+
+ @Service(path = "/test-path")
+ private static class TestServiceBean {
+ public void testMethod() {
+ }
+ }
+}
diff --git
a/shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/pom.xml
b/shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/pom.xml
index cd8a537bb6..53e2926153 100644
--- a/shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/pom.xml
+++ b/shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/pom.xml
@@ -36,5 +36,11 @@
<artifactId>spring-web</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo</artifactId>
+ <version>${apache.dubbo.version}</version>
+ <scope>provided</scope>
+ </dependency>
</dependencies>
</project>
diff --git
a/shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/src/main/java/org/apache/shenyu/client/dubbo/common/dto/DubboRpcExtBuilders.java
b/shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/src/main/java/org/apache/shenyu/client/dubbo/common/dto/DubboRpcExtBuilders.java
new file mode 100644
index 0000000000..02d5f6d54c
--- /dev/null
+++
b/shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/src/main/java/org/apache/shenyu/client/dubbo/common/dto/DubboRpcExtBuilders.java
@@ -0,0 +1,65 @@
+/*
+ * 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.dubbo.common.dto;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.spring.ServiceBean;
+import org.apache.shenyu.common.constant.Constants;
+import org.apache.shenyu.common.utils.GsonUtils;
+
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.Optional;
+
+import static org.apache.dubbo.remoting.Constants.DEFAULT_CONNECT_TIMEOUT;
+
+public final class DubboRpcExtBuilders {
+
+ private DubboRpcExtBuilders() {
+ }
+
+ public static String buildRpcExt(final ServiceBean<?> serviceBean) {
+ DubboRpcExt build = DubboRpcExt.builder()
+ .protocol(Objects.nonNull(serviceBean.getProtocol()) &&
StringUtils.isNotEmpty(serviceBean.getProtocol().getName()) ?
serviceBean.getProtocol().getName() : "")
+ .group(StringUtils.isNotEmpty(serviceBean.getGroup()) ?
serviceBean.getGroup() : "")
+ .version(StringUtils.isNotEmpty(serviceBean.getVersion()) ?
serviceBean.getVersion() : "")
+
.loadbalance(StringUtils.isNotEmpty(serviceBean.getLoadbalance()) ?
serviceBean.getLoadbalance() : CommonConstants.DEFAULT_LOADBALANCE)
+
.retries(Optional.ofNullable(serviceBean.getRetries()).orElse(CommonConstants.DEFAULT_RETRIES))
+
.timeout(Optional.ofNullable(serviceBean.getTimeout()).orElse(DEFAULT_CONNECT_TIMEOUT))
+
.sent(Optional.ofNullable(serviceBean.getSent()).orElse(Boolean.FALSE))
+ .cluster(StringUtils.isNotEmpty(serviceBean.getCluster()) ?
serviceBean.getCluster() : Constants.DEFAULT_CLUSTER)
+ .url("")
+ .serialization(serviceBean.getSerialization())
+ .build();
+ if (Objects.nonNull(serviceBean.getMethods())) {
+ build.setMethods(new ArrayList<>());
+ for (MethodConfig methodConfig : serviceBean.getMethods()) {
+ DubboRpcMethodExt methodExt = new DubboRpcMethodExt();
+ methodExt.setName(methodConfig.getName());
+ methodExt.setLoadbalance(methodConfig.getLoadbalance());
+ methodExt.setRetries(methodConfig.getRetries());
+ methodExt.setTimeout(methodConfig.getTimeout());
+ methodExt.setSent(methodConfig.getSent());
+ build.getMethods().add(methodExt);
+ }
+ }
+ return GsonUtils.getInstance().toJson(build);
+ }
+}
diff --git
a/shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/src/test/java/org/apache/shenyu/client/dubbo/common/dto/DubboRpcExtBuildersTest.java
b/shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/src/test/java/org/apache/shenyu/client/dubbo/common/dto/DubboRpcExtBuildersTest.java
new file mode 100644
index 0000000000..d695566723
--- /dev/null
+++
b/shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/src/test/java/org/apache/shenyu/client/dubbo/common/dto/DubboRpcExtBuildersTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.dubbo.common.dto;
+
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.spring.ServiceBean;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+public class DubboRpcExtBuildersTest {
+
+ @Mock
+ private ServiceBean<?> serviceBean;
+
+ @Mock
+ private ProtocolConfig protocolConfig;
+
+ @Test
+ void testBuildRpcExtWithFullConfig() {
+ when(serviceBean.getProtocol()).thenReturn(protocolConfig);
+ when(protocolConfig.getName()).thenReturn("dubbo");
+ when(serviceBean.getGroup()).thenReturn("testGroup");
+ when(serviceBean.getVersion()).thenReturn("1.0.0");
+ when(serviceBean.getLoadbalance()).thenReturn("random");
+ when(serviceBean.getRetries()).thenReturn(3);
+ when(serviceBean.getTimeout()).thenReturn(2000);
+ when(serviceBean.getSent()).thenReturn(true);
+ when(serviceBean.getCluster()).thenReturn("failfast");
+ when(serviceBean.getSerialization()).thenReturn("hessian2");
+ when(serviceBean.getMethods()).thenReturn(null);
+
+ String result = DubboRpcExtBuilders.buildRpcExt(serviceBean);
+ assertNotNull(result);
+ assertTrue(result.contains("\"serialization\":\"hessian2\""));
+ assertTrue(result.contains("\"protocol\":\"dubbo\""));
+ assertTrue(result.contains("\"group\":\"testGroup\""));
+ assertTrue(result.contains("\"version\":\"1.0.0\""));
+ assertTrue(result.contains("\"loadbalance\":\"random\""));
+ assertTrue(result.contains("\"retries\":3"));
+ assertTrue(result.contains("\"timeout\":2000"));
+ assertTrue(result.contains("\"sent\":true"));
+ assertTrue(result.contains("\"cluster\":\"failfast\""));
+ }
+
+ @Test
+ void testBuildRpcExtWithNullProtocol() {
+ when(serviceBean.getProtocol()).thenReturn(null);
+ when(serviceBean.getGroup()).thenReturn(null);
+ when(serviceBean.getVersion()).thenReturn(null);
+ when(serviceBean.getLoadbalance()).thenReturn(null);
+ when(serviceBean.getRetries()).thenReturn(null);
+ when(serviceBean.getTimeout()).thenReturn(null);
+ when(serviceBean.getSent()).thenReturn(null);
+ when(serviceBean.getCluster()).thenReturn(null);
+ when(serviceBean.getSerialization()).thenReturn(null);
+ when(serviceBean.getMethods()).thenReturn(null);
+
+ String result = DubboRpcExtBuilders.buildRpcExt(serviceBean);
+ assertNotNull(result);
+ assertTrue(result.contains("\"protocol\":\"\""));
+ }
+
+ @Test
+ void testBuildRpcExtWithMethodConfigs() {
+ when(serviceBean.getProtocol()).thenReturn(protocolConfig);
+ when(protocolConfig.getName()).thenReturn("dubbo");
+ when(serviceBean.getGroup()).thenReturn("testGroup");
+ when(serviceBean.getVersion()).thenReturn("1.0.0");
+ when(serviceBean.getLoadbalance()).thenReturn("random");
+ when(serviceBean.getRetries()).thenReturn(3);
+ when(serviceBean.getTimeout()).thenReturn(2000);
+ when(serviceBean.getSent()).thenReturn(true);
+ when(serviceBean.getCluster()).thenReturn("failover");
+ when(serviceBean.getSerialization()).thenReturn("hessian2");
+
+ MethodConfig methodConfig = new MethodConfig();
+ methodConfig.setName("sayHello");
+ methodConfig.setLoadbalance("roundrobin");
+ methodConfig.setRetries(5);
+ methodConfig.setTimeout(3000);
+ methodConfig.setSent(false);
+
+ List<MethodConfig> methods = new ArrayList<>();
+ methods.add(methodConfig);
+ when(serviceBean.getMethods()).thenReturn(methods);
+
+ String result = DubboRpcExtBuilders.buildRpcExt(serviceBean);
+ assertNotNull(result);
+ assertTrue(result.contains("\"methods\":[{"));
+ assertTrue(result.contains("\"name\":\"sayHello\""));
+ assertTrue(result.contains("\"loadbalance\":\"roundrobin\""));
+ assertTrue(result.contains("\"retries\":5"));
+ assertTrue(result.contains("\"timeout\":3000"));
+ }
+
+ @Test
+ void testBuildRpcExtWithEmptyProtocolName() {
+ when(serviceBean.getProtocol()).thenReturn(protocolConfig);
+ when(protocolConfig.getName()).thenReturn("");
+ when(serviceBean.getGroup()).thenReturn(null);
+ when(serviceBean.getVersion()).thenReturn(null);
+ when(serviceBean.getLoadbalance()).thenReturn(null);
+ when(serviceBean.getRetries()).thenReturn(null);
+ when(serviceBean.getTimeout()).thenReturn(null);
+ when(serviceBean.getSent()).thenReturn(null);
+ when(serviceBean.getCluster()).thenReturn(null);
+ when(serviceBean.getSerialization()).thenReturn(null);
+ when(serviceBean.getMethods()).thenReturn(null);
+
+ String result = DubboRpcExtBuilders.buildRpcExt(serviceBean);
+ assertNotNull(result);
+ assertTrue(result.contains("\"protocol\":\"\""));
+ }
+}