You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by cr...@apache.org on 2023/11/06 05:29:29 UTC
(dubbo) 01/01: Merge remote-tracking branch 'upstream/3.2' into 3.3
This is an automated email from the ASF dual-hosted git repository.
crazyhzm pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git
commit 35b668239340643f8fd453792e5305aea0f76662
Merge: 26b9f3e48d 2aca2e383b
Author: crazyhzm <cr...@gmail.com>
AuthorDate: Mon Nov 6 13:29:10 2023 +0800
Merge remote-tracking branch 'upstream/3.2' into 3.3
# Conflicts:
# dubbo-cluster/pom.xml
# dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
# dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/beans/factory/annotation/ServiceAnnotationPostProcessor.java
# dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-consumer/pom.xml
# dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-provider/pom.xml
# dubbo-demo/dubbo-demo-spring-boot/pom.xml
# dubbo-dependencies-bom/pom.xml
# dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/ParamType.java
# dubbo-spring-boot/pom.xml
dubbo-cluster/pom.xml | 27 +-
.../common/beans/factory/ScopeBeanFactory.java | 5 -
.../dubbo/common/compact/Dubbo2ActivateUtils.java | 169 ++++++++
.../dubbo/common/compact/Dubbo2CompactUtils.java | 118 ++++++
.../compact/Dubbo2GenericExceptionUtils.java | 129 ++++++
.../dubbo/common/constants/CommonConstants.java | 3 +
.../dubbo/common/extension/ExtensionLoader.java | 41 +-
.../extension/support/ActivateComparator.java | 16 +-
.../extension/support/WrapperComparator.java | 12 +-
.../apache/dubbo/common/json/impl/JacksonImpl.java | 2 +
.../common/utils/ServiceAnnotationResolver.java | 11 +-
.../apache/dubbo/config/ReferenceConfigBase.java | 4 +-
.../common/extension/ExtensionLoaderTest.java | 10 -
.../extension/support/ActivateComparatorTest.java | 11 +-
.../dubbo/common/utils/AnnotationUtilsTest.java | 28 +-
...he.dubbo.common.extension.activate.ActivateExt1 | 2 -
dubbo-compatible/pom.xml | 11 +
.../alibaba/dubbo/common/extension/Activate.java | 0
.../alibaba/dubbo/config/annotation/Reference.java | 0
.../alibaba/dubbo/config/annotation/Service.java | 0
.../java/com/alibaba/dubbo/rpc/RpcException.java | 0
.../com/alibaba/dubbo/rpc/service/EchoService.java | 0
.../dubbo/rpc/service/GenericException.java | 0
.../alibaba/dubbo/rpc/service/GenericService.java | 0
.../dubbo/common/extension/ExtensionTest.java | 26 ++
.../common/extension/activate/ActivateExt1.java | 9 +-
.../extension/activate/impl/ActivateExt1Impl1.java | 8 +-
.../activate/impl/OldActivateExt1Impl2.java | 0
.../activate/impl/OldActivateExt1Impl3.java | 0
.../extension/support/ActivateComparatorTest.java | 28 +-
.../dubbo/common/extension/support/Filter0.java | 5 +-
.../dubbo/common/extension/support/Filter1.java | 5 +-
.../dubbo/common/extension/support/Filter2.java | 5 +-
.../dubbo/common/extension/support/Filter3.java | 5 +-
.../dubbo/common/extension/support/Filter4.java | 5 +-
.../dubbo/common/extension/support/OldFilter0.java | 0
.../dubbo/common/extension/support/OldFilter5.java | 0
.../common/extension/support/Order0Filter0.java | 6 +-
.../common/extension/support/Order0Filter1.java | 6 +-
.../common/extension/support/Order0Filter2.java | 6 +-
.../dubbo/common/utils/AnnotationUtilsTest.java | 0
.../org/apache/dubbo/config/MethodConfigTest.java | 39 +-
.../org/apache/dubbo/config/spring/api/Box.java | 7 +-
.../dubbo/config/spring/api/DemoService.java | 12 +-
.../dubbo/config/spring/api/HelloService.java | 6 +-
.../ServiceAnnotationTestConfiguration.java | 109 +++++
.../DubboComponentScanRegistrarTest.java | 129 ++++++
.../annotation/DubboConfigConfigurationTest.java | 94 +++++
.../context/annotation/EnableDubboConfigTest.java | 140 ++++++
.../spring/context/annotation/EnableDubboTest.java | 31 +-
.../annotation/consumer/ConsumerConfiguration.java | 89 ++--
.../consumer/test/TestConsumerConfiguration.java | 0
.../annotation/provider/DefaultHelloService.java | 15 +-
.../annotation/provider/DemoServiceImpl.java | 33 +-
.../annotation/provider/HelloServiceImpl.java | 0
.../annotation/provider/ProviderConfiguration.java | 120 ++++++
.../apache/dubbo/config/spring/filter/MockDao.java | 8 +-
.../dubbo/config/spring/filter/MockDaoImpl.java | 8 +-
.../dubbo/config/spring/filter/MockFilter.java | 66 +++
.../apache/dubbo/generic/GenericServiceTest.java | 6 +-
.../AbstractAnnotationProcessingTest.java | 65 +++
.../AnnotationProcessingTestProcessor.java | 76 ++++
.../processing/CompilerInvocationInterceptor.java | 45 ++
.../builder/ArrayTypeDefinitionBuilderTest.java | 125 ++++++
.../CollectionTypeDefinitionBuilderTest.java | 105 +++++
.../builder/EnumTypeDefinitionBuilderTest.java | 69 +++
.../builder/GeneralTypeDefinitionBuilderTest.java | 67 +++
.../builder/MapTypeDefinitionBuilderTest.java | 139 ++++++
.../PrimitiveTypeDefinitionBuilderTest.java | 131 ++++++
.../builder/ServiceDefinitionBuilderTest.java | 83 ++++
.../builder/SimpleTypeDefinitionBuilderTest.java | 146 +++++++
.../processing/model/ArrayTypeModel.java | 30 +-
.../processing/model/CollectionTypeModel.java | 34 +-
.../annotation/processing/model/Color.java | 36 +-
.../annotation/processing/model/MapTypeModel.java | 33 +-
.../annotation/processing/model/Model.java | 89 ++++
.../processing/model/PrimitiveTypeModel.java | 65 ++-
.../processing/model/SimpleTypeModel.java | 161 +++++++
.../AnnotatedMethodParameterProcessorTest.java | 59 +++
.../processing/util/AnnotationUtilsTest.java | 0
.../annotation/processing/util/FieldUtilsTest.java | 259 ++++++++++++
.../processing/util/LoggerUtilsTest.java | 38 +-
.../processing/util/MemberUtilsTest.java | 113 +++++
.../processing/util/MethodUtilsTest.java | 196 +++++++++
.../util/ServiceAnnotationUtilsTest.java | 0
.../annotation/processing/util/TypeUtilsTest.java | 470 +++++++++++++++++++++
.../dubbo/metadata/rest/DefaultRestService.java | 69 +++
.../apache/dubbo/metadata/rest/RestService.java | 32 +-
.../dubbo/metadata/rest/SpringRestService.java | 95 +++++
.../dubbo/metadata/rest/StandardRestService.java | 107 +++++
.../java/org/apache/dubbo/metadata/rest/User.java | 50 ++-
.../org/apache/dubbo/metadata/tools/Ancestor.java | 19 +-
.../org/apache/dubbo/metadata/tools/Compiler.java | 120 ++++++
.../apache/dubbo/metadata/tools/CompilerTest.java | 27 +-
.../metadata/tools/DefaultRestServiceTest.java | 29 +-
.../dubbo/metadata/tools/DefaultTestService.java | 36 +-
.../dubbo/metadata/tools/GenericTestService.java | 0
.../org/apache/dubbo/metadata/tools/Parent.java | 55 ++-
.../dubbo/metadata/tools/RestServiceTest.java | 26 +-
.../metadata/tools/SpringRestServiceTest.java | 23 +-
.../metadata/tools/StandardRestServiceTest.java | 23 +-
.../apache/dubbo/metadata/tools/TestProcessor.java | 41 +-
.../apache/dubbo/metadata/tools/TestService.java | 42 +-
.../dubbo/metadata/tools/TestServiceImpl.java | 0
.../dubbo/rpc/filter/GenericImplFilterTest.java | 64 +++
.../org/apache/dubbo/rpc/support/DemoService.java | 64 +++
.../java/org/apache/dubbo/rpc/support/Person.java | 41 +-
.../java/org/apache/dubbo/rpc/support/Type.java | 5 +-
.../src/test/resources/META-INF/config.properties | 36 ++
.../src/test/resources/META-INF/default.properties | 4 +
.../resources/META-INF/dubbb-consumer.properties | 12 +
.../resources/META-INF/dubbb-provider.properties | 24 ++
.../resources/META-INF/dubbo-consumer.properties | 13 +
.../resources/META-INF/dubbo-provider.properties | 24 ++
...he.dubbo.common.extension.activate.ActivateExt1 | 2 +
...g.apache.dubbo.common.extension.support.Filter0 | 5 +
.../dubbo/internal/org.apache.dubbo.rpc.Filter | 1 +
.../apache/dubbo/config/AbstractConfigTest.java | 209 +++------
.../org/apache/dubbo/config/MethodConfigTest.java | 65 ++-
.../org/apache/dubbo/config/common/Person.java | 38 +-
dubbo-config/dubbo-config-spring/pom.xml | 2 +-
.../ReferenceAnnotationBeanPostProcessor.java | 12 +-
.../annotation/ServiceAnnotationPostProcessor.java | 30 +-
.../config/spring/util/DubboAnnotationUtils.java | 4 +-
.../spring/context/annotation/EnableDubboTest.java | 16 +-
.../consumer/test/TestConsumerConfiguration.java | 17 +-
.../annotation/provider/HelloServiceImpl.java | 2 +-
dubbo-demo/dubbo-demo-annotation/pom.xml | 2 +-
dubbo-demo/dubbo-demo-api/pom.xml | 2 +-
.../dubbo-demo-native-consumer/pom.xml | 2 +-
.../dubbo-demo-native-provider/pom.xml | 2 +-
dubbo-demo/dubbo-demo-spring-boot/pom.xml | 4 +-
dubbo-demo/dubbo-demo-xml/pom.xml | 2 +-
dubbo-dependencies-bom/pom.xml | 12 +-
.../dubbo/metadata/AbstractCacheManager.java | 8 +-
.../rest/jaxrs/FormBodyParameterProcessor.java | 54 +++
.../processing/util/AnnotationUtilsTest.java | 24 +-
.../util/ServiceAnnotationUtilsTest.java | 4 +-
.../dubbo/metadata/tools/GenericTestService.java | 2 +-
.../dubbo/metadata/tools/TestServiceImpl.java | 6 -
.../rest/AbstractServiceRestMetadataResolver.java | 9 +-
.../dubbo/metadata/rest/JAXRSClassConstants.java | 5 +
.../org/apache/dubbo/metadata/rest/ParamType.java | 4 +-
.../dubbo/metadata/rest/RestMetadataConstants.java | 5 +
...metadata.rest.AnnotatedMethodParameterProcessor | 1 +
.../org/apache/dubbo/rpc/filter/GenericFilter.java | 17 +-
.../apache/dubbo/rpc/filter/GenericImplFilter.java | 8 +-
.../dubbo/rpc/filter/GenericImplFilterTest.java | 36 +-
.../dubbo/qos/protocol/QosProtocolWrapper.java | 4 +-
.../registry/client/ServiceDiscoveryRegistry.java | 37 +-
.../client/migration/model/MigrationRule.java | 5 +-
.../multiple/MultipleServiceDiscovery.java | 39 +-
.../multiple/MultipleServiceDiscoveryTest.java | 119 ++++++
.../java/org/apache/dubbo/rpc/AppResponse.java | 17 +-
.../dubbo/rpc/proxy/AbstractProxyFactory.java | 13 +-
.../dubbo/rpc/support/Dubbo2RpcExceptionUtils.java | 73 ++++
.../rpc/protocol/dubbo/ArgumentCallbackTest.java | 12 +-
.../filter/DubboContainerResponseContextImpl.java | 10 +-
.../protocol/rest/request/NettyRequestFacade.java | 4 +
.../dubbo/rpc/protocol/rest/DemoService.java | 9 +-
.../dubbo/rpc/protocol/rest/DemoServiceImpl.java | 6 +
.../rpc/protocol/rest/JaxrsRestProtocolTest.java | 19 +-
dubbo-spring-boot/pom.xml | 2 +-
pom.xml | 4 +-
164 files changed, 5521 insertions(+), 804 deletions(-)
diff --cc dubbo-cluster/pom.xml
index 8afb607af4,7e2d58a95a..c21fab1581
--- a/dubbo-cluster/pom.xml
+++ b/dubbo-cluster/pom.xml
@@@ -88,15 -88,31 +88,36 @@@
<optional>true</optional>
</dependency>
<dependency>
- <groupId>org.openjdk.nashorn</groupId>
- <artifactId>nashorn-core</artifactId>
- <version>${nashorn-core.version}</version>
+ <groupId>io.micrometer</groupId>
+ <artifactId>micrometer-tracing-integration-test</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
+
+ <profiles>
+ <!--
+ https://github.com/openjdk/nashorn
+ Nashorn used to be part of the JDK until Java 14.
+ This project provides a standalone version of Nashorn suitable for use with Java 11 and later.
+ -->
+ <profile>
+ <id>nashorn-jdk11</id>
+ <activation>
+ <jdk>[11,)</jdk>
+ </activation>
+ <dependencies>
+ <dependency>
+ <groupId>org.openjdk.nashorn</groupId>
+ <artifactId>nashorn-core</artifactId>
+ <version>${nashorn-core.version}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+ </profiles>
</project>
diff --cc dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
index 2c6baee9ab,8b96f96b69..a0faee25a9
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/constants/CommonConstants.java
@@@ -639,22 -643,8 +639,25 @@@ public interface CommonConstants
String DUBBO_PACKABLE_METHOD_FACTORY = "dubbo.application.parameters." + PACKABLE_METHOD_FACTORY_KEY;
+ String DUBBO_TAG_HEADER = "dubbo-tag";
+
+ String REST_SERVICE_DEPLOYER_URL_ATTRIBUTE_KEY = "restServiceDeployerAttributeKey";
+
+ String SERVICE_DEPLOYER_ATTRIBUTE_KEY = "serviceDeployer";
+
+
+
String DUBBO_MANUAL_REGISTER_KEY = "dubbo.application.manual-register";
+ String DUBBO2_COMPACT_ENABLE = "dubbo.compact.enable";
+
++
+ String POD_NAMESPACE = "POD_NAMESPACE";
+
+ String CLUSTER_DOMAIN = "CLUSTER_DOMAIN";
+
+ String EXT_PROTOCOL = "ext.protocol";
+
+ String IS_EXTRA = "isExtra";
+
}
diff --cc dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
index 5bc262708e,bea5d7c474..2c44831c54
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
@@@ -18,8 -18,9 +18,10 @@@ package org.apache.dubbo.common.extensi
import org.apache.dubbo.common.Extension;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.aot.NativeDetector;
import org.apache.dubbo.common.beans.support.InstantiationStrategy;
+ import org.apache.dubbo.common.compact.Dubbo2ActivateUtils;
+ import org.apache.dubbo.common.compact.Dubbo2CompactUtils;
import org.apache.dubbo.common.context.Lifecycle;
import org.apache.dubbo.common.extension.support.ActivateComparator;
import org.apache.dubbo.common.extension.support.WrapperComparator;
diff --cc dubbo-demo/dubbo-demo-spring-boot/pom.xml
index f6d13b0f25,7c10fbd9d2..aa7ed6c1ef
--- a/dubbo-demo/dubbo-demo-spring-boot/pom.xml
+++ b/dubbo-demo/dubbo-demo-spring-boot/pom.xml
@@@ -33,13 -33,13 +33,13 @@@
</modules>
<properties>
- <maven.compiler.source>8</maven.compiler.source>
- <maven.compiler.target>8</maven.compiler.target>
<skip_maven_deploy>true</skip_maven_deploy>
- <spring-boot.version>2.7.16</spring-boot.version>
+ <spring-boot.version>2.7.17</spring-boot.version>
+ <slf4j-log4j12_version>1.7.33</slf4j-log4j12_version>
- <spring-boot-maven-plugin.version>2.7.16</spring-boot-maven-plugin.version>
+ <spring-boot-maven-plugin.version>2.7.17</spring-boot-maven-plugin.version>
<micrometer-core.version>1.11.5</micrometer-core.version>
</properties>
+
<dependencyManagement>
<dependencies>
<dependency>
diff --cc dubbo-dependencies-bom/pom.xml
index 3735264a62,ca615cbc52..45d97ec1cc
--- a/dubbo-dependencies-bom/pom.xml
+++ b/dubbo-dependencies-bom/pom.xml
@@@ -150,16 -149,11 +150,16 @@@
<tomcat_embed_version>8.5.87</tomcat_embed_version>
<jetcd_version>0.7.6</jetcd_version>
<nacos_version>2.2.4</nacos_version>
+ <sentinel.version>1.8.6</sentinel.version>
+ <seata.version>1.6.1</seata.version>
- <grpc.version>1.58.0</grpc.version>
+ <grpc.version>1.59.0</grpc.version>
<grpc_contrib_verdion>0.8.1</grpc_contrib_verdion>
<jprotoc_version>1.2.2</jprotoc_version>
+ <mustache_version>0.9.10</mustache_version>
<!-- Log libs -->
<slf4j_version>1.7.36</slf4j_version>
+ <!-- Do not upgrade the log4j12 version, or else reload4j and log4j will coexist -->
+ <slf4j-log4j12_version>1.7.33</slf4j-log4j12_version>
<jcl_version>1.2</jcl_version>
<log4j_version>1.2.17</log4j_version>
<logback_version>1.2.11</logback_version>
diff --cc dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/AbstractServiceRestMetadataResolver.java
index d0062f74cd,0000000000..a520005e3c
mode 100644,000000..100644
--- a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/AbstractServiceRestMetadataResolver.java
+++ b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/AbstractServiceRestMetadataResolver.java
@@@ -1,438 -1,0 +1,443 @@@
+/*
+ * 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.dubbo.metadata.rest;
+
++import org.apache.dubbo.common.compact.Dubbo2CompactUtils;
+import org.apache.dubbo.common.utils.MethodComparator;
+import org.apache.dubbo.common.utils.ServiceAnnotationResolver;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.apache.dubbo.config.annotation.Service;
+import org.apache.dubbo.metadata.definition.MethodDefinitionBuilder;
+import org.apache.dubbo.metadata.definition.model.MethodDefinition;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.sort;
+import static java.util.Collections.unmodifiableMap;
+import static org.apache.dubbo.common.function.ThrowableFunction.execute;
+import static org.apache.dubbo.common.utils.AnnotationUtils.isAnnotationPresent;
+import static org.apache.dubbo.common.utils.AnnotationUtils.isAnyAnnotationPresent;
+import static org.apache.dubbo.common.utils.ClassUtils.forName;
+import static org.apache.dubbo.common.utils.ClassUtils.getAllInterfaces;
+import static org.apache.dubbo.common.utils.MemberUtils.isPrivate;
+import static org.apache.dubbo.common.utils.MemberUtils.isStatic;
+import static org.apache.dubbo.common.utils.MethodUtils.excludedDeclaredClass;
+import static org.apache.dubbo.common.utils.MethodUtils.getAllMethods;
+import static org.apache.dubbo.common.utils.MethodUtils.overrides;
+
+/**
+ * The abstract {@link ServiceRestMetadataResolver} class to provider some template methods assemble the instance of
+ * {@link ServiceRestMetadata} will extended by the sub-classes.
+ *
+ * @since 2.7.6
+ */
+public abstract class AbstractServiceRestMetadataResolver implements ServiceRestMetadataResolver {
+
+ private final Map<String, List<AnnotatedMethodParameterProcessor>> parameterProcessorsMap;
+ private final Set<NoAnnotatedParameterRequestTagProcessor> noAnnotatedParameterRequestTagProcessors;
+
+ public AbstractServiceRestMetadataResolver(ApplicationModel applicationModel) {
+ this.parameterProcessorsMap = loadAnnotatedMethodParameterProcessors(applicationModel);
+ this.noAnnotatedParameterRequestTagProcessors = loadNoAnnotatedMethodParameterProcessors(applicationModel);
+ }
+
+ @Override
+ public final boolean supports(Class<?> serviceType) {
+ return supports(serviceType, false);
+ }
+
+ @Override
+ public final boolean supports(Class<?> serviceType, boolean consumer) {
+
+ if (serviceType == null) {
+ return false;
+ }
+
+ // for consumer
+ // it is possible serviceType is impl
+ // for provider
+ // for xml config bean && isServiceAnnotationPresent(serviceType)
+ // isImplementedInterface(serviceType) SpringController
+ return supports0(serviceType);
+ }
+
+ protected final boolean isImplementedInterface(Class<?> serviceType) {
+ return !getAllInterfaces(serviceType).isEmpty();
+ }
+
+ protected final boolean isServiceAnnotationPresent(Class<?> serviceType) {
- return isAnyAnnotationPresent(serviceType, DubboService.class, Service.class,
- com.alibaba.dubbo.config.annotation.Service.class);
++ if (Dubbo2CompactUtils.isEnabled() && Dubbo2CompactUtils.isServiceClassLoaded()) {
++ return isAnyAnnotationPresent(serviceType, DubboService.class, Service.class,
++ Dubbo2CompactUtils.getServiceClass());
++ } else {
++ return isAnyAnnotationPresent(serviceType, DubboService.class, Service.class);
++ }
+ }
+
+ /**
+ * internal support method
+ *
+ * @param serviceType Dubbo Service interface or type
+ * @return If supports, return <code>true</code>, or <code>false</code>
+ */
+ protected abstract boolean supports0(Class<?> serviceType);
+
+ @Override
+ public final ServiceRestMetadata resolve(Class<?> serviceType) {
+ ServiceRestMetadata serviceRestMetadata = new ServiceRestMetadata();
+
+ // Process ServiceRestMetadata
+ processServiceRestMetadata(serviceRestMetadata, serviceType);
+
+ return resolve(serviceType, serviceRestMetadata);
+ }
+
+
+ @Override
+ public final ServiceRestMetadata resolve(Class<?> serviceType, ServiceRestMetadata serviceRestMetadata) {
+ serviceRestMetadata.setCodeStyle(this.getClass());
+ // Process RestMethodMetadata
+ processAllRestMethodMetadata(serviceRestMetadata, serviceType);
+
+ return serviceRestMetadata;
+ }
+
+ /**
+ * Process the service type including the sub-routines:
+ * <ul>
+ * <li>{@link ServiceRestMetadata#setServiceInterface(String)}</li>
+ * <li>{@link ServiceRestMetadata#setVersion(String)}</li>
+ * <li>{@link ServiceRestMetadata#setGroup(String)}</li>
+ * </ul>
+ *
+ * @param serviceRestMetadata {@link ServiceRestMetadata}
+ * @param serviceType Dubbo Service interface or type
+ */
+ protected void processServiceRestMetadata(ServiceRestMetadata serviceRestMetadata, Class<?> serviceType) {
+ ServiceAnnotationResolver resolver = new ServiceAnnotationResolver(serviceType);
+ serviceRestMetadata.setServiceInterface(resolver.resolveInterfaceClassName());
+ serviceRestMetadata.setVersion(resolver.resolveVersion());
+ serviceRestMetadata.setGroup(resolver.resolveGroup());
+ }
+
+ /**
+ * Process all {@link RestMethodMetadata}
+ *
+ * @param serviceRestMetadata {@link ServiceRestMetadata}
+ * @param serviceType Dubbo Service interface or type
+ */
+ protected void processAllRestMethodMetadata(ServiceRestMetadata serviceRestMetadata, Class<?> serviceType) {
+ Class<?> serviceInterfaceClass = resolveServiceInterfaceClass(serviceRestMetadata, serviceType);
+ Map<Method, Method> serviceMethodsMap = resolveServiceMethodsMap(serviceType, serviceInterfaceClass);
+ for (Map.Entry<Method, Method> entry : serviceMethodsMap.entrySet()) {
+ // try the overrider method first
+ Method serviceMethod = entry.getKey();
+ // If failed, it indicates the overrider method does not contain metadata , then try the declared method
+ if (!processRestMethodMetadata(serviceMethod, serviceType, serviceInterfaceClass, serviceRestMetadata::addRestMethodMetadata, serviceRestMetadata)) {
+ Method declaredServiceMethod = entry.getValue();
+ processRestMethodMetadata(declaredServiceMethod, serviceType, serviceInterfaceClass,
+ serviceRestMetadata::addRestMethodMetadata, serviceRestMetadata);
+ }
+ }
+ }
+
+ /**
+ * Resolve a map of all public services methods from the specified service type and its interface class, whose key is the
+ * declared method, and the value is the overrider method
+ *
+ * @param serviceType the service interface implementation class
+ * @param serviceInterfaceClass the service interface class
+ * @return non-null read-only {@link Map}
+ */
+ protected Map<Method, Method> resolveServiceMethodsMap(Class<?> serviceType, Class<?> serviceInterfaceClass) {
+ Map<Method, Method> serviceMethodsMap = new LinkedHashMap<>();
+ // exclude the public methods declared in java.lang.Object.class
+ List<Method> declaredServiceMethods = new ArrayList<>(getAllMethods(serviceInterfaceClass, excludedDeclaredClass(Object.class)));
+
+ // controller class
+ if (serviceType.equals(serviceInterfaceClass)) {
+ putServiceMethodToMap(serviceMethodsMap, declaredServiceMethods);
+ return unmodifiableMap(serviceMethodsMap);
+ }
+
+ // for interface , such as consumer interface
+ if (serviceType.isInterface()) {
+ putServiceMethodToMap(serviceMethodsMap, declaredServiceMethods);
+ return unmodifiableMap(serviceMethodsMap);
+ }
+
+ List<Method> serviceMethods = new ArrayList<>(getAllMethods(serviceType, excludedDeclaredClass(Object.class)));
+
+
+ // sort methods
+ sort(declaredServiceMethods, MethodComparator.INSTANCE);
+ sort(serviceMethods, MethodComparator.INSTANCE);
+
+ for (Method declaredServiceMethod : declaredServiceMethods) {
+ for (Method serviceMethod : serviceMethods) {
+ if (overrides(serviceMethod, declaredServiceMethod)) {
+ serviceMethodsMap.put(serviceMethod, declaredServiceMethod);
+ // override method count > 1
+// // once method match ,break for decrease loop times
+// break;
+ }
+ }
+ }
+ // make them to be read-only
+ return unmodifiableMap(serviceMethodsMap);
+ }
+
+ private void putServiceMethodToMap(Map<Method, Method> serviceMethodsMap, List<Method> declaredServiceMethods) {
+ declaredServiceMethods.stream().forEach(method -> {
+
+ // filter static private default
+ if (isStatic(method) || isPrivate(method) || method.isDefault()) {
+ return;
+ }
+ serviceMethodsMap.put(method, method);
+ });
+ }
+
+ /**
+ * Resolve the class of Dubbo Service interface
+ *
+ * @param serviceRestMetadata {@link ServiceRestMetadata}
+ * @param serviceType Dubbo Service interface or type
+ * @return non-null
+ * @throws RuntimeException If the class is not found, the {@link RuntimeException} wraps the cause will be thrown
+ */
+ protected Class<?> resolveServiceInterfaceClass(ServiceRestMetadata serviceRestMetadata, Class<?> serviceType) {
+ return execute(serviceType.getClassLoader(), classLoader -> {
+ String serviceInterface = serviceRestMetadata.getServiceInterface();
+ return forName(serviceInterface, classLoader);
+ });
+ }
+
+ /**
+ * Process the single {@link RestMethodMetadata} by the specified {@link Consumer} if present
+ *
+ * @param serviceMethod Dubbo Service method
+ * @param serviceType Dubbo Service interface or type
+ * @param serviceInterfaceClass The type of Dubbo Service interface
+ * @param metadataToProcess {@link RestMethodMetadata} to process if present
+ * @return if processed successfully, return <code>true</code>, or <code>false</code>
+ */
+ protected boolean processRestMethodMetadata(Method serviceMethod, Class<?> serviceType,
+ Class<?> serviceInterfaceClass,
+ Consumer<RestMethodMetadata> metadataToProcess,
+ ServiceRestMetadata serviceRestMetadata) {
+
+ if (!isRestCapableMethod(serviceMethod, serviceType, serviceInterfaceClass)) {
+ return false;
+ }
+
+ String requestPath = resolveRequestPath(serviceMethod, serviceType, serviceInterfaceClass); // requestPath is required
+
+ if (requestPath == null) {
+ return false;
+ }
+
+ String requestMethod = resolveRequestMethod(serviceMethod, serviceType, serviceInterfaceClass); // requestMethod is required
+
+ if (requestMethod == null) {
+ return false;
+ }
+
+ RestMethodMetadata metadata = new RestMethodMetadata();
+
+ metadata.setCodeStyle(this.getClass());
+
+ // to consumer service map
+ metadata.setReflectMethod(serviceMethod);
+
+ MethodDefinition methodDefinition = resolveMethodDefinition(serviceMethod, serviceType, serviceInterfaceClass);
+ // Set MethodDefinition
+ metadata.setMethod(methodDefinition);
+
+ // process produces
+ Set<String> produces = new LinkedHashSet<>();
+ processProduces(serviceMethod, serviceType, serviceInterfaceClass, produces);
+
+ // process consumes
+ Set<String> consumes = new LinkedHashSet<>();
+ processConsumes(serviceMethod, serviceType, serviceInterfaceClass, consumes);
+
+ // Initialize RequestMetadata
+ RequestMetadata request = metadata.getRequest();
+ request.setPath(requestPath);
+ request.appendContextPathFromUrl(serviceRestMetadata.getContextPathFromUrl());
+ request.setMethod(requestMethod);
+ request.setProduces(produces);
+ request.setConsumes(consumes);
+
+ // process the annotated method parameters
+ processAnnotatedMethodParameters(serviceMethod, serviceType, serviceInterfaceClass, metadata);
+
+
+ // Post-Process
+ postResolveRestMethodMetadata(serviceMethod, serviceType, serviceInterfaceClass, metadata);
+
+ // Accept RestMethodMetadata
+ metadataToProcess.accept(metadata);
+
+ return true;
+ }
+
+ /**
+ * Test the service method is capable of REST or not?
+ *
+ * @param serviceMethod Dubbo Service method
+ * @param serviceType Dubbo Service interface or type
+ * @param serviceInterfaceClass The type of Dubbo Service interface
+ * @return If capable, return <code>true</code>
+ */
+ protected abstract boolean isRestCapableMethod(Method serviceMethod, Class<?> serviceType, Class<?>
+ serviceInterfaceClass);
+
+ /**
+ * Resolve the request method
+ *
+ * @param serviceMethod Dubbo Service method
+ * @param serviceType Dubbo Service interface or type
+ * @param serviceInterfaceClass The type of Dubbo Service interface
+ * @return if can't be resolve, return <code>null</code>
+ */
+ protected abstract String resolveRequestMethod(Method serviceMethod, Class<?> serviceType, Class<?>
+ serviceInterfaceClass);
+
+ /**
+ * Resolve the request path
+ *
+ * @param serviceMethod Dubbo Service method
+ * @param serviceType Dubbo Service interface or type
+ * @param serviceInterfaceClass The type of Dubbo Service interface
+ * @return if can't be resolve, return <code>null</code>
+ */
+ protected abstract String resolveRequestPath(Method serviceMethod, Class<?> serviceType, Class<?>
+ serviceInterfaceClass);
+
+ /**
+ * Resolve the {@link MethodDefinition}
+ *
+ * @param serviceMethod Dubbo Service method
+ * @param serviceType Dubbo Service interface or type
+ * @param serviceInterfaceClass The type of Dubbo Service interface
+ * @return if can't be resolve, return <code>null</code>
+ * @see MethodDefinitionBuilder
+ */
+ protected MethodDefinition resolveMethodDefinition(Method serviceMethod, Class<?> serviceType,
+ Class<?> serviceInterfaceClass) {
+ MethodDefinitionBuilder builder = new MethodDefinitionBuilder();
+ return builder.build(serviceMethod);
+ }
+
+ private void processAnnotatedMethodParameters(Method serviceMethod, Class<?> serviceType,
+ Class<?> serviceInterfaceClass, RestMethodMetadata metadata) {
+ int paramCount = serviceMethod.getParameterCount();
+ Parameter[] parameters = serviceMethod.getParameters();
+ for (int i = 0; i < paramCount; i++) {
+ Parameter parameter = parameters[i];
+ // Add indexed parameter name
+ metadata.addIndexToName(i, parameter.getName());
+ processAnnotatedMethodParameter(parameter, i, serviceMethod, serviceType, serviceInterfaceClass, metadata);
+ }
+ }
+
+ protected void processAnnotatedMethodParameter(Parameter parameter, int parameterIndex, Method serviceMethod,
+ Class<?> serviceType, Class<?> serviceInterfaceClass,
+ RestMethodMetadata metadata) {
+ Annotation[] annotations = parameter.getAnnotations();
+
+ if (annotations == null || annotations.length == 0) {
+
+ for (NoAnnotatedParameterRequestTagProcessor processor : noAnnotatedParameterRequestTagProcessors) {
+ // no annotation only one default annotationType
+ if (processor.process(parameter, parameterIndex, metadata)) {
+ return;
+ }
+ }
+
+ }
+
+ for (Annotation annotation : annotations) {
+ String annotationType = annotation.annotationType().getName();
+ parameterProcessorsMap.getOrDefault(annotationType, emptyList())
+ .forEach(processor -> {
+ processor.process(annotation, parameter, parameterIndex, serviceMethod, serviceType,
+ serviceInterfaceClass, metadata);
+ });
+ }
+ }
+
+ protected abstract void processProduces(Method serviceMethod, Class<?> serviceType, Class<?>
+ serviceInterfaceClass,
+ Set<String> produces);
+
+ protected abstract void processConsumes(Method serviceMethod, Class<?> serviceType, Class<?>
+ serviceInterfaceClass,
+ Set<String> consumes);
+
+ protected void postResolveRestMethodMetadata(Method serviceMethod, Class<?> serviceType,
+ Class<?> serviceInterfaceClass, RestMethodMetadata metadata) {
+
+ // parse pathVariable index from url by annotation info
+ PathUtil.setArgInfoSplitIndex(metadata.getRequest().getPath(), metadata.getArgInfos());
+ }
+
+ private static Map<String, List<AnnotatedMethodParameterProcessor>> loadAnnotatedMethodParameterProcessors(ApplicationModel applicationModel) {
+ Map<String, List<AnnotatedMethodParameterProcessor>> parameterProcessorsMap = new LinkedHashMap<>();
+ applicationModel.getExtensionLoader(AnnotatedMethodParameterProcessor.class)
+ .getSupportedExtensionInstances()
+ .forEach(processor -> {
+ List<AnnotatedMethodParameterProcessor> processors =
+ parameterProcessorsMap.computeIfAbsent(processor.getAnnotationName(), k -> new LinkedList<>());
+ processors.add(processor);
+ });
+ return parameterProcessorsMap;
+ }
+
+ private static Set<NoAnnotatedParameterRequestTagProcessor> loadNoAnnotatedMethodParameterProcessors(ApplicationModel applicationModel) {
+ Set<NoAnnotatedParameterRequestTagProcessor> supportedExtensionInstances = applicationModel.getExtensionLoader(NoAnnotatedParameterRequestTagProcessor.class)
+ .getSupportedExtensionInstances();
+
+ return supportedExtensionInstances;
+ }
+
+ public static boolean isServiceMethodAnnotationPresent(Class<?> serviceImpl, String annotationClass) {
+ List<Method> allMethods = getAllMethods(serviceImpl, excludedDeclaredClass(Object.class));
+
+ for (Method method : allMethods) {
+ if (isAnnotationPresent(method, annotationClass)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --cc dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/ParamType.java
index 0ffbf935b6,0000000000..df59bf1da0
mode 100644,000000..100644
--- a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/ParamType.java
+++ b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/ParamType.java
@@@ -1,90 -1,0 +1,90 @@@
+/*
+ * 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.dubbo.metadata.rest;
+
+import org.apache.dubbo.metadata.rest.tag.BodyTag;
+import org.apache.dubbo.metadata.rest.tag.NoAnnotationTag;
+import org.apache.dubbo.metadata.rest.tag.ParamTag;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public enum ParamType {
+ HEADER(addSupportTypes(JAXRSClassConstants.HEADER_PARAM_ANNOTATION_CLASS,
+ SpringMvcClassConstants.REQUEST_HEADER_ANNOTATION_CLASS)),
+
+ PARAM(addSupportTypes(JAXRSClassConstants.QUERY_PARAM_ANNOTATION_CLASS,
+ SpringMvcClassConstants.REQUEST_PARAM_ANNOTATION_CLASS, ParamTag.class)),
+
+ BODY(addSupportTypes(
+ JAXRSClassConstants.REST_EASY_BODY_ANNOTATION_CLASS,
+ SpringMvcClassConstants.REQUEST_BODY_ANNOTATION_CLASS, BodyTag.class)),
+
+ PATH(addSupportTypes(JAXRSClassConstants.PATH_PARAM_ANNOTATION_CLASS,
+ SpringMvcClassConstants.PATH_VARIABLE_ANNOTATION_CLASS)),
+
- FORM(addSupportTypes(JAXRSClassConstants.FORM_PARAM_ANNOTATION_CLASS,
++ FORM(addSupportTypes(JAXRSClassConstants.FORM_PARAM_ANNOTATION_CLASS, JAXRSClassConstants.FORM_BODY_ANNOTATION_CLASS,
+ SpringMvcClassConstants.REQUEST_BODY_ANNOTATION_CLASS)),
+
+ PROVIDER_BODY(addSupportTypes(
+ JAXRSClassConstants.REST_EASY_BODY_ANNOTATION_CLASS, JAXRSClassConstants.FORM_PARAM_ANNOTATION_CLASS,
- SpringMvcClassConstants.REQUEST_BODY_ANNOTATION_CLASS, BodyTag.class)),
++ SpringMvcClassConstants.REQUEST_BODY_ANNOTATION_CLASS, BodyTag.class, JAXRSClassConstants.FORM_BODY_ANNOTATION_CLASS)),
+
+ PROVIDER_NO_ANNOTATION(addSupportTypes(NoAnnotationTag.class)),
+
+ EMPTY(addSupportTypes());
+ private List<Class> annotationClasses;
+
+
+ ParamType(List<Class> annotationClasses) {
+ this.annotationClasses = annotationClasses;
+ }
+
+
+ public boolean supportAnno(Class anno) {
+ if (anno == null) {
+ return false;
+ }
+ return this.annotationClasses.contains(anno);
+ }
+
+ /**
+ * exclude null types
+ *
+ * @param classes
+ * @return
+ */
+ private static List<Class> addSupportTypes(Class... classes) {
+
+ ArrayList<Class> types = new ArrayList<>();
+
+ for (Class clazz : classes) {
+
+ if (clazz == null) {
+ continue;
+ }
+
+ types.add(clazz);
+ }
+
+ return types;
+
+
+ }
+
+
+}
diff --cc dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/RestMetadataConstants.java
index e43b5b557d,0000000000..7e2f51f781
mode 100644,000000..100644
--- a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/RestMetadataConstants.java
+++ b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/RestMetadataConstants.java
@@@ -1,173 -1,0 +1,178 @@@
+/*
+ * 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.dubbo.metadata.rest;
+
+import java.lang.annotation.Annotation;
+
+import static org.apache.dubbo.common.utils.ClassUtils.getClassLoader;
+import static org.apache.dubbo.common.utils.ClassUtils.resolveClass;
+
+/**
+ * The REST Metadata Constants definition interface
+ *
+ * @since 2.7.6
+ */
+public interface RestMetadataConstants {
+
+ /**
+ * The encoding of metadata
+ */
+ String METADATA_ENCODING = "UTF-8";
+
+ /**
+ * {@link ServiceRestMetadata} Resource PATH
+ */
+ String SERVICE_REST_METADATA_RESOURCE_PATH = "META-INF/dubbo/service-rest-metadata.json";
+
+ /**
+ * JAX-RS
+ */
+ interface JAX_RS {
+
+ /**
+ * The annotation class name of @Path
+ */
+ String PATH_ANNOTATION_CLASS_NAME = "javax.ws.rs.Path";
+
+ /**
+ * The annotation class name of @HttpMethod
+ */
+ String HTTP_METHOD_ANNOTATION_CLASS_NAME = "javax.ws.rs.HttpMethod";
+
+ /**
+ * The annotation class name of @Produces
+ */
+ String PRODUCES_ANNOTATION_CLASS_NAME = "javax.ws.rs.Produces";
+
+ /**
+ * The annotation class name of @Consumes
+ */
+ String CONSUMES_ANNOTATION_CLASS_NAME = "javax.ws.rs.Consumes";
+
+ /**
+ * The annotation class name of @DefaultValue
+ */
+ String DEFAULT_VALUE_ANNOTATION_CLASS_NAME = "javax.ws.rs.DefaultValue";
+
+ /**
+ * The annotation class name of @FormParam
+ */
+ String FORM_PARAM_ANNOTATION_CLASS_NAME = "javax.ws.rs.FormParam";
+
+ /**
+ * The annotation class name of @HeaderParam
+ */
+ String HEADER_PARAM_ANNOTATION_CLASS_NAME = "javax.ws.rs.HeaderParam";
+
+ /**
+ * The annotation class name of @MatrixParam
+ */
+ String MATRIX_PARAM_ANNOTATION_CLASS_NAME = "javax.ws.rs.MatrixParam";
+
+ /**
+ * The annotation class name of @QueryParam
+ */
+ String QUERY_PARAM_ANNOTATION_CLASS_NAME = "javax.ws.rs.QueryParam";
+
+ /**
+ * The annotation class name of @Body
+ */
+ String REST_EASY_BODY_ANNOTATION_CLASS_NAME = "org.jboss.resteasy.annotations.Body";
+
++ /**
++ * The annotation class name of @Form
++ */
++ String REST_EASY_FORM_BODY_ANNOTATION_CLASS_NAME = "org.jboss.resteasy.annotations.Form";
++
+ /**
+ * The annotation class name of @PathParam
+ */
+ String PATH_PARAM_ANNOTATION_CLASS_NAME = "javax.ws.rs.PathParam";
+ }
+
+ /**
+ * Spring MVC
+ */
+ interface SPRING_MVC {
+
+ /**
+ * The annotation class name of @Controller
+ */
+ String CONTROLLER_ANNOTATION_CLASS_NAME = "org.springframework.stereotype.Controller";
+
+ /**
+ * The annotation class name of @FeignClient
+ */
+ String FEIGN_CLIENT_CLASS_NAME = "org.springframework.cloud.openfeign.FeignClient";
+
+ /**
+ * The annotation class name of @RequestMapping
+ */
+ String REQUEST_MAPPING_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.RequestMapping";
+
+ /**
+ * The annotation class name of @RequestHeader
+ */
+ String REQUEST_HEADER_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.RequestHeader";
+
+ /**
+ * The annotation class name of @RequestParam
+ */
+ String REQUEST_PARAM_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.RequestParam";
+
+ /**
+ * The annotation class name of @RequestBody
+ */
+ String REQUEST_BODY_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.RequestBody";
+
+ /**
+ * The annotation class name of @PathVariable
+ */
+ String PATH_VARIABLE_ANNOTATION_CLASS_NAME = "org.springframework.web.bind.annotation.PathVariable";
+
+ /**
+ * The class of @Controller
+ *
+ * @since 2.7.9
+ */
+ Class<? extends Annotation> CONTROLLER_ANNOTATION_CLASS = (Class<? extends Annotation>) resolveClass(CONTROLLER_ANNOTATION_CLASS_NAME, getClassLoader());
+
+ /**
+ * The class of @RequestMapping
+ *
+ * @since 2.7.9
+ */
+ Class<? extends Annotation> REQUEST_MAPPING_ANNOTATION_CLASS = (Class<? extends Annotation>) resolveClass(REQUEST_MAPPING_ANNOTATION_CLASS_NAME, getClassLoader());
+
+ /**
+ * The annotation class name of AnnotatedElementUtils
+ *
+ * @since 2.7.9
+ */
+ String ANNOTATED_ELEMENT_UTILS_CLASS_NAME = "org.springframework.core.annotation.AnnotatedElementUtils";
+
+ /**
+ * The class of AnnotatedElementUtils
+ *
+ * @since 2.7.9
+ */
+ Class<?> ANNOTATED_ELEMENT_UTILS_CLASS = resolveClass(ANNOTATED_ELEMENT_UTILS_CLASS_NAME, getClassLoader());
+
+ Class<? extends Annotation> FEIGN_CLIENT_CLASS = (Class<? extends Annotation>) resolveClass(FEIGN_CLIENT_CLASS_NAME, getClassLoader());
+
+ }
+}
diff --cc dubbo-plugin/dubbo-plugin-generic-invoke/src/main/java/org/apache/dubbo/rpc/filter/GenericFilter.java
index 1d83f35aa3,0000000000..e9cb1cc816
mode 100644,000000..100644
--- a/dubbo-plugin/dubbo-plugin-generic-invoke/src/main/java/org/apache/dubbo/rpc/filter/GenericFilter.java
+++ b/dubbo-plugin/dubbo-plugin-generic-invoke/src/main/java/org/apache/dubbo/rpc/filter/GenericFilter.java
@@@ -1,348 -1,0 +1,357 @@@
+/*
+ * 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.dubbo.rpc.filter;
+
+import org.apache.dubbo.common.beanutil.JavaBeanAccessor;
+import org.apache.dubbo.common.beanutil.JavaBeanDescriptor;
+import org.apache.dubbo.common.beanutil.JavaBeanSerializeUtil;
++import org.apache.dubbo.common.compact.Dubbo2CompactUtils;
++import org.apache.dubbo.common.compact.Dubbo2GenericExceptionUtils;
+import org.apache.dubbo.common.config.Configuration;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.constants.LoggerCodeConstants;
+import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.io.UnsafeByteArrayInputStream;
+import org.apache.dubbo.common.io.UnsafeByteArrayOutputStream;
+import org.apache.dubbo.common.json.GsonUtils;
+import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.serialize.Serialization;
+import org.apache.dubbo.common.utils.ClassUtils;
+import org.apache.dubbo.common.utils.PojoUtils;
+import org.apache.dubbo.common.utils.ReflectUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.rpc.Filter;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.MethodDescriptor;
+import org.apache.dubbo.rpc.model.ScopeModelAware;
+import org.apache.dubbo.rpc.model.ServiceModel;
+import org.apache.dubbo.rpc.service.GenericException;
+import org.apache.dubbo.rpc.service.GenericService;
+import org.apache.dubbo.rpc.support.ProtocolUtils;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.IntStream;
+
+import static org.apache.dubbo.common.constants.CommonConstants.$INVOKE;
+import static org.apache.dubbo.common.constants.CommonConstants.$INVOKE_ASYNC;
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_BEAN;
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_NATIVE_JAVA;
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_PROTOBUF;
+import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FILTER_VALIDATION_EXCEPTION;
+import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
+
+/**
+ * GenericInvokerFilter.
+ */
+@Activate(group = CommonConstants.PROVIDER, order = -20000)
+public class GenericFilter implements Filter, Filter.Listener, ScopeModelAware {
+ private final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(GenericFilter.class);
+
+ private ApplicationModel applicationModel;
+
+ private final Map<ClassLoader, Map<String, Class<?>>> classCache = new ConcurrentHashMap<>();
+
+ @Override
+ public void setApplicationModel(ApplicationModel applicationModel) {
+ this.applicationModel = applicationModel;
+ }
+
+ @Override
+ public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
+ if ((inv.getMethodName().equals($INVOKE) || inv.getMethodName().equals($INVOKE_ASYNC))
+ && inv.getArguments() != null
+ && inv.getArguments().length == 3
+ && !GenericService.class.isAssignableFrom(invoker.getInterface())) {
+ String name = ((String) inv.getArguments()[0]).trim();
+ String[] types = (String[]) inv.getArguments()[1];
+ Object[] args = (Object[]) inv.getArguments()[2];
+ try {
+ Method method = findMethodByMethodSignature(invoker.getInterface(), name, types, inv.getServiceModel());
+ Class<?>[] params = method.getParameterTypes();
+ if (args == null) {
+ args = new Object[params.length];
+ }
+
+ if (types == null) {
+ types = new String[params.length];
+ }
+
+ if (args.length != types.length) {
+ throw new RpcException("GenericFilter#invoke args.length != types.length, please check your "
+ + "params");
+ }
+ String generic = inv.getAttachment(GENERIC_KEY);
+
+ if (StringUtils.isBlank(generic)) {
+ generic = getGenericValueFromRpcContext();
+ }
+
+ if (StringUtils.isEmpty(generic)
+ || ProtocolUtils.isDefaultGenericSerialization(generic)
+ || ProtocolUtils.isGenericReturnRawResult(generic)) {
+ try {
+ args = PojoUtils.realize(args, params, method.getGenericParameterTypes());
+ } catch (Exception e) {
+ logger.error(LoggerCodeConstants.PROTOCOL_ERROR_DESERIALIZE, "", "",
+ "Deserialize generic invocation failed. ServiceKey: " + inv.getTargetServiceUniqueName(), e);
+ throw new RpcException(e);
+ }
+ } else if (ProtocolUtils.isGsonGenericSerialization(generic)) {
+ args = getGsonGenericArgs(args, method.getGenericParameterTypes());
+ } else if (ProtocolUtils.isJavaGenericSerialization(generic)) {
+ Configuration configuration = ApplicationModel.ofNullable(applicationModel).modelEnvironment().getConfiguration();
+ if (!configuration.getBoolean(CommonConstants.ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE, false)) {
+ String notice = "Trigger the safety barrier! " +
+ "Native Java Serializer is not allowed by default." +
+ "This means currently maybe being attacking by others. " +
+ "If you are sure this is a mistake, " +
+ "please set `" + CommonConstants.ENABLE_NATIVE_JAVA_GENERIC_SERIALIZE + "` enable in configuration! " +
+ "Before doing so, please make sure you have configure JEP290 to prevent serialization attack.";
+ logger.error(CONFIG_FILTER_VALIDATION_EXCEPTION, "", "", notice);
+ throw new RpcException(new IllegalStateException(notice));
+ }
+
+ for (int i = 0; i < args.length; i++) {
+ if (byte[].class == args[i].getClass()) {
+ try (UnsafeByteArrayInputStream is = new UnsafeByteArrayInputStream((byte[]) args[i])) {
+ args[i] = applicationModel.getExtensionLoader(Serialization.class)
+ .getExtension(GENERIC_SERIALIZATION_NATIVE_JAVA)
+ .deserialize(null, is).readObject();
+ } catch (Exception e) {
+ throw new RpcException("Deserialize argument [" + (i + 1) + "] failed.", e);
+ }
+ } else {
+ throw new RpcException(
+ "Generic serialization [" +
+ GENERIC_SERIALIZATION_NATIVE_JAVA +
+ "] only support message type " +
+ byte[].class +
+ " and your message type is " +
+ args[i].getClass());
+ }
+ }
+ } else if (ProtocolUtils.isBeanGenericSerialization(generic)) {
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] != null) {
+ if (args[i] instanceof JavaBeanDescriptor) {
+ args[i] = JavaBeanSerializeUtil.deserialize((JavaBeanDescriptor) args[i]);
+ } else {
+ throw new RpcException(
+ "Generic serialization [" +
+ GENERIC_SERIALIZATION_BEAN +
+ "] only support message type " +
+ JavaBeanDescriptor.class.getName() +
+ " and your message type is " +
+ args[i].getClass().getName());
+ }
+ }
+ }
+ } else if (ProtocolUtils.isProtobufGenericSerialization(generic)) {
+ // as proto3 only accept one protobuf parameter
+ if (args.length == 1 && args[0] instanceof String) {
+ try (UnsafeByteArrayInputStream is =
+ new UnsafeByteArrayInputStream(((String) args[0]).getBytes())) {
+ args[0] = applicationModel.getExtensionLoader(Serialization.class)
+ .getExtension(GENERIC_SERIALIZATION_PROTOBUF)
+ .deserialize(null, is).readObject(method.getParameterTypes()[0]);
+ } catch (Exception e) {
+ throw new RpcException("Deserialize argument failed.", e);
+ }
+ } else {
+ throw new RpcException(
+ "Generic serialization [" +
+ GENERIC_SERIALIZATION_PROTOBUF +
+ "] only support one " + String.class.getName() +
+ " argument and your message size is " +
+ args.length + " and type is" +
+ args[0].getClass().getName());
+ }
+ }
+
+ RpcInvocation rpcInvocation = new RpcInvocation(inv.getTargetServiceUniqueName(),
+ invoker.getUrl().getServiceModel(), method.getName(), invoker.getInterface().getName(), invoker.getUrl().getProtocolServiceKey(),
+ method.getParameterTypes(), args, inv.getObjectAttachments(),
+ inv.getInvoker(), inv.getAttributes(), inv instanceof RpcInvocation ? ((RpcInvocation) inv).getInvokeMode() : null);
+
+ return invoker.invoke(rpcInvocation);
+ } catch (NoSuchMethodException | ClassNotFoundException e) {
+ throw new RpcException(e.getMessage(), e);
+ }
+ }
+ return invoker.invoke(inv);
+ }
+
+ private Object[] getGsonGenericArgs(final Object[] args, Type[] types) {
+ return IntStream.range(0, args.length).mapToObj(i -> {
+ if (args[i] == null) {
+ return null;
+ }
+ if (!(args[i] instanceof String)) {
+ throw new RpcException("When using GSON to deserialize generic dubbo request arguments, the arguments must be of type String");
+ }
+ String str = args[i].toString();
+ try {
+ return GsonUtils.fromJson(str, types[i]);
+ } catch (RuntimeException ex) {
+ throw new RpcException(ex.getMessage());
+ }
+ }).toArray();
+ }
+
+ private String getGenericValueFromRpcContext() {
+ String generic = RpcContext.getServerAttachment().getAttachment(GENERIC_KEY);
+ if (StringUtils.isBlank(generic)) {
+ generic = RpcContext.getClientAttachment().getAttachment(GENERIC_KEY);
+ }
+ return generic;
+ }
+
+ public Method findMethodByMethodSignature(Class<?> clazz, String methodName, String[] parameterTypes, ServiceModel serviceModel)
+ throws NoSuchMethodException, ClassNotFoundException {
+ Method method;
+ if (parameterTypes == null) {
+ List<Method> finded = new ArrayList<>();
+ for (Method m : clazz.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ finded.add(m);
+ }
+ }
+ if (finded.isEmpty()) {
+ throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz);
+ }
+ if (finded.size() > 1) {
+ String msg = String.format("Not unique method for method name(%s) in class(%s), find %d methods.",
+ methodName, clazz.getName(), finded.size());
+ throw new IllegalStateException(msg);
+ }
+ method = finded.get(0);
+ } else {
+ Class<?>[] types = new Class<?>[parameterTypes.length];
+ for (int i = 0; i < parameterTypes.length; i++) {
+ ClassLoader classLoader = ClassUtils.getClassLoader();
+ Map<String, Class<?>> cacheMap = classCache.get(classLoader);
+ if (cacheMap == null) {
+ cacheMap = new ConcurrentHashMap<>();
+ classCache.putIfAbsent(classLoader, cacheMap);
+ cacheMap = classCache.get(classLoader);
+ }
+ types[i] = cacheMap.get(parameterTypes[i]);
+ if (types[i] == null) {
+ types[i] = ReflectUtils.name2class(parameterTypes[i]);
+ cacheMap.put(parameterTypes[i], types[i]);
+ }
+ }
+ if (serviceModel != null) {
+ MethodDescriptor methodDescriptor = serviceModel.getServiceModel().getMethod(methodName, types);
+ if (methodDescriptor == null) {
+ throw new NoSuchMethodException("No such method " + methodName + " in class " + clazz);
+ }
+ method = methodDescriptor.getMethod();
+ } else {
+ method = clazz.getMethod(methodName, types);
+ }
+ }
+ return method;
+ }
+
+ @Override
+ public void onResponse(Result appResponse, Invoker<?> invoker, Invocation inv) {
+ if ((inv.getMethodName().equals($INVOKE) || inv.getMethodName().equals($INVOKE_ASYNC))
+ && inv.getArguments() != null
+ && inv.getArguments().length == 3
+ && !GenericService.class.isAssignableFrom(invoker.getInterface())) {
+
+ String generic = inv.getAttachment(GENERIC_KEY);
+ if (StringUtils.isBlank(generic)) {
+ generic = getGenericValueFromRpcContext();
+ }
+
- if (appResponse.hasException()) {
++ if (appResponse.hasException() &&
++ Dubbo2CompactUtils.isEnabled() && Dubbo2GenericExceptionUtils.isGenericExceptionClassLoaded()) {
+ Throwable appException = appResponse.getException();
+ if (appException instanceof GenericException) {
+ GenericException tmp = (GenericException) appException;
- appException = new com.alibaba.dubbo.rpc.service.GenericException(tmp.getMessage(), tmp.getCause(),
++ GenericException recreated = Dubbo2GenericExceptionUtils.newGenericException(tmp.getMessage(), tmp.getCause(),
+ tmp.getExceptionClass(), tmp.getExceptionMessage());
++ if (recreated != null) {
++ appException = recreated;
++ }
+ appException.setStackTrace(tmp.getStackTrace());
+ }
- if (!(appException instanceof com.alibaba.dubbo.rpc.service.GenericException)) {
- appException = new com.alibaba.dubbo.rpc.service.GenericException(appException);
++ if (!(Dubbo2GenericExceptionUtils.getGenericExceptionClass().isAssignableFrom(appException.getClass()))) {
++ GenericException recreated = Dubbo2GenericExceptionUtils.newGenericException(appException);
++ if (recreated != null) {
++ appException = recreated;
++ }
+ }
+ appResponse.setException(appException);
+ }
+ if (ProtocolUtils.isGenericReturnRawResult(generic)) {
+ return;
+ }
+ if (ProtocolUtils.isJavaGenericSerialization(generic)) {
+ try {
+ UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(512);
+ applicationModel.getExtensionLoader(Serialization.class).getExtension(GENERIC_SERIALIZATION_NATIVE_JAVA)
+ .serialize(null, os).writeObject(appResponse.getValue());
+ appResponse.setValue(os.toByteArray());
+ } catch (IOException e) {
+ throw new RpcException(
+ "Generic serialization [" +
+ GENERIC_SERIALIZATION_NATIVE_JAVA +
+ "] serialize result failed.", e);
+ }
+ } else if (ProtocolUtils.isBeanGenericSerialization(generic)) {
+ appResponse.setValue(JavaBeanSerializeUtil.serialize(appResponse.getValue(), JavaBeanAccessor.METHOD));
+ } else if (ProtocolUtils.isProtobufGenericSerialization(generic)) {
+ try {
+ UnsafeByteArrayOutputStream os = new UnsafeByteArrayOutputStream(512);
+ applicationModel.getExtensionLoader(Serialization.class)
+ .getExtension(GENERIC_SERIALIZATION_PROTOBUF)
+ .serialize(null, os).writeObject(appResponse.getValue());
+ appResponse.setValue(os.toString());
+ } catch (IOException e) {
+ throw new RpcException("Generic serialization [" +
+ GENERIC_SERIALIZATION_PROTOBUF +
+ "] serialize result failed.", e);
+ }
+ } else if (ProtocolUtils.isGsonGenericSerialization(generic)) {
+ appResponse.setValue(GsonUtils.toJson(appResponse.getValue()));
+ } else {
+ appResponse.setValue(PojoUtils.generalize(appResponse.getValue()));
+ }
+ }
+ }
+
+ @Override
+ public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
+
+ }
+}
diff --cc dubbo-spring-boot/pom.xml
index 5f8f83c774,1f20850f19..3e4344ec2e
--- a/dubbo-spring-boot/pom.xml
+++ b/dubbo-spring-boot/pom.xml
@@@ -41,11 -40,12 +41,11 @@@
</modules>
<properties>
- <spring-boot.version>2.7.16</spring-boot.version>
+ <spring-boot.version>2.7.17</spring-boot.version>
- <dubbo.version>${revision}</dubbo.version>
- <!-- Fix the bug of log4j refer:https://github.com/apache/logging-log4j2/pull/608 -->
- <log4j2_version>2.20.0</log4j2_version>
<!-- Spring boot buddy is lower than the delivery dependency package version and can only show the defined dependency version -->
<byte-buddy.version>1.14.9</byte-buddy.version>
+ <slf4j-log4j12_version>1.7.33</slf4j-log4j12_version>
+ <mockito_version>4.11.0</mockito_version>
</properties>
<dependencyManagement>