From ef7d0490297cd38e3dd43f385f133acd8557837e Mon Sep 17 00:00:00 2001 From: hengyuss <1183660933@qq.com> Date: Wed, 5 Aug 2026 17:27:08 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20ServiceProcessor=20imports=20Spring?= =?UTF-8?q?=20@Service=20instead=20of=20Dubbo=20@Service=20=E2=80=94=20old?= =?UTF-8?q?-style=20Dubbo=20beans=20never=20get=20beanPath?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../processor/extractor/ServiceProcessor.java | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) 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 447357334689..babb9709c371 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,14 +17,23 @@ 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.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.DubboRpcExt; +import org.apache.shenyu.common.constant.Constants; import org.apache.shenyu.common.enums.RpcTypeEnum; +import org.apache.shenyu.common.utils.GsonUtils; import org.apache.shenyu.common.utils.ListUtil; -import org.springframework.stereotype.Service; import java.util.List; +import java.util.Optional; + +import static org.apache.dubbo.remoting.Constants.DEFAULT_CONNECT_TIMEOUT; /** * ServiceProcessor. @@ -38,7 +47,14 @@ public List supportedClient() { @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 +66,35 @@ public void process(final ApiBean.ApiDefinition definition, final Service annota public Class matchAnnotation() { return Service.class; } + + private String getRpcExt(final ApiBean apiBean) { + final Object beanInstance = apiBean.getBeanInstance(); + if (beanInstance instanceof ServiceBean) { + return getRpcExt((ServiceBean) beanInstance); + } + return "{}"; + } + + private String getRpcExt(final ApiBean.ApiDefinition definition) { + final Object beanInstance = definition.getApiBean().getBeanInstance(); + if (beanInstance instanceof ServiceBean) { + return getRpcExt((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); + } } From 1cfa7c29dca04aceb4febe2f6df053b1a5577328 Mon Sep 17 00:00:00 2001 From: hengyuss <1183660933@qq.com> Date: Thu, 6 Aug 2026 16:34:28 +0800 Subject: [PATCH 2/2] fix: ServiceProcessor uses Dubbo @Service, extract shared DubboRpcExtBuilders --- .../dubbo/ApacheDubboServiceBeanListener.java | 37 +--- .../extractor/DubboServiceProcessor.java | 28 +-- .../processor/extractor/ServiceProcessor.java | 28 +-- .../extractor/DubboServiceProcessorTest.java | 175 ++++++++++++++++++ .../extractor/ServiceProcessorTest.java | 175 ++++++++++++++++++ .../shenyu-client-dubbo-common/pom.xml | 6 + .../dubbo/common/dto/DubboRpcExtBuilders.java | 65 +++++++ .../common/dto/DubboRpcExtBuildersTest.java | 140 ++++++++++++++ 8 files changed, 569 insertions(+), 85 deletions(-) create mode 100644 shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/test/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/DubboServiceProcessorTest.java create mode 100644 shenyu-client/shenyu-client-dubbo/shenyu-client-apache-dubbo/src/test/java/org/apache/shenyu/client/apache/dubbo/processor/extractor/ServiceProcessorTest.java create mode 100644 shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/src/main/java/org/apache/shenyu/client/dubbo/common/dto/DubboRpcExtBuilders.java create mode 100644 shenyu-client/shenyu-client-dubbo/shenyu-client-dubbo-common/src/test/java/org/apache/shenyu/client/dubbo/common/dto/DubboRpcExtBuildersTest.java 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 c537b04c3d53..4606103c8663 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 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.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 String getPort() { } 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 71e4602c68a2..bfe672ac3c3b 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 matchAnnotation() { 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 @@ private String getRpcExt(final ApiBean apiBean) { 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 babb9709c371..83c332282bdb 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,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.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.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; /** * ServiceProcessor. @@ -70,7 +63,7 @@ public Class matchAnnotation() { 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 @@ private String getRpcExt(final ApiBean apiBean) { 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/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 000000000000..31087b93d400 --- /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 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 000000000000..3d8e1c0152c4 --- /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 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 cd8a537bb663..53e292615373 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 @@ spring-web provided + + org.apache.dubbo + dubbo + ${apache.dubbo.version} + provided + 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 000000000000..02d5f6d54c2a --- /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 000000000000..d6955667231c --- /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 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\":\"\"")); + } +}