From c7f0b9abb37461ac73fc057b8dabea052c859a46 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Fri, 1 Nov 2024 21:42:52 +0800 Subject: [PATCH 01/23] Initial version of openapi --- .../apache/dubbo/config/AbstractConfig.java | 6 + .../dubbo/config/nested/OpenAPIConfig.java | 267 +++++++++ .../dubbo/config/nested/RestConfig.java | 32 + dubbo-distribution/dubbo-all-shaded/pom.xml | 1 + dubbo-distribution/dubbo-all/pom.xml | 1 + dubbo-distribution/dubbo-bom/pom.xml | 5 + .../dubbo/metadata/MetadataService.java | 10 + .../dubbo/metadata/MetadataServiceV2.java | 3 + dubbo-plugin/dubbo-rest-swagger/pom.xml | 71 +++ .../metadata/MetadataServiceDelegation.java | 19 +- .../remoting/http12/message/MediaType.java | 2 + .../dubbo/remoting/http12/rest/OpenAPI.java | 82 +++ .../dubbo/remoting/http12/rest/Operation.java | 71 +++ .../tri/rest/mapping/ContentNegotiator.java | 2 +- .../DefaultRequestMappingRegistry.java | 73 +-- .../protocol/tri/rest/mapping/RadixTree.java | 24 + .../tri/rest/mapping/Registration.java | 59 ++ .../tri/rest/mapping/RequestMapping.java | 16 + .../rest/mapping/RequestMappingRegistry.java | 4 + .../mapping/condition/ConsumesCondition.java | 5 + .../condition/MediaTypeExpression.java | 11 + .../mapping/condition/ProducesCondition.java | 9 +- .../tri/rest/openapi/AnnotationResolver.java | 32 + .../rest/openapi/DefaultOpenAPIService.java | 244 ++++++++ .../tri/rest/openapi/FilterContext.java | 19 + .../rpc/protocol/tri/rest/openapi/Helper.java | 36 ++ .../tri/rest/openapi/OpenAPIExtension.java | 29 + .../tri/rest/openapi/OpenAPIFilter.java | 79 +++ .../tri/rest/openapi/OpenAPIRequest.java | 87 +++ .../tri/rest/openapi/OpenAPIService.java | 30 + .../tri/rest/openapi/ProtoEncoder.java | 40 ++ .../tri/rest/openapi/ResolveContext.java | 42 ++ .../tri/rest/openapi/SchemaFactory.java | 26 + .../tri/rest/openapi/WriteContext.java | 19 + .../tri/rest/openapi/model/ApiResponse.java | 111 ++++ .../tri/rest/openapi/model/Components.java | 92 +++ .../tri/rest/openapi/model/Contact.java | 64 ++ .../tri/rest/openapi/model/Discriminator.java | 78 +++ .../tri/rest/openapi/model/Encoding.java | 127 ++++ .../tri/rest/openapi/model/Example.java | 75 +++ .../tri/rest/openapi/model/ExternalDocs.java | 53 ++ .../tri/rest/openapi/model/Header.java | 191 ++++++ .../protocol/tri/rest/openapi/model/Info.java | 116 ++++ .../tri/rest/openapi/model/License.java | 53 ++ .../tri/rest/openapi/model/MediaType.java | 115 ++++ .../protocol/tri/rest/openapi/model/Node.java | 164 +++++ .../tri/rest/openapi/model/OAuthFlow.java | 99 +++ .../tri/rest/openapi/model/OAuthFlows.java | 85 +++ .../tri/rest/openapi/model/OpenAPI.java | 216 +++++++ .../tri/rest/openapi/model/Operation.java | 277 +++++++++ .../tri/rest/openapi/model/Parameter.java | 265 ++++++++ .../tri/rest/openapi/model/PathItem.java | 161 +++++ .../tri/rest/openapi/model/RequestBody.java | 86 +++ .../tri/rest/openapi/model/Schema.java | 567 ++++++++++++++++++ .../openapi/model/SecurityRequirement.java | 80 +++ .../rest/openapi/model/SecurityScheme.java | 161 +++++ .../tri/rest/openapi/model/Server.java | 87 +++ .../rest/openapi/model/ServerVariable.java | 90 +++ .../protocol/tri/rest/openapi/model/Tag.java | 71 +++ .../protocol/tri/rest/openapi/model/XML.java | 82 +++ .../rpc/protocol/tri/rest/util/PathUtils.java | 3 + .../dubbo-spring-boot-autoconfigure/pom.xml | 6 + dubbo-test/dubbo-dependencies-all/pom.xml | 5 + 63 files changed, 4986 insertions(+), 50 deletions(-) create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java create mode 100644 dubbo-plugin/dubbo-rest-swagger/pom.xml create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/Registration.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AnnotationResolver.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/FilterContext.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequest.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/WriteContext.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java index bc709a35413..35da43e059e 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java @@ -795,6 +795,12 @@ private void assignProperties( List methods = MethodUtils.getMethods(obj.getClass(), method -> method.getDeclaringClass() != Object.class); for (Method method : methods) { + // filter non attribute + Parameter parameter = method.getAnnotation(Parameter.class); + if (parameter != null && !parameter.attribute()) { + continue; + } + if (isPropertySetter(method)) { String propertyName = extractPropertyName(method.getName()); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java new file mode 100644 index 00000000000..3267c661566 --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -0,0 +1,267 @@ +/* + * 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.config.nested; + +import java.io.Serializable; +import java.util.Map; + +public class OpenAPIConfig implements Serializable { + + private static final long serialVersionUID = 6943417456345001947L; + + /** + * Whether to enable OpenAPI support + *

The default value is 'true'. + */ + private Boolean enabled; + + /** + * The HTTP path where OpenAPI will be registered. + *

The default value is 'api-docs'. + */ + private String path; + + /** + * The version of OpenAPI being used. + * e.g. 3.0.1, 3.1.0 + *

The default value is '3.0.1'. + */ + private String version; + + /** + * The title of the OpenAPI information. + */ + private String infoTitle; + + /** + * A brief description of the OpenAPI information. + */ + private String infoDescription; + + /** + * The version number of the OpenAPI information. + */ + private String infoVersion; + + /** + * The name of the contact. + */ + private String infoContactName; + + /** + * The email address of the contact. + */ + private String infoContactEmail; + + /** + * A description of the external documentation. + */ + private String externalDocsDescription; + + /** + * The URL of the external documentation. + */ + private String externalDocsUrl; + + /** + * A list of servers. + */ + private String[] servers; + + /** + * The security scheme. + */ + private String securityScheme; + + /** + * The strategy used to generate operation id. + */ + private String operationIdStrategy; + + /** + * The strategy used to generate schema name. + */ + private String schemaNameStrategy; + + /** + * The default media types that are consumed. + */ + private String[] defaultConsumesMediaType; + + /** + * The default media types that are produced. + */ + private String[] defaultProducesMediaType; + + /** + * The default HTTP status codes are returned. + */ + private String[] defaultHttpStatusCode; + + /** + * The custom settings. + */ + private Map settings; + + public String getExternalDocsUrl() { + return externalDocsUrl; + } + + public void setExternalDocsUrl(String externalDocsUrl) { + this.externalDocsUrl = externalDocsUrl; + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getInfoTitle() { + return infoTitle; + } + + public void setInfoTitle(String infoTitle) { + this.infoTitle = infoTitle; + } + + public String getInfoDescription() { + return infoDescription; + } + + public void setInfoDescription(String infoDescription) { + this.infoDescription = infoDescription; + } + + public String getInfoVersion() { + return infoVersion; + } + + public void setInfoVersion(String infoVersion) { + this.infoVersion = infoVersion; + } + + public String getInfoContactName() { + return infoContactName; + } + + public void setInfoContactName(String infoContactName) { + this.infoContactName = infoContactName; + } + + public String getInfoContactEmail() { + return infoContactEmail; + } + + public void setInfoContactEmail(String infoContactEmail) { + this.infoContactEmail = infoContactEmail; + } + + public String getExternalDocsDescription() { + return externalDocsDescription; + } + + public void setExternalDocsDescription(String externalDocsDescription) { + this.externalDocsDescription = externalDocsDescription; + } + + public String[] getServers() { + return servers; + } + + public void setServers(String[] servers) { + this.servers = servers; + } + + public String getSecurityScheme() { + return securityScheme; + } + + public void setSecurityScheme(String securityScheme) { + this.securityScheme = securityScheme; + } + + public String getOperationIdStrategy() { + return operationIdStrategy; + } + + public void setOperationIdStrategy(String operationIdStrategy) { + this.operationIdStrategy = operationIdStrategy; + } + + public String getSchemaNameStrategy() { + return schemaNameStrategy; + } + + public void setSchemaNameStrategy(String schemaNameStrategy) { + this.schemaNameStrategy = schemaNameStrategy; + } + + public String[] getDefaultConsumesMediaType() { + return defaultConsumesMediaType; + } + + public void setDefaultConsumesMediaType(String[] defaultConsumesMediaType) { + this.defaultConsumesMediaType = defaultConsumesMediaType; + } + + public String[] getDefaultProducesMediaType() { + return defaultProducesMediaType; + } + + public void setDefaultProducesMediaType(String[] defaultProducesMediaType) { + this.defaultProducesMediaType = defaultProducesMediaType; + } + + public String[] getDefaultHttpStatusCode() { + return defaultHttpStatusCode; + } + + public void setDefaultHttpStatusCode(String[] defaultHttpStatusCode) { + this.defaultHttpStatusCode = defaultHttpStatusCode; + } + + public Map getSettings() { + return settings; + } + + public void setSettings(Map settings) { + this.settings = settings; + } + + public String getSetting(String key) { + return settings == null ? null : settings.get(key); + } +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java index be813c68e59..8f64a3d0157 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java @@ -20,6 +20,7 @@ import org.apache.dubbo.config.support.Parameter; import java.io.Serializable; +import java.util.Map; /** * Configuration for triple rest protocol. @@ -78,6 +79,17 @@ public class RestConfig implements Serializable { @Nested private CorsConfig cors; + /** + * The openapi configuration. + */ + @Nested + private OpenAPIConfig openapi; + + /** + * Multiple configurations for openapi. + */ + private Map openapis; + public Boolean getTrailingSlashMatch() { return trailingSlashMatch; } @@ -161,4 +173,24 @@ public CorsConfig getCorsOrDefault() { public void setCors(CorsConfig cors) { this.cors = cors; } + + @Parameter(excluded = true) + public OpenAPIConfig getOpenapi() { + return openapi; + } + + @Parameter(attribute = false) + public void setOpenapi(OpenAPIConfig openapi) { + this.openapi = openapi; + } + + @Parameter(excluded = true) + public Map getOpenapis() { + return openapis; + } + + @Parameter(attribute = false) + public void setOpenapis(Map openapis) { + this.openapis = openapis; + } } diff --git a/dubbo-distribution/dubbo-all-shaded/pom.xml b/dubbo-distribution/dubbo-all-shaded/pom.xml index 6066525a2a9..c38df014a28 100644 --- a/dubbo-distribution/dubbo-all-shaded/pom.xml +++ b/dubbo-distribution/dubbo-all-shaded/pom.xml @@ -524,6 +524,7 @@ org.apache.dubbo:dubbo-rpc-triple org.apache.dubbo:dubbo-rest-jaxrs org.apache.dubbo:dubbo-rest-spring + org.apache.dubbo:dubbo-rest-swagger org.apache.dubbo:dubbo-triple-servlet org.apache.dubbo:dubbo-triple-websocket org.apache.dubbo:dubbo-serialization-api diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml index 7d6b9f81c37..ea3b05d3f47 100644 --- a/dubbo-distribution/dubbo-all/pom.xml +++ b/dubbo-distribution/dubbo-all/pom.xml @@ -523,6 +523,7 @@ org.apache.dubbo:dubbo-rpc-triple org.apache.dubbo:dubbo-rest-jaxrs org.apache.dubbo:dubbo-rest-spring + org.apache.dubbo:dubbo-rest-swagger org.apache.dubbo:dubbo-triple-servlet org.apache.dubbo:dubbo-triple-websocket org.apache.dubbo:dubbo-serialization-api diff --git a/dubbo-distribution/dubbo-bom/pom.xml b/dubbo-distribution/dubbo-bom/pom.xml index ea2c7712c1f..5003a7c7d45 100644 --- a/dubbo-distribution/dubbo-bom/pom.xml +++ b/dubbo-distribution/dubbo-bom/pom.xml @@ -301,6 +301,11 @@ dubbo-rest-spring ${project.version} + + org.apache.dubbo + dubbo-rest-swagger + ${project.version} + org.apache.dubbo dubbo-triple-servlet diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java index cd767adcad9..eec8bcd7c7b 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java @@ -17,6 +17,9 @@ package org.apache.dubbo.metadata; import org.apache.dubbo.common.URL; +import org.apache.dubbo.remoting.http12.rest.Mapping; +import org.apache.dubbo.remoting.http12.rest.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequest; import java.util.Collections; import java.util.List; @@ -36,6 +39,7 @@ * 1. The Consumer queries the metadata information of the Provider to list the interfaces and each interface's configuration * 2. The Console (dubbo-admin) queries for the metadata of a specific process, or aggregate data of all processes. */ +@OpenAPI(hidden = true) public interface MetadataService { /** @@ -226,4 +230,10 @@ static boolean isMetadataService(String interfaceName) { * @since 3.0 */ String getAndListenInstanceMetadata(String consumerId, InstanceMetadataChangedListener listener); + + /** + * 1. Get the openAPI definition + */ + @Mapping({"getOpenAPI", "//_meta/openapi"}) + String getOpenAPI(OpenAPIRequest request); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java index d85df91a140..79ad7e1cc4b 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java @@ -16,8 +16,11 @@ */ package org.apache.dubbo.metadata; +import org.apache.dubbo.remoting.http12.rest.OpenAPI; + import java.util.concurrent.CompletableFuture; +@OpenAPI(hidden = true) public interface MetadataServiceV2 extends org.apache.dubbo.rpc.model.DubboStub { String JAVA_SERVICE_NAME = "org.apache.dubbo.metadata.MetadataServiceV2"; diff --git a/dubbo-plugin/dubbo-rest-swagger/pom.xml b/dubbo-plugin/dubbo-rest-swagger/pom.xml new file mode 100644 index 00000000000..62815d348c6 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-swagger/pom.xml @@ -0,0 +1,71 @@ + + + + 4.0.0 + + org.apache.dubbo + dubbo-plugin + ${revision} + ../pom.xml + + + dubbo-rest-swagger + + + + org.apache.dubbo + dubbo-rpc-triple + ${project.version} + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.6.0 + provided + + + io.quarkus + quarkus-smallrye-openapi-deployment + 3.16.0 + provided + + + + org.spockframework + spock-core + test + + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + + + + compileTests + + + + + + + diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java index 55041f96e88..741a3a5f100 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java @@ -26,7 +26,11 @@ import org.apache.dubbo.metadata.MetadataService; import org.apache.dubbo.registry.client.ServiceDiscovery; import org.apache.dubbo.registry.support.RegistryManager; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequest; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIService; import java.util.ArrayList; import java.util.Comparator; @@ -55,7 +59,8 @@ public class MetadataServiceDelegation implements MetadataService, Disposable { private final ApplicationModel applicationModel; private final RegistryManager registryManager; - private ConcurrentMap instanceMetadataChangedListenerMap = + private final OpenAPIService openAPIService; + private final ConcurrentMap instanceMetadataChangedListenerMap = new ConcurrentHashMap<>(); private URL url; // works only for DNS service discovery @@ -66,6 +71,10 @@ public class MetadataServiceDelegation implements MetadataService, Disposable { public MetadataServiceDelegation(ApplicationModel applicationModel) { this.applicationModel = applicationModel; registryManager = RegistryManager.getInstance(applicationModel); + openAPIService = applicationModel.getFrameworkModel().getBeanFactory().getBean(OpenAPIService.class); + if (openAPIService != null) { + openAPIService.export(); + } } /** @@ -214,6 +223,14 @@ public String getAndListenInstanceMetadata(String consumerId, InstanceMetadataCh return instanceMetadata; } + @Override + public String getOpenAPI(OpenAPIRequest request) { + if (openAPIService == null) { + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode(), "OpenAPI is not available"); + } + return openAPIService.getDocument(request); + } + private SortedSet getServiceURLs( Map> exportedServiceURLs, String serviceKey, String protocol) { diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java index 84f71ce6815..a43b1e4891e 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java @@ -30,6 +30,8 @@ public final class MediaType { public static final MediaType APPLICATION_YAML = new MediaType("application", "yaml"); + public static final MediaType TEXT_PROTO = new MediaType("text", "proto"); + public static final MediaType APPLICATION_JAVASCRIPT = new MediaType("application", "javascript"); public static final MediaType APPLICATION_OCTET_STREAM = new MediaType("application", "octet-stream"); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java new file mode 100644 index 00000000000..17ea2490540 --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java @@ -0,0 +1,82 @@ +/* + * 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.remoting.http12.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for defining OpenAPI on Dubbo service interface. + * Provide metadata such as tags, groups, title, description, version, hidden, and order. + * + *

Example usage:

+ *
+ * @OpenAPI(tags = {"user=User API"}, title = "User Service", description = "User Service API", version = "1.0.0")
+ * public interface UserService {
+ *     ...
+ * }
+ * 
+ */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface OpenAPI { + + /** + * The openAPI tags. + *
Supported Syntax
+ * + * e.g. user=User API + */ + String[] tags() default {}; + + /** + * The openAPI groups. + */ + String[] groups() default {}; + + /** + * The title of the application. + **/ + String title() default ""; + + /** + * A short description of the application. + **/ + String description() default ""; + + /** + * The version of the API definition. + **/ + String version() default ""; + + /** + * Indicates whether the mapping is hidden in OpenAPI. + */ + boolean hidden() default false; + + /** + * Ordering info. + */ + int order() default 0; +} diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java new file mode 100644 index 00000000000..3cac2b11dba --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java @@ -0,0 +1,71 @@ +/* + * 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.remoting.http12.rest; + +import org.apache.dubbo.remoting.http12.HttpMethods; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Operation { + + /** + * The HTTP method for this operation. + */ + HttpMethods[] method() default {}; + + /** + * The operation tags. + */ + String[] tags() default {}; + + /** + * The operation group. + */ + String group() default ""; + + /** + * The ID of this operation. + **/ + String operationId() default ""; + + /** + * A brief description of this operation. Should be 120 characters or fewer. + */ + String summary() default ""; + + /** + * A verbose description of the operation. + */ + String description() default ""; + + /** + * Whether this operation is deprecated + */ + boolean deprecated() default false; + + /** + * Indicates whether the operation is hidden in OpenAPI. + */ + boolean hidden() default false; +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java index 713d695e5e6..e0f53c91eba 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java @@ -171,7 +171,7 @@ private String getMediaTypeByExtension(String extension) { extensionMapping.put("xhtml", MediaType.TEXT_HTML); extensionMapping.put("html", MediaType.TEXT_HTML); extensionMapping.put("htm", MediaType.TEXT_HTML); - for (String ext : new String[] {"txt", "md", "csv", "log", "properties"}) { + for (String ext : new String[] {"txt", "md", "csv", "log", "properties", "proto"}) { extensionMapping.put(ext, MediaType.TEXT_PLAIN); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java index c544efce29f..ba570a5f174 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java @@ -40,12 +40,15 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPIService; import org.apache.dubbo.rpc.protocol.tri.rest.util.KeyString; import org.apache.dubbo.rpc.protocol.tri.rest.util.MethodWalker; import org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collection; +import java.util.IdentityHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -59,24 +62,25 @@ public final class DefaultRequestMappingRegistry implements RequestMappingRegist private static final FluentLogger LOGGER = FluentLogger.of(DefaultRequestMappingRegistry.class); private final FrameworkModel frameworkModel; - private final ContentNegotiator contentNegotiator; private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final AtomicBoolean initialized = new AtomicBoolean(); - private RestConfig restConfig; + private ContentNegotiator contentNegotiator; + private DefaultOpenAPIService openAPIService; private List resolvers; + private RestConfig restConfig; private RadixTree tree; public DefaultRequestMappingRegistry(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; - contentNegotiator = frameworkModel.getBeanFactory().getOrRegisterBean(ContentNegotiator.class); } private void init(Invoker invoker) { - restConfig = ConfigManager.getProtocolOrDefault(invoker.getUrl()) - .getTripleOrDefault() - .getRestOrDefault(); + contentNegotiator = frameworkModel.getBeanFactory().getOrRegisterBean(ContentNegotiator.class); + openAPIService = frameworkModel.getBeanFactory().getOrRegisterBean(DefaultOpenAPIService.class); + openAPIService.setRequestMappingRegistry(this); resolvers = frameworkModel.getActivateExtensions(RequestMappingResolver.class); + restConfig = ConfigManager.getProtocolOrDefault(invoker.getUrl()).getTripleOrDefault().getRestOrDefault(); tree = new RadixTree<>(restConfig.getCaseSensitiveMatchOrDefault()); } @@ -144,6 +148,7 @@ public void register(Invoker invoker) { }); } }); + onMappingChanged(); LOGGER.info( "Registered {} rest mappings for service [{}] at url [{}] in {}ms", counter, @@ -155,17 +160,15 @@ public void register(Invoker invoker) { private void register0(RequestMapping mapping, HandlerMeta handler, AtomicInteger counter) { lock.writeLock().lock(); try { - Registration registration = new Registration(); - registration.mapping = mapping; - registration.meta = handler; + Registration registration = new Registration(mapping, handler); for (PathExpression path : mapping.getPathCondition().getExpressions()) { Registration exists = tree.addPath(path, registration); if (exists == null) { + counter.incrementAndGet(); if (LOGGER.isDebugEnabled()) { String msg = "Register rest mapping: '{}' -> mapping={}, method={}"; LOGGER.debug(msg, path, mapping, handler.getMethod()); } - counter.incrementAndGet(); } else if (LOGGER.isWarnEnabled()) { LOGGER.internalWarn(Messages.DUPLICATE_MAPPING.format(path, mapping, handler.getMethod(), exists)); } @@ -183,7 +186,8 @@ public void unregister(Invoker invoker) { lock.writeLock().lock(); try { - tree.remove(mapping -> mapping.meta.getInvoker() == invoker); + tree.remove(r -> r.getMeta().getInvoker() == invoker); + onMappingChanged(); } finally { lock.writeLock().unlock(); } @@ -316,11 +320,11 @@ private void tryMatch( } for (int i = 0; i < size; i++) { Match match = matches.get(i); - RequestMapping mapping = match.getValue().mapping.match(request, match.getExpression()); + RequestMapping mapping = match.getValue().getMapping().match(request, match.getExpression()); if (mapping != null) { Candidate candidate = new Candidate(); candidate.mapping = mapping; - candidate.meta = match.getValue().meta; + candidate.meta = match.getValue().getMeta(); candidate.expression = match.getExpression(); candidate.variableMap = match.getVariableMap(); candidates.add(candidate); @@ -328,7 +332,7 @@ private void tryMatch( } if (candidates.isEmpty()) { for (int i = 0; i < size; i++) { - partialMatches.add(matches.get(i).getValue().mapping); + partialMatches.add(matches.get(i).getValue().getMapping()); } } } @@ -411,6 +415,18 @@ public boolean exists(String stringPath, String method) { return false; } + @Override + public Collection getRegistrations() { + lock.readLock().lock(); + try { + Map registrations = new IdentityHashMap<>(); + tree.walk((expr, registration) -> registrations.put(registration, Boolean.TRUE)); + return registrations.keySet(); + } finally { + lock.readLock().unlock(); + } + } + private boolean tryExists(KeyString path, String method) { List> matches = new ArrayList<>(); lock.readLock().lock(); @@ -420,38 +436,15 @@ private boolean tryExists(KeyString path, String method) { lock.readLock().unlock(); } for (int i = 0, size = matches.size(); i < size; i++) { - if (matches.get(i).getValue().mapping.matchMethod(method)) { + if (matches.get(i).getValue().getMapping().matchMethod(method)) { return true; } } return false; } - private static final class Registration { - - RequestMapping mapping; - HandlerMeta meta; - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null || obj.getClass() != Registration.class) { - return false; - } - return mapping.equals(((Registration) obj).mapping); - } - - @Override - public int hashCode() { - return mapping.hashCode(); - } - - @Override - public String toString() { - return "Registration{mapping=" + mapping + ", method=" + meta.getMethod() + '}'; - } + private void onMappingChanged() { + openAPIService.refresh(); } private static final class Candidate { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java index 1c570559869..d6242e6117a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.function.BiConsumer; import java.util.function.Predicate; /** @@ -136,6 +137,29 @@ private void removeRecursive(Node current, Predicate tester) { } } + public void walk(BiConsumer consumer) { + for (List> matches : directPathMap.values()) { + for (Match match : matches) { + consumer.accept(match.getExpression(), match.getValue()); + } + } + walkRecursive(root, consumer); + } + + private void walkRecursive(Node root, BiConsumer consumer) { + for (Pair pair : root.values) { + consumer.accept(pair.getLeft(), pair.getRight()); + } + + for (Node node : root.children.values()) { + walkRecursive(node, consumer); + } + + for (Node node : root.fuzzyChildren.values()) { + walkRecursive(node, consumer); + } + } + /** * Ensure that the path is normalized using {@link PathUtils#normalize(String)} before matching. */ diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/Registration.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/Registration.java new file mode 100644 index 00000000000..f5c993a4542 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/Registration.java @@ -0,0 +1,59 @@ +/* + * 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.protocol.tri.rest.mapping; + +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; + +public final class Registration { + + private final RequestMapping mapping; + private final HandlerMeta meta; + + public Registration(RequestMapping mapping, HandlerMeta meta) { + this.mapping = mapping; + this.meta = meta; + } + + public RequestMapping getMapping() { + return mapping; + } + + public HandlerMeta getMeta() { + return meta; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || obj.getClass() != Registration.class) { + return false; + } + return mapping.equals(((Registration) obj).mapping); + } + + @Override + public int hashCode() { + return mapping.hashCode(); + } + + @Override + public String toString() { + return "Registration{mapping=" + mapping + ", method=" + meta.getMethod() + '}'; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java index a8a829d02db..feef0738e84 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMapping.java @@ -208,6 +208,10 @@ public String getName() { return name; } + public String getSig() { + return sig; + } + public PathCondition getPathCondition() { return pathCondition; } @@ -216,6 +220,18 @@ public MethodsCondition getMethodsCondition() { return methodsCondition; } + public ParamsCondition getParamsCondition() { + return paramsCondition; + } + + public HeadersCondition getHeadersCondition() { + return headersCondition; + } + + public ConsumesCondition getConsumesCondition() { + return consumesCondition; + } + public ProducesCondition getProducesCondition() { return producesCondition; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java index 444854c5e78..b27036b1686 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingRegistry.java @@ -20,6 +20,8 @@ import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; +import java.util.Collection; + /** * RequestMappingRegistry used for registering and unregistering rest request mappings. */ @@ -33,5 +35,7 @@ public interface RequestMappingRegistry { boolean exists(String path, String method); + Collection getRegistrations(); + void destroy(); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java index 181d4c4a1c6..a19030db7fd 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ConsumesCondition.java @@ -18,6 +18,7 @@ import org.apache.dubbo.remoting.http12.HttpHeaderNames; import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.message.MediaType; import java.util.ArrayList; import java.util.Collections; @@ -113,6 +114,10 @@ public int compareTo(ConsumesCondition other, HttpRequest request) { return expressions.get(0).compareTo(other.expressions.get(0)); } + public List getMediaTypes() { + return MediaTypeExpression.toMediaTypes(expressions); + } + @Override public int hashCode() { return expressions.hashCode(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MediaTypeExpression.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MediaTypeExpression.java index 9edb4c71cb2..f4661295a08 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MediaTypeExpression.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/MediaTypeExpression.java @@ -20,6 +20,7 @@ import org.apache.dubbo.remoting.http12.HttpUtils; import org.apache.dubbo.remoting.http12.message.MediaType; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -66,6 +67,16 @@ public MediaTypeExpression(String type, String subType) { negated = false; } + public static List toMediaTypes(List expressions) { + int size = expressions.size(); + List mediaTypes = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + MediaTypeExpression expr = expressions.get(i); + mediaTypes.add(new MediaType(expr.getType(), expr.getSubType())); + } + return mediaTypes; + } + public static MediaTypeExpression parse(String expr) { boolean negated; if (expr.indexOf('!') == 0) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java index 0f336d1405f..f0f5aed4b3a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/ProducesCondition.java @@ -164,14 +164,7 @@ public int compareTo(ProducesCondition other, HttpRequest request) { } public List getMediaTypes() { - List expressions = this.expressions; - int size = expressions.size(); - List mediaTypes = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - MediaTypeExpression expr = expressions.get(i); - mediaTypes.add(new MediaType(expr.getType(), expr.getSubType())); - } - return mediaTypes; + return MediaTypeExpression.toMediaTypes(expressions); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AnnotationResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AnnotationResolver.java new file mode 100644 index 00000000000..e6a0073e1a7 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AnnotationResolver.java @@ -0,0 +1,32 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.extension.ExtensionScope; +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; + +@SPI(scope = ExtensionScope.FRAMEWORK) +public interface AnnotationResolver { + + OpenAPI resolve(ServiceMeta serviceMeta); + + Operation resolve(MethodMeta methodMeta, Operation operation, ResolveContext context); +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java new file mode 100644 index 00000000000..fde71c26927 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -0,0 +1,244 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.resource.Disposable; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException; +import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; +import org.apache.dubbo.remoting.http12.message.codec.JsonCodec; +import org.apache.dubbo.remoting.http12.message.codec.YamlCodec; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.Registration; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingRegistry; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.*; + +import java.io.ByteArrayOutputStream; +import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.Map.Entry; + +public class DefaultOpenAPIService implements OpenAPIService, Disposable { + + private final List annotationResolvers; + private final List extensions; + private final SchemaFactory schemaFactory = new SchemaFactory(); + private final Map, List> extensionsCache = CollectionUtils.newConcurrentHashMap(); + + private Map, OpenAPI> openAPIMap; + private RequestMappingRegistry requestMappingRegistry; + + public DefaultOpenAPIService(FrameworkModel frameworkModel) { + annotationResolvers = frameworkModel.getActivateExtensions(AnnotationResolver.class); + extensions = frameworkModel.getActivateExtensions(OpenAPIExtension.class); + } + + public void setRequestMappingRegistry(RequestMappingRegistry requestMappingRegistry) { + this.requestMappingRegistry = requestMappingRegistry; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private List getExtensions(Class clazz) { + return (List) extensionsCache.computeIfAbsent(clazz, k -> { + List list = new ArrayList<>(); + for (OpenAPIExtension extension : extensions) { + if (clazz.isInstance(extension)) { + list.add(extension); + } + } + return list; + }); + } + + @Override + public OpenAPI getOpenAPI(OpenAPIRequest request) { + Collection registrations = requestMappingRegistry.getRegistrations(); + Map, ServiceMeta> serviceMetaMap = new HashMap<>(); + for (Registration registration : registrations) { + ServiceMeta serviceMeta = registration.getMeta().getService(); + serviceMetaMap.putIfAbsent(serviceMeta.getType(), serviceMeta); + } + + Map, OpenAPI> openAPIMap = new IdentityHashMap<>(); + out: + for (Entry, ServiceMeta> entry : serviceMetaMap.entrySet()) { + for (int i = 0, size = annotationResolvers.size(); i < size; i++) { + OpenAPI openAPI = annotationResolvers.get(i).resolve(entry.getValue()); + if (openAPI == null) { + continue; + } + openAPIMap.put(entry.getKey(), openAPI); + continue out; + } + } + + Map> registrationsGroupMap = new IdentityHashMap<>(registrations.size()); + for (Registration registration : registrations) { + registrationsGroupMap + .computeIfAbsent(registration.getMeta().getMethod().getMethod(), k -> new ArrayList<>(1)) + .add(registration); + } + + ResolveContext context = new ResolveContext(schemaFactory); + out: + for (List registrationsGroup : registrationsGroupMap.values()) { + String mainPath = null; + for (int i = 0, size = registrationsGroup.size(); i < size; i++) { + Registration registration = registrationsGroup.get(i); + HandlerMeta meta = registration.getMeta(); + OpenAPI openAPI = openAPIMap.get(meta.getService().getType()); + if (openAPI == null) { + continue out; + } + RequestMapping mapping = registration.getMapping(); + List expressions = mapping.getPathCondition().getExpressions(); + for (int j = 0, len = expressions.size(); j < len; j++) { + PathExpression expression = expressions.get(j); + String path = Helper.resolvePath(expression); + PathItem pathItem = openAPI.getOrAddPath(path); + if (pathItem.getRef() != null) { + path = pathItem.getRef(); + pathItem = openAPI.getOrAddPath(path); + } + if (mainPath == null) { + mainPath = path; + Set methods = mapping.getMethodsCondition().getMethods(); + for (String method : methods) { + HttpMethods httpMethod = HttpMethods.of(method); + Operation operation = pathItem.getOrAddOperation(httpMethod); + operation.setMeta(meta.getMethod()); + resolveOperation(openAPI, httpMethod, operation, expression, mapping, meta, context); + } + } else { + pathItem.setRef(Helper.pathToRef(mainPath)); + } + } + } + } + return null; + } + + private void resolveOperation( + OpenAPI openAPI, + HttpMethods method, + Operation operation, + PathExpression expression, + RequestMapping mapping, + HandlerMeta meta, + ResolveContext context) { + operation.setOperationId(meta.getMethodDescriptor().getMethodName()); + for (ParameterMeta paramMeta : meta.getMethod().getParameters()) { + Parameter parameter = resolveParameter(paramMeta); + if (parameter != null) { + operation.addParameter(parameter); + } + } + resolveRequestBody(operation, mapping, meta); + for (String httpStatus : new String[] {"200", "500"}) { + resolveResponse(operation, httpStatus, mapping, meta); + } + } + + private Parameter resolveParameter(ParameterMeta paramMeta) { + if (paramMeta == null) { + return null; + } + Parameter parameter = new Parameter(); + parameter.setMeta(paramMeta); + return parameter; + } + + private void resolveRequestBody(Operation operation, RequestMapping mapping, HandlerMeta meta) { + RequestBody body = new RequestBody(); + List mediaTypes = + mapping.getConsumesCondition().getMediaTypes(); + for (org.apache.dubbo.remoting.http12.message.MediaType mediaType : mediaTypes) { + MediaType mediaTypeModel = new MediaType(); + mediaTypeModel.setSchema(resolveSchema(meta.getMethod().getMethod().getParameterTypes()[0])); + body.addContent(mediaType.getName(), mediaTypeModel); + } + operation.setRequestBody(body); + } + + private void resolveResponse(Operation operation, String httpStatus, RequestMapping mapping, HandlerMeta meta) { + ApiResponse response = new ApiResponse(); + List mediaTypes = + mapping.getProducesCondition().getMediaTypes(); + for (org.apache.dubbo.remoting.http12.message.MediaType mediaType : mediaTypes) { + MediaType mediaTypeModel = new MediaType(); + mediaTypeModel.setSchema(resolveSchema(meta.getMethod().getReturnType())); + response.addContent(mediaType.getName(), mediaTypeModel); + } + operation.addResponse(httpStatus, response); + } + + private Schema resolveSchema(Class returnType) { + return null; + } + + @Override + public String getDocument(OpenAPIRequest request) { + Map document = new LinkedHashMap<>(); + OpenAPI openAPI = getOpenAPI(request); + openAPI.writeTo(document, new WriteContext() {}); + + HttpMessageEncoder encoder = getEncoder(request); + ByteArrayOutputStream os = new ByteArrayOutputStream(1024); + encoder.encode(os, document, StandardCharsets.UTF_8); + return new String(os.toByteArray(), StandardCharsets.UTF_8); + } + + private static HttpMessageEncoder getEncoder(OpenAPIRequest request) { + String format = request.getFormat(); + format = format == null ? "json" : format.toLowerCase(); + HttpMessageEncoder encoder; + switch (format) { + case "json": + encoder = JsonCodec.INSTANCE; + break; + case "yml": + case "yaml": + encoder = YamlCodec.INSTANCE; + break; + case "proto": + encoder = ProtoEncoder.INSTANCE; + break; + default: + throw new UnsupportedMediaTypeException("application/" + format); + } + return encoder; + } + + @Override + public void refresh() { + this.openAPIMap = null; + } + + @Override + public void export() {} + + @Override + public void destroy() { + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/FilterContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/FilterContext.java new file mode 100644 index 00000000000..f5abd5212fa --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/FilterContext.java @@ -0,0 +1,19 @@ +/* + * 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.protocol.tri.rest.openapi; + +public interface FilterContext {} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java new file mode 100644 index 00000000000..733d0789eaa --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -0,0 +1,36 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression; + +public final class Helper { + + private Helper() {} + + public static String resolvePath(PathExpression expr) { + return expr.getPath(); + } + + public static String pathToRef(String path) { + return path; + } + + public static String refToPath(String ref) { + return ref; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java new file mode 100644 index 00000000000..5ffc8c0baf2 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java @@ -0,0 +1,29 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.extension.ExtensionScope; +import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.common.lang.Prioritized; + +@SPI(scope = ExtensionScope.FRAMEWORK) +public interface OpenAPIExtension extends Prioritized { + + default String[] getGroups() { + return null; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java new file mode 100644 index 00000000000..ff0297debc0 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java @@ -0,0 +1,79 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; + +public interface OpenAPIFilter extends OpenAPIExtension { + + default OpenAPI filterOpenAPI(OpenAPI openAPI, FilterContext context) { + return openAPI; + } + + default PathItem filterPathItem(PathItem pathItem, FilterContext context) { + return pathItem; + } + + default Operation filterOperation(Operation operation, FilterContext context) { + return operation; + } + + default Parameter filterParameter(Parameter parameter, FilterContext context) { + return parameter; + } + + default RequestBody filterRequestBody(RequestBody requestBody, FilterContext context) { + return requestBody; + } + + default ApiResponse filterResponse(ApiResponse apiResponse, FilterContext context) { + return apiResponse; + } + + default Schema filterSchema(Schema schema, FilterContext context) { + return schema; + } + + default Schema filterSchemaProperty(Schema schema, FilterContext context) { + return schema; + } + + default Server filterServer(Server server, FilterContext context) { + return server; + } + + default SecurityScheme filterSecurityScheme(SecurityScheme securityScheme, FilterContext context) { + return securityScheme; + } + + default Tag filterTag(Tag tag, FilterContext context) { + return tag; + } + + default OpenAPI filterOpenAPICompletion(OpenAPI openAPI, FilterContext context) { + return openAPI; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequest.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequest.java new file mode 100644 index 00000000000..7e101bf9520 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequest.java @@ -0,0 +1,87 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.utils.ToStringUtils; + +import java.io.Serializable; + +public class OpenAPIRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + private String group; + private String[] tags; + private String service; + + private String version; + private String format; + private boolean pretty; + + public String getGroup() { + return group; + } + + public void setGroup(String group) { + this.group = group; + } + + public String[] getTags() { + return tags; + } + + public void setTags(String[] tags) { + this.tags = tags; + } + + public String getService() { + return service; + } + + public void setService(String service) { + this.service = service; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public boolean isPretty() { + return pretty; + } + + public void setPretty(boolean pretty) { + this.pretty = pretty; + } + + @Override + public String toString() { + return ToStringUtils.printToString(this); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java new file mode 100644 index 00000000000..6e12b9cda96 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java @@ -0,0 +1,30 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +public interface OpenAPIService { + + OpenAPI getOpenAPI(OpenAPIRequest request); + + String getDocument(OpenAPIRequest request); + + void refresh(); + + void export(); +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java new file mode 100644 index 00000000000..7b95b70486f --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java @@ -0,0 +1,40 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.remoting.http12.exception.EncodeException; +import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; +import org.apache.dubbo.remoting.http12.message.MediaType; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +import java.io.OutputStream; +import java.nio.charset.Charset; + +final class ProtoEncoder implements HttpMessageEncoder { + + static final ProtoEncoder INSTANCE = new ProtoEncoder(); + + @Override + public void encode(OutputStream outputStream, Object data, Charset charset) throws EncodeException { + OpenAPI openAPI = (OpenAPI) data; + } + + @Override + public MediaType mediaType() { + return MediaType.TEXT_PLAIN; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java new file mode 100644 index 00000000000..eb62043ab2e --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java @@ -0,0 +1,42 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.config.nested.OpenAPIConfig; + +public final class ResolveContext { + + private final SchemaFactory schemaFactory; + private OpenAPIConfig config; + + public ResolveContext(SchemaFactory schemaFactory) { + this.schemaFactory = schemaFactory; + } + + public SchemaFactory getSchemaFactory() { + return schemaFactory; + } + + public OpenAPIConfig getConfig() { + return config; + } + + public ResolveContext setConfig(OpenAPIConfig config) { + this.config = config; + return this; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java new file mode 100644 index 00000000000..dcfbccac3bf --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java @@ -0,0 +1,26 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; + +public class SchemaFactory { + + public static Schema getSchema(Class clazz) { + return new Schema(); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/WriteContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/WriteContext.java new file mode 100644 index 00000000000..f418b0ada89 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/WriteContext.java @@ -0,0 +1,19 @@ +/* + * 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.protocol.tri.rest.openapi; + +public interface WriteContext {} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java new file mode 100644 index 00000000000..4279cf7b819 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java @@ -0,0 +1,111 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class ApiResponse extends Node { + + private String ref; + private String description; + private Map headers; + private Map content; + + public String getRef() { + return ref; + } + + public ApiResponse setRef(String ref) { + this.ref = ref; + return this; + } + + public String getDescription() { + return description; + } + + public ApiResponse setDescription(String description) { + this.description = description; + return this; + } + + public Map getHeaders() { + return headers; + } + + public ApiResponse setHeaders(Map headers) { + this.headers = headers; + return this; + } + + public ApiResponse addHeader(String name, Header header) { + if (headers == null) { + headers = new LinkedHashMap<>(); + } + headers.put(name, header); + return this; + } + + public ApiResponse removeHeader(String name) { + if (headers != null) { + headers.remove(name); + } + return this; + } + + public Map getContent() { + return content; + } + + public ApiResponse setContent(Map content) { + this.content = content; + return this; + } + + public ApiResponse addContent(String name, MediaType mediaType) { + if (content == null) { + content = new LinkedHashMap<>(); + } + content.put(name, mediaType); + return this; + } + + public ApiResponse removeContent(String name) { + if (content != null) { + content.remove(name); + } + return this; + } + + @Override + public ApiResponse clone() { + ApiResponse clone = super.clone(); + clone.content = clone(content); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "description", description); + write(node, "content", content, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java new file mode 100644 index 00000000000..0180c7af7ca --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java @@ -0,0 +1,92 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class Components extends Node { + + private Map schemas; + private Map securitySchemes; + + public Map getSchemas() { + return schemas; + } + + public Components setSchemas(Map schemas) { + this.schemas = schemas; + return this; + } + + public Components addSchema(String name, Schema schema) { + if (schemas == null) { + schemas = new LinkedHashMap<>(); + } + schemas.put(name, schema); + return this; + } + + public Components removeSchema(String name) { + if (schemas != null) { + schemas.remove(name); + } + return this; + } + + public Map getSecuritySchemes() { + return securitySchemes; + } + + public Components setSecuritySchemes(Map securitySchemes) { + this.securitySchemes = securitySchemes; + return this; + } + + public Components addSecurityScheme(String name, SecurityScheme securityScheme) { + if (securitySchemes == null) { + securitySchemes = new LinkedHashMap<>(); + } + securitySchemes.put(name, securityScheme); + return this; + } + + public Components removeSecurityScheme(String name) { + if (securitySchemes != null) { + securitySchemes.remove(name); + } + return this; + } + + @Override + public Components clone() { + Components clone = super.clone(); + clone.schemas = clone(schemas); + clone.securitySchemes = clone(securitySchemes); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "schemas", schemas, context); + write(node, "securitySchemes", securitySchemes, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java new file mode 100644 index 00000000000..a37d76cc06e --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java @@ -0,0 +1,64 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.Map; + +public final class Contact extends Node { + + private String name; + private String url; + private String email; + + public String getName() { + return name; + } + + public Contact setName(String name) { + this.name = name; + return this; + } + + public String getUrl() { + return url; + } + + public Contact setUrl(String url) { + this.url = url; + return this; + } + + public String getEmail() { + return email; + } + + public Contact setEmail(String email) { + this.email = email; + return this; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "name", name); + write(node, "url", url); + write(node, "email", email); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java new file mode 100644 index 00000000000..c3b9ca8cdb6 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java @@ -0,0 +1,78 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class Discriminator extends Node { + + private String propertyName; + private Map mapping; + + public String getPropertyName() { + return propertyName; + } + + public Discriminator setPropertyName(String propertyName) { + this.propertyName = propertyName; + return this; + } + + public Map getMapping() { + return mapping; + } + + public Discriminator setMapping(Map mapping) { + this.mapping = mapping; + return this; + } + + public Discriminator addMapping(String key, String value) { + if (mapping == null) { + mapping = new LinkedHashMap<>(); + } + mapping.put(key, value); + return this; + } + + public Discriminator removeMapping(String key) { + if (mapping != null) { + mapping.remove(key); + } + return this; + } + + @Override + public Discriminator clone() { + Discriminator clone = super.clone(); + if (mapping != null) { + clone.setMapping(new LinkedHashMap<>(mapping)); + } + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "propertyName", propertyName); + write(node, "mapping", mapping); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java new file mode 100644 index 00000000000..d70b18da1f2 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java @@ -0,0 +1,127 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class Encoding extends Node { + + public enum Style { + FORM("form"), + SPACE_DELIMITED("spaceDelimited"), + PIPE_DELIMITED("pipeDelimited"), + DEEP_OBJECT("deepObject"); + + private final String value; + + Style(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + private String contentType; + private Map headers; + private Style style; + private Boolean explode; + private Boolean allowReserved; + + public String getContentType() { + return contentType; + } + + public Encoding setContentType(String contentType) { + this.contentType = contentType; + return this; + } + + public Map getHeaders() { + return headers; + } + + public Encoding setHeaders(Map headers) { + this.headers = headers; + return this; + } + + public Encoding addHeader(String name, Parameter header) { + if (headers == null) { + headers = new LinkedHashMap<>(); + } + headers.put(name, header); + return this; + } + + public Encoding removeHeader(String name) { + if (headers != null) { + headers.remove(name); + } + return this; + } + + public Style getStyle() { + return style; + } + + public Encoding setStyle(Style style) { + this.style = style; + return this; + } + + public Boolean getExplode() { + return explode; + } + + public Encoding setExplode(Boolean explode) { + this.explode = explode; + return this; + } + + public Boolean getAllowReserved() { + return allowReserved; + } + + public Encoding setAllowReserved(Boolean allowReserved) { + this.allowReserved = allowReserved; + return this; + } + + @Override + public Encoding clone() { + Encoding clone = super.clone(); + clone.headers = clone(headers); + return clone; + } + + @Override + public Map writeTo(Map encoding, WriteContext context) { + write(encoding, "contentType", contentType); + write(encoding, "headers", headers, context); + write(encoding, "style", style); + write(encoding, "explode", explode); + write(encoding, "allowReserved", allowReserved); + writeExtensions(encoding); + return encoding; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java new file mode 100644 index 00000000000..b7c0d2bd525 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java @@ -0,0 +1,75 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.Map; + +public final class Example extends Node { + + private String summary; + private String description; + private Object value; + private String externalValue; + + public String getSummary() { + return summary; + } + + public Example setSummary(String summary) { + this.summary = summary; + return this; + } + + public String getDescription() { + return description; + } + + public Example setDescription(String description) { + this.description = description; + return this; + } + + public Object getValue() { + return value; + } + + public Example setValue(Object value) { + this.value = value; + return this; + } + + public String getExternalValue() { + return externalValue; + } + + public Example setExternalValue(String externalValue) { + this.externalValue = externalValue; + return this; + } + + @Override + public Map writeTo(Map exampleNode, WriteContext context) { + write(exampleNode, "summary", summary); + write(exampleNode, "description", description); + write(exampleNode, "value", value); + write(exampleNode, "externalValue", externalValue); + writeExtensions(exampleNode); + return exampleNode; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java new file mode 100644 index 00000000000..04075d81e07 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java @@ -0,0 +1,53 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.Map; + +public final class ExternalDocs extends Node { + + private String description; + private String url; + + public String getDescription() { + return description; + } + + public ExternalDocs setDescription(String description) { + this.description = description; + return this; + } + + public String getUrl() { + return url; + } + + public ExternalDocs setUrl(String url) { + this.url = url; + return this; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "description", description); + write(node, "url", url); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java new file mode 100644 index 00000000000..a7d237a9b6a --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java @@ -0,0 +1,191 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class Header extends Node
{ + + public enum Style { + SIMPLE("simple"); + + private final String value; + + Style(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + private String description; + private Boolean required; + private Boolean deprecated; + private Boolean allowEmptyValue; + private final Style style = Style.SIMPLE; + private Boolean explode; + private Schema schema; + private Object example; + private Map examples; + private Map content; + + public String getDescription() { + return description; + } + + public Header setDescription(String description) { + this.description = description; + return this; + } + + public Boolean getRequired() { + return required; + } + + public Header setRequired(Boolean required) { + this.required = required; + return this; + } + + public Boolean getDeprecated() { + return deprecated; + } + + public Header setDeprecated(Boolean deprecated) { + this.deprecated = deprecated; + return this; + } + + public Boolean getAllowEmptyValue() { + return allowEmptyValue; + } + + public Header setAllowEmptyValue(Boolean allowEmptyValue) { + this.allowEmptyValue = allowEmptyValue; + return this; + } + + public Style getStyle() { + return style; + } + + public Boolean getExplode() { + return explode; + } + + public Header setExplode(Boolean explode) { + this.explode = explode; + return this; + } + + public Schema getSchema() { + return schema; + } + + public Header setSchema(Schema schema) { + this.schema = schema; + return this; + } + + public Object getExample() { + return example; + } + + public Header setExample(Object example) { + this.example = example; + return this; + } + + public Map getExamples() { + return examples; + } + + public Header setExamples(Map examples) { + this.examples = examples; + return this; + } + + public Header addExample(String name, Example example) { + if (examples == null) { + examples = new LinkedHashMap<>(); + } + examples.put(name, example); + return this; + } + + public Header removeExample(String name) { + if (examples != null) { + examples.remove(name); + } + return this; + } + + public Map getContent() { + return content; + } + + public Header setContent(Map content) { + this.content = content; + return this; + } + + public Header addContent(String name, MediaType mediaType) { + if (content == null) { + content = new LinkedHashMap<>(); + } + content.put(name, mediaType); + return this; + } + + public Header removeContent(String name) { + if (content != null) { + content.remove(name); + } + return this; + } + + @Override + public Header clone() { + Header clone = super.clone(); + clone.schema = clone(schema); + clone.examples = clone(examples); + clone.content = clone(content); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "description", description); + write(node, "required", required); + write(node, "deprecated", deprecated); + write(node, "allowEmptyValue", allowEmptyValue); + write(node, "style", style); + write(node, "explode", explode); + write(node, "schema", schema, context); + write(node, "example", example); + write(node, "examples", examples, context); + write(node, "content", content, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java new file mode 100644 index 00000000000..bd0339d3ce2 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java @@ -0,0 +1,116 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.Map; + +public final class Info extends Node { + + private String title; + private String summary; + private String description; + private String termsOfService; + private Contact contact; + private License license; + private String version; + + public String getTitle() { + return title; + } + + public Info setTitle(String title) { + this.title = title; + return this; + } + + public String getSummary() { + return summary; + } + + public Info setSummary(String summary) { + this.summary = summary; + return this; + } + + public String getDescription() { + return description; + } + + public Info setDescription(String description) { + this.description = description; + return this; + } + + public String getTermsOfService() { + return termsOfService; + } + + public Info setTermsOfService(String termsOfService) { + this.termsOfService = termsOfService; + return this; + } + + public Contact getContact() { + return contact; + } + + public Info setContact(Contact contact) { + this.contact = contact; + return this; + } + + public License getLicense() { + return license; + } + + public Info setLicense(License license) { + this.license = license; + return this; + } + + public String getVersion() { + return version; + } + + public Info setVersion(String version) { + this.version = version; + return this; + } + + @Override + public Info clone() { + Info clone = super.clone(); + clone.contact = clone(contact); + clone.license = clone(license); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "title", title); + write(node, "summary", summary); + write(node, "description", description); + write(node, "termsOfService", termsOfService); + write(node, "contact", contact, context); + write(node, "license", license, context); + write(node, "version", version); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java new file mode 100644 index 00000000000..9f0965d54a8 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java @@ -0,0 +1,53 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.Map; + +public final class License extends Node { + + private String name; + private String url; + + public String getName() { + return name; + } + + public License setName(String name) { + this.name = name; + return this; + } + + public String getUrl() { + return url; + } + + public License setUrl(String url) { + this.url = url; + return this; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "name", name); + write(node, "url", url); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java new file mode 100644 index 00000000000..109e744e516 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java @@ -0,0 +1,115 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class MediaType extends Node { + + private Schema schema; + private Object example; + private Map examples; + private Map encoding; + + public Schema getSchema() { + return schema; + } + + public MediaType setSchema(Schema schema) { + this.schema = schema; + return this; + } + + public Object getExample() { + return example; + } + + public MediaType setExample(Object example) { + this.example = example; + return this; + } + + public Map getExamples() { + return examples; + } + + public MediaType setExamples(Map examples) { + this.examples = examples; + return this; + } + + public MediaType addExample(String name, Example example) { + if (examples == null) { + examples = new LinkedHashMap<>(); + } + examples.put(name, example); + return this; + } + + public MediaType removeExample(String name) { + if (examples != null) { + examples.remove(name); + } + return this; + } + + public Map getEncoding() { + return encoding; + } + + public MediaType setEncoding(Map encoding) { + this.encoding = encoding; + return this; + } + + public MediaType addEncoding(String name, Encoding encoding) { + if (this.encoding == null) { + this.encoding = new LinkedHashMap<>(); + } + this.encoding.put(name, encoding); + return this; + } + + public MediaType removeEncoding(String name) { + if (encoding != null) { + encoding.remove(name); + } + return this; + } + + @Override + public MediaType clone() { + MediaType clone = super.clone(); + clone.schema = clone(schema); + clone.examples = clone(examples); + clone.encoding = clone(encoding); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "schema", schema, context); + write(node, "example", example); + write(node, "examples", examples, context); + write(node, "encoding", encoding, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java new file mode 100644 index 00000000000..125de5a7640 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java @@ -0,0 +1,164 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.common.utils.ToStringUtils; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public abstract class Node> implements Cloneable { + + private Map extensions; + + public Map getExtensions() { + return extensions; + } + + @SuppressWarnings("unchecked") + public T addExtension(String name, Object value) { + Map extensions = this.extensions; + if (extensions == null) { + this.extensions = extensions = new LinkedHashMap<>(); + } + extensions.put(name, value); + return (T) this; + } + + public void removeExtension(String name) { + if (extensions != null) { + extensions.remove(name); + } + } + + public void setExtensions(Map extensions) { + this.extensions = new LinkedHashMap<>(extensions); + } + + @Override + @SuppressWarnings("unchecked") + public T clone() { + try { + T clone = (T) super.clone(); + if (extensions != null) { + clone.setExtensions(extensions); + } + return clone; + } catch (CloneNotSupportedException e) { + throw new UnsupportedOperationException(e); + } + } + + @Override + public String toString() { + return ToStringUtils.printToString(this); + } + + protected static > T clone(T node) { + return node == null ? null : node.clone(); + } + + protected static > List clone(List list) { + if (list == null) { + return null; + } + int size = list.size(); + if (size == 0) { + return new ArrayList<>(); + } + List clone = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + clone.add(list.get(i).clone()); + } + return clone; + } + + protected static > Map clone(Map map) { + if (map == null) { + return null; + } + int size = map.size(); + if (size == 0) { + return new LinkedHashMap<>(); + } + Map clone = newMap(size); + for (Map.Entry entry : map.entrySet()) { + clone.put(entry.getKey(), entry.getValue().clone()); + } + return clone; + } + + protected static void write(Map node, String name, Object value) { + if (value == null) { + return; + } + node.put(name, value); + } + + protected static void write(Map node, String name, Node value, WriteContext context) { + if (value == null) { + return; + } + node.put(name, value.writeTo(new LinkedHashMap<>(), context)); + } + + protected static void write( + Map node, String name, List> value, WriteContext context) { + if (value == null) { + return; + } + int size = value.size(); + if (size > 0) { + List> list = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + list.add(value.get(i).writeTo(new LinkedHashMap<>(), context)); + } + node.put(name, list); + } + } + + protected static void write( + Map node, String name, Map> value, WriteContext context) { + if (value == null) { + return; + } + int size = value.size(); + if (size > 0) { + Map> map = newMap(size); + for (Map.Entry> entry : value.entrySet()) { + map.put(entry.getKey(), entry.getValue().writeTo(new LinkedHashMap<>(), context)); + } + node.put(name, map); + } + } + + protected static Map newMap(int capacity) { + return new LinkedHashMap<>(capacity < 3 ? capacity + 1 : (int) (capacity / 0.75F + 1.0F)); + } + + protected final void writeExtensions(Map node) { + if (extensions == null) { + return; + } + node.putAll(extensions); + } + + public abstract Map writeTo(Map node, WriteContext context); +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java new file mode 100644 index 00000000000..10e78591904 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java @@ -0,0 +1,99 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class OAuthFlow extends Node { + + private String authorizationUrl; + private String tokenUrl; + private String refreshUrl; + private Map scopes; + + public String getAuthorizationUrl() { + return authorizationUrl; + } + + public OAuthFlow setAuthorizationUrl(String authorizationUrl) { + this.authorizationUrl = authorizationUrl; + return this; + } + + public String getTokenUrl() { + return tokenUrl; + } + + public OAuthFlow setTokenUrl(String tokenUrl) { + this.tokenUrl = tokenUrl; + return this; + } + + public String getRefreshUrl() { + return refreshUrl; + } + + public OAuthFlow setRefreshUrl(String refreshUrl) { + this.refreshUrl = refreshUrl; + return this; + } + + public Map getScopes() { + return scopes; + } + + public OAuthFlow setScopes(Map scopes) { + this.scopes = scopes; + return this; + } + + public OAuthFlow addScope(String name, String description) { + if (scopes == null) { + scopes = new LinkedHashMap<>(); + } + scopes.put(name, description); + return this; + } + + public void removeScope(String name) { + if (scopes != null) { + scopes.remove(name); + } + } + + @Override + public OAuthFlow clone() { + OAuthFlow clone = super.clone(); + if (scopes != null) { + clone.scopes = new LinkedHashMap<>(scopes); + } + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "authorizationUrl", authorizationUrl); + write(node, "tokenUrl", tokenUrl); + write(node, "refreshUrl", refreshUrl); + write(node, "scopes", scopes); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java new file mode 100644 index 00000000000..55a17e347c6 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java @@ -0,0 +1,85 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.Map; + +public final class OAuthFlows extends Node { + + private OAuthFlow implicit; + private OAuthFlow password; + private OAuthFlow clientCredentials; + private OAuthFlow authorizationCode; + + public OAuthFlow getImplicit() { + return implicit; + } + + public OAuthFlows setImplicit(OAuthFlow implicit) { + this.implicit = implicit; + return this; + } + + public OAuthFlow getPassword() { + return password; + } + + public OAuthFlows setPassword(OAuthFlow password) { + this.password = password; + return this; + } + + public OAuthFlow getClientCredentials() { + return clientCredentials; + } + + public OAuthFlows setClientCredentials(OAuthFlow clientCredentials) { + this.clientCredentials = clientCredentials; + return this; + } + + public OAuthFlow getAuthorizationCode() { + return authorizationCode; + } + + public OAuthFlows setAuthorizationCode(OAuthFlow authorizationCode) { + this.authorizationCode = authorizationCode; + return this; + } + + @Override + public OAuthFlows clone() { + OAuthFlows clone = super.clone(); + clone.implicit = clone(implicit); + clone.password = clone(password); + clone.clientCredentials = clone(clientCredentials); + clone.authorizationCode = clone(authorizationCode); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "implicit", implicit); + write(node, "password", password); + write(node, "clientCredentials", clientCredentials); + write(node, "authorizationCode", authorizationCode); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java new file mode 100644 index 00000000000..c1fe5c26367 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java @@ -0,0 +1,216 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class OpenAPI extends Node { + + private String openapi; + private Info info; + private List servers; + private Map paths; + private Components components; + private List security; + private List tags; + private ExternalDocs externalDocs; + + private String[] groups; + private transient int priority; + + public String getOpenapi() { + return openapi; + } + + public OpenAPI setOpenapi(String openapi) { + this.openapi = openapi; + return this; + } + + public Info getInfo() { + return info; + } + + public OpenAPI setInfo(Info info) { + this.info = info; + return this; + } + + public List getServers() { + return servers; + } + + public OpenAPI setServers(List servers) { + this.servers = servers; + return this; + } + + public OpenAPI addServer(Server server) { + if (servers == null) { + servers = new ArrayList<>(); + } + servers.add(server); + return this; + } + + public OpenAPI removeServer(Server server) { + if (servers != null) { + servers.remove(server); + } + return this; + } + + public Map getPaths() { + return paths; + } + + public PathItem getOrAddPath(String path) { + if (paths == null) { + paths = new LinkedHashMap<>(); + } + return paths.computeIfAbsent(path, k -> new PathItem()); + } + + public OpenAPI setPaths(Map paths) { + this.paths = paths; + return this; + } + + public OpenAPI addPath(String path, PathItem pathItem) { + if (paths == null) { + paths = new LinkedHashMap<>(); + } + paths.put(path, pathItem); + return this; + } + + public OpenAPI removePath(String path) { + if (paths != null) { + paths.remove(path); + } + return this; + } + + public Components getComponents() { + return components; + } + + public OpenAPI setComponents(Components components) { + this.components = components; + return this; + } + + public List getSecurity() { + return security; + } + + public OpenAPI setSecurity(List security) { + this.security = security; + return this; + } + + public OpenAPI addSecurity(SecurityRequirement securityRequirement) { + if (security == null) { + security = new ArrayList<>(); + } + security.add(securityRequirement); + return this; + } + + public List getTags() { + return tags; + } + + public OpenAPI setTags(List tags) { + this.tags = tags; + return this; + } + + public OpenAPI addTag(Tag tag) { + if (tags == null) { + tags = new ArrayList<>(); + } + tags.add(tag); + return this; + } + + public OpenAPI removeTag(Tag tag) { + if (tags != null) { + tags.remove(tag); + } + return this; + } + + public ExternalDocs getExternalDocs() { + return externalDocs; + } + + public OpenAPI setExternalDocs(ExternalDocs externalDocs) { + this.externalDocs = externalDocs; + return this; + } + + public String[] getGroups() { + return groups; + } + + public OpenAPI setGroups(String[] groups) { + this.groups = groups; + return this; + } + + public int getPriority() { + return priority; + } + + public OpenAPI setPriority(int priority) { + this.priority = priority; + return this; + } + + @Override + public OpenAPI clone() { + OpenAPI clone = super.clone(); + clone.info = clone(info); + clone.servers = clone(servers); + clone.paths = clone(paths); + clone.components = clone(components); + clone.security = clone(security); + clone.tags = clone(tags); + clone.externalDocs = clone(externalDocs); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + node.put("openapi", openapi); + write(node, "info", info, context); + write(node, "servers", servers, context); + write(node, "paths", paths, context); + write(node, "components", components, context); + write(node, "security", security, context); + write(node, "tags", tags, context); + write(node, "externalDocs", externalDocs, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java new file mode 100644 index 00000000000..09222c44269 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java @@ -0,0 +1,277 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class Operation extends Node { + + private List tags; + private String summary; + private String description; + private ExternalDocs externalDocs; + private String operationId; + private List parameters; + private RequestBody requestBody; + private Map responses; + private Boolean deprecated; + private List security; + private List servers; + + private String[] groups; + private transient int priority; + private transient MethodMeta meta; + + public List getTags() { + return tags; + } + + public Operation setTags(List tags) { + this.tags = tags; + return this; + } + + public Operation addTag(String tag) { + if (tags == null) { + tags = new ArrayList<>(); + } + tags.add(tag); + return this; + } + + public Operation removeTag(String tag) { + if (tags != null) { + tags.remove(tag); + } + return this; + } + + public String getSummary() { + return summary; + } + + public Operation setSummary(String summary) { + this.summary = summary; + return this; + } + + public String getDescription() { + return description; + } + + public Operation setDescription(String description) { + this.description = description; + return this; + } + + public ExternalDocs getExternalDocs() { + return externalDocs; + } + + public Operation setExternalDocs(ExternalDocs externalDocs) { + this.externalDocs = externalDocs; + return this; + } + + public String getOperationId() { + return operationId; + } + + public Operation setOperationId(String operationId) { + this.operationId = operationId; + return this; + } + + public List getParameters() { + return parameters; + } + + public Operation setParameters(List parameters) { + this.parameters = parameters; + return this; + } + + public Operation addParameter(Parameter parameter) { + if (parameters == null) { + parameters = new ArrayList<>(); + } + parameters.add(parameter); + return this; + } + + public Operation removeParameter(Parameter parameter) { + if (parameters != null) { + parameters.remove(parameter); + } + return this; + } + + public RequestBody getRequestBody() { + return requestBody; + } + + public Operation setRequestBody(RequestBody requestBody) { + this.requestBody = requestBody; + return this; + } + + public Map getResponses() { + return responses; + } + + public Operation setResponses(Map responses) { + this.responses = responses; + return this; + } + + public Operation addResponse(String name, ApiResponse response) { + if (responses == null) { + responses = new LinkedHashMap<>(); + } + responses.put(name, response); + return this; + } + + public Operation removeResponse(String name) { + if (responses != null) { + responses.remove(name); + } + return this; + } + + public Boolean getDeprecated() { + return deprecated; + } + + public Operation setDeprecated(Boolean deprecated) { + this.deprecated = deprecated; + return this; + } + + public List getSecurity() { + return security; + } + + public Operation setSecurity(List security) { + this.security = security; + return this; + } + + public Operation addSecurity(SecurityRequirement security) { + if (this.security == null) { + this.security = new ArrayList<>(); + } + this.security.add(security); + return this; + } + + public Operation removeSecurity(SecurityRequirement security) { + if (this.security != null) { + this.security.remove(security); + } + return this; + } + + public List getServers() { + return servers; + } + + public Operation setServers(List servers) { + this.servers = servers; + return this; + } + + public Operation addServer(Server server) { + if (servers == null) { + servers = new ArrayList<>(); + } + servers.add(server); + return this; + } + + public Operation removeServer(Server server) { + if (servers != null) { + servers.remove(server); + } + return this; + } + + public String[] getGroups() { + return groups; + } + + public Operation setGroups(String[] groups) { + this.groups = groups; + return this; + } + + public int getPriority() { + return priority; + } + + public Operation setPriority(int priority) { + this.priority = priority; + return this; + } + + public MethodMeta getMeta() { + return meta; + } + + public Operation setMeta(MethodMeta meta) { + this.meta = meta; + return this; + } + + @Override + public Operation clone() { + Operation clone = super.clone(); + if (tags != null) { + clone.tags = new ArrayList<>(tags); + } + clone.externalDocs = clone(externalDocs); + clone.parameters = clone(parameters); + clone.requestBody = clone(requestBody); + clone.responses = clone(responses); + clone.security = clone(security); + clone.servers = clone(servers); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "tags", tags); + write(node, "summary", summary); + write(node, "description", description); + write(node, "externalDocs", externalDocs, context); + write(node, "operationId", operationId); + write(node, "parameters", parameters, context); + write(node, "requestBody", requestBody, context); + write(node, "responses", responses, context); + write(node, "deprecated", deprecated); + write(node, "security", security, context); + write(node, "servers", servers, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java new file mode 100644 index 00000000000..9308039ac76 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java @@ -0,0 +1,265 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class Parameter extends Node { + + public enum In { + PATH("path"), + QUERY("query"), + HEADER("header"), + COOKIE("cookie"); + + private final String value; + + In(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + public enum Style { + MATRIX("matrix"), + LABEL("label"), + FORM("form"), + SIMPLE("simple"), + SPACE_DELIMITED("spaceDelimited"), + PIPE_DELIMITED("pipeDelimited"), + DEEP_OBJECT("deepObject"); + + private final String value; + + Style(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + private String name; + private In in; + private String description; + private Boolean required; + private Boolean deprecated; + private Boolean allowEmptyValue; + private Style style; + private Boolean explode; + private Boolean allowReserved; + private Schema schema; + private Object example; + private Map examples; + private Map content; + + private transient ParameterMeta meta; + + public String getName() { + return name; + } + + public Parameter setName(String name) { + this.name = name; + return this; + } + + public In getIn() { + return in; + } + + public Parameter setIn(In in) { + this.in = in; + return this; + } + + public String getDescription() { + return description; + } + + public Parameter setDescription(String description) { + this.description = description; + return this; + } + + public Boolean getRequired() { + return required; + } + + public Parameter setRequired(Boolean required) { + this.required = required; + return this; + } + + public Boolean getDeprecated() { + return deprecated; + } + + public Parameter setDeprecated(Boolean deprecated) { + this.deprecated = deprecated; + return this; + } + + public Boolean getAllowEmptyValue() { + return allowEmptyValue; + } + + public Parameter setAllowEmptyValue(Boolean allowEmptyValue) { + this.allowEmptyValue = allowEmptyValue; + return this; + } + + public Style getStyle() { + return style; + } + + public Parameter setStyle(Style style) { + this.style = style; + return this; + } + + public Boolean getExplode() { + return explode; + } + + public Parameter setExplode(Boolean explode) { + this.explode = explode; + return this; + } + + public Boolean getAllowReserved() { + return allowReserved; + } + + public Parameter setAllowReserved(Boolean allowReserved) { + this.allowReserved = allowReserved; + return this; + } + + public Schema getSchema() { + return schema; + } + + public Parameter setSchema(Schema schema) { + this.schema = schema; + return this; + } + + public Object getExample() { + return example; + } + + public Parameter setExample(Object example) { + this.example = example; + return this; + } + + public Map getExamples() { + return examples; + } + + public Parameter setExamples(Map examples) { + this.examples = examples; + return this; + } + + public Parameter addExample(String name, Example example) { + if (examples == null) { + examples = new LinkedHashMap<>(); + } + examples.put(name, example); + return this; + } + + public Parameter removeExample(String name) { + if (examples != null) { + examples.remove(name); + } + return this; + } + + public Map getContent() { + return content; + } + + public Parameter setContent(Map content) { + this.content = content; + return this; + } + + public Parameter addContent(String name, MediaType mediaType) { + if (content == null) { + content = new LinkedHashMap<>(); + } + content.put(name, mediaType); + return this; + } + + public Parameter removeContent(String name) { + if (content != null) { + content.remove(name); + } + return this; + } + + public ParameterMeta getMeta() { + return meta; + } + + public Parameter setMeta(ParameterMeta meta) { + this.meta = meta; + return this; + } + + @Override + public Parameter clone() { + Parameter clone = super.clone(); + clone.schema = clone(schema); + clone.examples = clone(examples); + clone.content = clone(content); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "name", name); + write(node, "in", in); + write(node, "description", description); + write(node, "required", required); + write(node, "deprecated", deprecated); + write(node, "allowEmptyValue", allowEmptyValue); + write(node, "style", style); + write(node, "explode", explode); + write(node, "allowReserved", allowReserved); + write(node, "schema", schema, context); + write(node, "example", example); + write(node, "examples", examples, context); + write(node, "content", content, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java new file mode 100644 index 00000000000..bd77f481f1b --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java @@ -0,0 +1,161 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class PathItem extends Node { + + private String ref; + private String summary; + private String description; + private Map operations; + private List servers; + private List parameters; + + public String getRef() { + return ref; + } + + public PathItem setRef(String ref) { + this.ref = ref; + return this; + } + + public String getSummary() { + return summary; + } + + public PathItem setSummary(String summary) { + this.summary = summary; + return this; + } + + public String getDescription() { + return description; + } + + public PathItem setDescription(String description) { + this.description = description; + return this; + } + + public Map getOperations() { + return operations; + } + + public Operation getOrAddOperation(HttpMethods method) { + return operations.computeIfAbsent(method, k -> new Operation()); + } + + public PathItem setOperations(Map operations) { + this.operations = operations; + return this; + } + + public PathItem addOperation(HttpMethods method, Operation operation) { + if (operations == null) { + operations = new LinkedHashMap<>(); + } + operations.put(method, operation); + return this; + } + + public PathItem removeOperation(HttpMethods method) { + if (operations != null) { + operations.remove(method); + } + return this; + } + + public List getServers() { + return servers; + } + + public PathItem setServers(List servers) { + this.servers = servers; + return this; + } + + public PathItem addServer(Server server) { + if (servers == null) { + servers = new ArrayList<>(); + } + servers.add(server); + return this; + } + + public PathItem removeServer(Server server) { + if (servers != null) { + servers.remove(server); + } + return this; + } + + public List getParameters() { + return parameters; + } + + public PathItem setParameters(List parameters) { + this.parameters = parameters; + return this; + } + + public PathItem addParameter(Parameter parameter) { + if (parameters == null) { + parameters = new ArrayList<>(); + } + parameters.add(parameter); + return this; + } + + public PathItem removeParameter(Parameter parameter) { + if (parameters != null) { + parameters.remove(parameter); + } + return this; + } + + @Override + public PathItem clone() { + PathItem clone = super.clone(); + clone.operations = clone(operations); + clone.servers = clone(servers); + clone.parameters = clone(parameters); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "$ref", ref); + write(node, "summary", summary); + write(node, "description", description); + for (Map.Entry entry : operations.entrySet()) { + write(node, entry.getKey().name().toLowerCase(), entry.getValue(), context); + } + write(node, "servers", servers, context); + write(node, "parameters", parameters, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java new file mode 100644 index 00000000000..9f063398e7d --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java @@ -0,0 +1,86 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class RequestBody extends Node { + + private String description; + private Map content; + private boolean required; + + public String getDescription() { + return description; + } + + public RequestBody setDescription(String description) { + this.description = description; + return this; + } + + public Map getContent() { + return content; + } + + public RequestBody setContent(Map content) { + this.content = content; + return this; + } + + public RequestBody addContent(String name, MediaType mediaType) { + if (content == null) { + content = new LinkedHashMap<>(); + } + content.put(name, mediaType); + return this; + } + + public RequestBody removeContent(String name) { + if (content != null) { + content.remove(name); + } + return this; + } + + public boolean isRequired() { + return required; + } + + public RequestBody setRequired(boolean required) { + this.required = required; + return this; + } + + @Override + public RequestBody clone() { + RequestBody clone = super.clone(); + clone.content = clone(content); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "description", description); + write(node, "required", required); + write(node, "content", content, context); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java new file mode 100644 index 00000000000..dd2c34626dd --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java @@ -0,0 +1,567 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class Schema extends Node { + + public enum Type { + INTEGER("integer"), + NUMBER("number"), + BOOLEAN("boolean"), + STRING("string"), + OBJECT("object"), + ARRAY("array"); + + private final String value; + + Type(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + private String ref; + private String format; + private String name; + private String title; + private String description; + private Object defaultValue; + private BigDecimal multipleOf; + private BigDecimal maximum; + private Boolean exclusiveMaximum; + private BigDecimal minimum; + private Boolean exclusiveMinimum; + private Integer maxLength; + private Integer minLength; + private String pattern; + private Integer maxItems; + private Integer minItems; + private Boolean uniqueItems; + private Integer maxProperties; + private Integer minProperties; + private List required; + private List enumeration; + private Type type; + private Schema items; + private Map properties; + private Schema additionalPropertiesSchema; + private Boolean additionalPropertiesBoolean; + private Boolean readOnly; + private XML xml; + private ExternalDocs externalDocs; + private Object example; + private List allOf; + private List oneOf; + private List anyOf; + private Schema not; + private Discriminator discriminator; + private Boolean nullable; + private Boolean writeOnly; + private Boolean deprecated; + + public String getRef() { + return ref; + } + + public Schema setRef(String ref) { + this.ref = ref; + return this; + } + + public String getFormat() { + return format; + } + + public Schema setFormat(String format) { + this.format = format; + return this; + } + + public String getName() { + return name; + } + + public Schema setName(String name) { + this.name = name; + return this; + } + + public String getTitle() { + return title; + } + + public Schema setTitle(String title) { + this.title = title; + return this; + } + + public String getDescription() { + return description; + } + + public Schema setDescription(String description) { + this.description = description; + return this; + } + + public Object getDefaultValue() { + return defaultValue; + } + + public Schema setDefaultValue(Object defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + public BigDecimal getMultipleOf() { + return multipleOf; + } + + public Schema setMultipleOf(BigDecimal multipleOf) { + this.multipleOf = multipleOf; + return this; + } + + public BigDecimal getMaximum() { + return maximum; + } + + public Schema setMaximum(BigDecimal maximum) { + this.maximum = maximum; + return this; + } + + public Boolean getExclusiveMaximum() { + return exclusiveMaximum; + } + + public Schema setExclusiveMaximum(Boolean exclusiveMaximum) { + this.exclusiveMaximum = exclusiveMaximum; + return this; + } + + public BigDecimal getMinimum() { + return minimum; + } + + public Schema setMinimum(BigDecimal minimum) { + this.minimum = minimum; + return this; + } + + public Boolean getExclusiveMinimum() { + return exclusiveMinimum; + } + + public Schema setExclusiveMinimum(Boolean exclusiveMinimum) { + this.exclusiveMinimum = exclusiveMinimum; + return this; + } + + public Integer getMaxLength() { + return maxLength; + } + + public Schema setMaxLength(Integer maxLength) { + this.maxLength = maxLength; + return this; + } + + public Integer getMinLength() { + return minLength; + } + + public Schema setMinLength(Integer minLength) { + this.minLength = minLength; + return this; + } + + public String getPattern() { + return pattern; + } + + public Schema setPattern(String pattern) { + this.pattern = pattern; + return this; + } + + public Integer getMaxItems() { + return maxItems; + } + + public Schema setMaxItems(Integer maxItems) { + this.maxItems = maxItems; + return this; + } + + public Integer getMinItems() { + return minItems; + } + + public Schema setMinItems(Integer minItems) { + this.minItems = minItems; + return this; + } + + public Boolean getUniqueItems() { + return uniqueItems; + } + + public Schema setUniqueItems(Boolean uniqueItems) { + this.uniqueItems = uniqueItems; + return this; + } + + public Integer getMaxProperties() { + return maxProperties; + } + + public Schema setMaxProperties(Integer maxProperties) { + this.maxProperties = maxProperties; + return this; + } + + public Integer getMinProperties() { + return minProperties; + } + + public Schema setMinProperties(Integer minProperties) { + this.minProperties = minProperties; + return this; + } + + public List getRequired() { + return required; + } + + public Schema setRequired(List required) { + this.required = required; + return this; + } + + public Schema addRequired(String required) { + if (this.required == null) { + this.required = new ArrayList<>(); + } + this.required.add(required); + return this; + } + + public Schema removeRequired(String required) { + if (this.required != null) { + this.required.remove(required); + } + return this; + } + + public List getEnumeration() { + return enumeration; + } + + public Schema setEnumeration(List enumeration) { + this.enumeration = enumeration; + return this; + } + + public Schema addEnumeration(Object enumeration) { + if (this.enumeration == null) { + this.enumeration = new ArrayList<>(); + } + this.enumeration.add(enumeration); + return this; + } + + public Schema removeEnumeration(Object enumeration) { + if (this.enumeration != null) { + this.enumeration.remove(enumeration); + } + return this; + } + + public Type getType() { + return type; + } + + public Schema setType(Type type) { + this.type = type; + return this; + } + + public Schema getItems() { + return items; + } + + public Schema setItems(Schema items) { + this.items = items; + return this; + } + + public Map getProperties() { + return properties; + } + + public Schema setProperties(Map properties) { + this.properties = properties; + return this; + } + + public Schema addProperty(String name, Schema schema) { + if (properties == null) { + properties = new LinkedHashMap<>(); + } + properties.put(name, schema); + return this; + } + + public Schema removeProperty(String name) { + if (properties != null) { + properties.remove(name); + } + return this; + } + + public Schema getAdditionalPropertiesSchema() { + return additionalPropertiesSchema; + } + + public Schema setAdditionalPropertiesSchema(Schema additionalPropertiesSchema) { + this.additionalPropertiesSchema = additionalPropertiesSchema; + return this; + } + + public Boolean getAdditionalPropertiesBoolean() { + return additionalPropertiesBoolean; + } + + public Schema setAdditionalPropertiesBoolean(Boolean additionalPropertiesBoolean) { + this.additionalPropertiesBoolean = additionalPropertiesBoolean; + return this; + } + + public Boolean getReadOnly() { + return readOnly; + } + + public Schema setReadOnly(Boolean readOnly) { + this.readOnly = readOnly; + return this; + } + + public XML getXml() { + return xml; + } + + public Schema setXml(XML xml) { + this.xml = xml; + return this; + } + + public ExternalDocs getExternalDocs() { + return externalDocs; + } + + public Schema setExternalDocs(ExternalDocs externalDocs) { + this.externalDocs = externalDocs; + return this; + } + + public Object getExample() { + return example; + } + + public Schema setExample(Object example) { + this.example = example; + return this; + } + + public List getAllOf() { + return allOf; + } + + public Schema setAllOf(List allOf) { + this.allOf = allOf; + return this; + } + + public Schema addAllOf(Schema schema) { + if (allOf == null) { + allOf = new ArrayList<>(); + } + allOf.add(schema); + return this; + } + + public List getOneOf() { + return oneOf; + } + + public Schema setOneOf(List oneOf) { + this.oneOf = oneOf; + return this; + } + + public Schema addOneOf(Schema schema) { + if (oneOf == null) { + oneOf = new ArrayList<>(); + } + oneOf.add(schema); + return this; + } + + public List getAnyOf() { + return anyOf; + } + + public Schema setAnyOf(List anyOf) { + this.anyOf = anyOf; + return this; + } + + public Schema addAnyOf(Schema schema) { + if (anyOf == null) { + anyOf = new ArrayList<>(); + } + anyOf.add(schema); + return this; + } + + public Schema getNot() { + return not; + } + + public Schema setNot(Schema not) { + this.not = not; + return this; + } + + public Discriminator getDiscriminator() { + return discriminator; + } + + public Schema setDiscriminator(Discriminator discriminator) { + this.discriminator = discriminator; + return this; + } + + public Boolean getNullable() { + return nullable; + } + + public Schema setNullable(Boolean nullable) { + this.nullable = nullable; + return this; + } + + public Boolean getWriteOnly() { + return writeOnly; + } + + public Schema setWriteOnly(Boolean writeOnly) { + this.writeOnly = writeOnly; + return this; + } + + public Boolean getDeprecated() { + return deprecated; + } + + public Schema setDeprecated(Boolean deprecated) { + this.deprecated = deprecated; + return this; + } + + @Override + public Schema clone() { + Schema clone = super.clone(); + if (required != null) { + clone.required = new ArrayList<>(required); + } + if (enumeration != null) { + clone.enumeration = new ArrayList<>(enumeration); + } + clone.items = clone(items); + clone.properties = clone(properties); + clone.additionalPropertiesSchema = clone(additionalPropertiesSchema); + clone.xml = clone(xml); + clone.externalDocs = clone(externalDocs); + clone.allOf = clone(allOf); + clone.oneOf = clone(oneOf); + clone.anyOf = clone(anyOf); + clone.not = clone(not); + clone.discriminator = clone(discriminator); + return clone; + } + + @Override + public Map writeTo(Map schema, WriteContext context) { + write(schema, "$ref", ref); + write(schema, "format", format); + write(schema, "name", name); + write(schema, "title", title); + write(schema, "description", description); + write(schema, "default", defaultValue); + write(schema, "multipleOf", multipleOf); + write(schema, "maximum", maximum); + write(schema, "exclusiveMaximum", exclusiveMaximum); + write(schema, "minimum", minimum); + write(schema, "exclusiveMinimum", exclusiveMinimum); + write(schema, "maxLength", maxLength); + write(schema, "minLength", minLength); + write(schema, "pattern", pattern); + write(schema, "maxItems", maxItems); + write(schema, "minItems", minItems); + write(schema, "uniqueItems", uniqueItems); + write(schema, "maxProperties", maxProperties); + write(schema, "minProperties", minProperties); + write(schema, "required", required); + write(schema, "enum", enumeration); + write(schema, "type", type); + write(schema, "items", items, context); + write(schema, "properties", properties, context); + if (additionalPropertiesBoolean == null) { + write(schema, "additionalProperties", additionalPropertiesSchema, context); + } else { + schema.put("additionalProperties", additionalPropertiesBoolean); + } + write(schema, "readOnly", readOnly); + write(schema, "xml", xml, context); + write(schema, "externalDocs", externalDocs, context); + write(schema, "example", example); + write(schema, "allOf", allOf, context); + write(schema, "oneOf", oneOf, context); + write(schema, "anyOf", anyOf, context); + write(schema, "not", not, context); + write(schema, "discriminator", discriminator, context); + write(schema, "nullable", nullable); + write(schema, "writeOnly", writeOnly); + write(schema, "deprecated", deprecated); + writeExtensions(schema); + return schema; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java new file mode 100644 index 00000000000..d7d1f206eba --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java @@ -0,0 +1,80 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public final class SecurityRequirement extends Node { + + private Map> requirements; + + public Map> getRequirements() { + return requirements; + } + + public void setRequirements(Map> requirements) { + this.requirements = requirements; + } + + public SecurityRequirement addRequirement(String name, String... scope) { + return addRequirement(name, scope == null ? Collections.emptyList() : Arrays.asList(scope)); + } + + public SecurityRequirement addRequirement(String name, List scopes) { + if (requirements == null) { + requirements = new LinkedHashMap<>(); + } + if (scopes == null) { + scopes = Collections.emptyList(); + } + requirements.put(name, scopes); + return this; + } + + public void removeRequirement(String name) { + if (requirements != null) { + requirements.remove(name); + } + } + + @Override + public SecurityRequirement clone() { + SecurityRequirement clone = super.clone(); + if (requirements != null) { + Map> requirements = newMap(this.requirements.size()); + for (Map.Entry> entry : this.requirements.entrySet()) { + requirements.put(entry.getKey(), new ArrayList<>(entry.getValue())); + } + clone.requirements = requirements; + } + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "requirements", requirements); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java new file mode 100644 index 00000000000..b068fc30f27 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java @@ -0,0 +1,161 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.Map; + +public final class SecurityScheme extends Node { + + public enum Type { + APIKEY("apiKey"), + HTTP("http"), + OAUTH2("oauth2"), + OPEN_ID_CONNECT("openIdConnect"); + + private final String value; + + Type(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + public enum In { + COOKIE("cookie"), + HEADER("header"), + QUERY("query"); + + private final String value; + + In(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + + private Type type; + private String description; + private String name; + private In in; + private String scheme; + private String bearerFormat; + private OAuthFlows flows; + private String openIdConnectUrl; + + public Type getType() { + return type; + } + + public SecurityScheme setType(Type type) { + this.type = type; + return this; + } + + public String getDescription() { + return description; + } + + public SecurityScheme setDescription(String description) { + this.description = description; + return this; + } + + public String getName() { + return name; + } + + public SecurityScheme setName(String name) { + this.name = name; + return this; + } + + public In getIn() { + return in; + } + + public SecurityScheme setIn(In in) { + this.in = in; + return this; + } + + public String getScheme() { + return scheme; + } + + public SecurityScheme setScheme(String scheme) { + this.scheme = scheme; + return this; + } + + public String getBearerFormat() { + return bearerFormat; + } + + public SecurityScheme setBearerFormat(String bearerFormat) { + this.bearerFormat = bearerFormat; + return this; + } + + public OAuthFlows getFlows() { + return flows; + } + + public SecurityScheme setFlows(OAuthFlows flows) { + this.flows = flows; + return this; + } + + public String getOpenIdConnectUrl() { + return openIdConnectUrl; + } + + public SecurityScheme setOpenIdConnectUrl(String openIdConnectUrl) { + this.openIdConnectUrl = openIdConnectUrl; + return this; + } + + @Override + public SecurityScheme clone() { + SecurityScheme clone = super.clone(); + clone.flows = clone(flows); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "type", type); + write(node, "description", description); + write(node, "name", name); + write(node, "in", in); + write(node, "scheme", scheme); + write(node, "bearerFormat", bearerFormat); + write(node, "flows", flows, context); + write(node, "openIdConnectUrl", openIdConnectUrl); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java new file mode 100644 index 00000000000..0f1deb9053a --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java @@ -0,0 +1,87 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.LinkedHashMap; +import java.util.Map; + +public final class Server extends Node { + + private String url; + private String description; + private Map variables; + + public String getUrl() { + return url; + } + + public Server setUrl(String url) { + this.url = url; + return this; + } + + public String getDescription() { + return description; + } + + public Server setDescription(String description) { + this.description = description; + return this; + } + + public Map getVariables() { + return variables; + } + + public Server setVariables(Map variables) { + this.variables = variables; + return this; + } + + public Server addVariable(String name, ServerVariable variable) { + if (variables == null) { + variables = new LinkedHashMap<>(); + } + variables.put(name, variable); + return this; + } + + public Server removeVariable(String name) { + if (variables != null) { + variables.remove(name); + } + return this; + } + + @Override + public Server clone() { + Server clone = super.clone(); + clone.variables = clone(variables); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "url", url); + write(node, "description", description); + write(node, "variables", variables, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java new file mode 100644 index 00000000000..e82074fcc3a --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java @@ -0,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.rpc.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public final class ServerVariable extends Node { + + private List enumeration; + private String defaultValue; + private String description; + + public List getEnumeration() { + return enumeration; + } + + public ServerVariable setEnumeration(List enumeration) { + this.enumeration = enumeration; + return this; + } + + public ServerVariable addEnumeration(String value) { + if (enumeration == null) { + enumeration = new ArrayList<>(); + } + enumeration.add(value); + return this; + } + + public ServerVariable removeEnumeration(String value) { + if (enumeration != null) { + enumeration.remove(value); + } + return this; + } + + public String getDefaultValue() { + return defaultValue; + } + + public ServerVariable setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + return this; + } + + public String getDescription() { + return description; + } + + public ServerVariable setDescription(String description) { + this.description = description; + return this; + } + + @Override + public ServerVariable clone() { + ServerVariable clone = super.clone(); + if (enumeration != null) { + clone.enumeration = new ArrayList<>(enumeration); + } + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + write(node, "enum", enumeration); + write(node, "default", defaultValue); + write(node, "description", description); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java new file mode 100644 index 00000000000..6b5ce936056 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java @@ -0,0 +1,71 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.Map; + +public final class Tag extends Node { + + private String name; + private String description; + private ExternalDocs externalDocs; + + public String getName() { + return name; + } + + public Tag setName(String name) { + this.name = name; + return this; + } + + public String getDescription() { + return description; + } + + public Tag setDescription(String description) { + this.description = description; + return this; + } + + public ExternalDocs getExternalDocs() { + return externalDocs; + } + + public Tag setExternalDocs(ExternalDocs externalDocs) { + this.externalDocs = externalDocs; + return this; + } + + @Override + public Tag clone() { + Tag clone = super.clone(); + clone.externalDocs = clone(externalDocs); + return clone; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + node.put("name", name); + node.put("description", description); + write(node, "externalDocs", externalDocs, context); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java new file mode 100644 index 00000000000..5df87dece44 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java @@ -0,0 +1,82 @@ +/* + * 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.protocol.tri.rest.openapi.model; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; + +import java.util.Map; + +public final class XML extends Node { + + private String name; + private String namespace; + private String prefix; + private Boolean attribute; + private Boolean wrapped; + + public String getName() { + return name; + } + + public XML setName(String name) { + this.name = name; + return this; + } + + public String getNamespace() { + return namespace; + } + + public XML setNamespace(String namespace) { + this.namespace = namespace; + return this; + } + + public String getPrefix() { + return prefix; + } + + public XML setPrefix(String prefix) { + this.prefix = prefix; + return this; + } + + public Boolean getAttribute() { + return attribute; + } + + public XML setAttribute(Boolean attribute) { + this.attribute = attribute; + return this; + } + + public Boolean getWrapped() { + return wrapped; + } + + public XML setWrapped(Boolean wrapped) { + this.wrapped = wrapped; + return this; + } + + @Override + public Map writeTo(Map node, WriteContext context) { + node.put("name", name); + writeExtensions(node); + return node; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java index 609446f826c..6213561a74d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java @@ -121,6 +121,9 @@ public static String combine(@Nonnull String path1, @Nonnull String path2) { boolean slash1 = last1 == '/'; boolean slash2 = path2.charAt(0) == '/'; + if (slash2 && path2.length() > 1 && path2.charAt(1) == '/') { + return path2.substring(1); + } if (slash1) { return slash2 ? path1 + path2.substring(1) : path1 + path2; } diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/pom.xml index 45e6e4a3b68..31e80c0b352 100644 --- a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/pom.xml @@ -217,6 +217,12 @@ true + + org.springframework.boot + spring-boot-configuration-processor + true + + org.springframework.boot diff --git a/dubbo-test/dubbo-dependencies-all/pom.xml b/dubbo-test/dubbo-dependencies-all/pom.xml index dd9b862abde..554c6cb50a1 100644 --- a/dubbo-test/dubbo-dependencies-all/pom.xml +++ b/dubbo-test/dubbo-dependencies-all/pom.xml @@ -251,6 +251,11 @@ dubbo-rest-spring ${project.version} + + org.apache.dubbo + dubbo-rest-swagger + ${project.version} + org.apache.dubbo dubbo-triple-servlet From 7d39d222027341f4b242e9c902be858626bf9d19 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Thu, 7 Nov 2024 09:32:16 +0800 Subject: [PATCH 02/23] Split openapi processing stages into separate classes --- .../dubbo/config/nested/OpenAPIConfig.java | 43 +- .../apache/dubbo/rpc/model/ScopeModel.java | 12 +- .../support/jaxrs/BeanArgumentBinder.java | 4 +- .../support/spring/BeanArgumentBinder.java | 4 +- .../spring/SpringResponseRestFilter.java | 4 +- .../support/spring/SpringRestToolKit.java | 4 +- .../protocol/tri/servlet/TripleFilter.java | 2 +- .../dubbo/remoting/http12/HttpMethods.java | 4 + .../remoting/http12/message/MediaType.java | 22 +- .../dubbo/remoting/http12/rest/OpenAPI.java | 7 +- .../dubbo/remoting/http12/rest/Operation.java | 9 +- .../rpc/protocol/tri/TripleProtocol.java | 2 +- .../h12/AbstractServerTransportListener.java | 2 +- .../tri/h12/ExceptionCustomizerWrapper.java | 2 +- .../rpc/protocol/tri/rest/RestConstants.java | 13 - .../rest/argument/GeneralTypeConverter.java | 8 +- .../tri/rest/mapping/ContentNegotiator.java | 16 +- .../DefaultRequestMappingRegistry.java | 10 +- .../mapping/RestRequestHandlerMapping.java | 12 +- .../mapping/condition/PathExpression.java | 2 +- .../tri/rest/mapping/meta/ParameterMeta.java | 5 + .../tri/rest/openapi/AbstractContext.java | 75 ++++ .../tri/rest/openapi/AnnotationResolver.java | 6 +- .../tri/rest/openapi/ConfigFactory.java | 168 ++++++++ .../protocol/tri/rest/openapi/Constants.java | 30 ++ .../protocol/tri/rest/openapi/Context.java | 47 +++ .../tri/rest/openapi/ContextImpl.java | 56 +++ .../rest/openapi/DefaultOpenAPIService.java | 274 +++++-------- .../tri/rest/openapi/DefinitionEncoder.java | 69 ++++ .../tri/rest/openapi/DefinitionFilter.java | 379 ++++++++++++++++++ .../tri/rest/openapi/DefinitionMerger.java | 119 ++++++ .../tri/rest/openapi/DefinitionResolver.java | 306 ++++++++++++++ ...iteContext.java => DocumentPublisher.java} | 10 +- .../tri/rest/openapi/ExtensionFactory.java | 75 ++++ .../rpc/protocol/tri/rest/openapi/Helper.java | 89 +++- .../tri/rest/openapi/NamingStrategy.java | 31 ++ .../tri/rest/openapi/OpenAPIFilter.java | 39 +- .../tri/rest/openapi/OpenAPIRequest.java | 9 +- .../tri/rest/openapi/ProtoEncoder.java | 20 +- .../tri/rest/openapi/ResolveContext.java | 29 +- .../tri/rest/openapi/ResolveContextImpl.java | 26 ++ .../tri/rest/openapi/SchemaFactory.java | 11 +- ...FilterContext.java => SchemaProvider.java} | 7 +- .../tri/rest/openapi/model/ApiResponse.java | 43 +- .../tri/rest/openapi/model/Components.java | 4 +- .../tri/rest/openapi/model/Contact.java | 4 +- .../tri/rest/openapi/model/Discriminator.java | 4 +- .../tri/rest/openapi/model/Encoding.java | 8 +- .../tri/rest/openapi/model/Example.java | 4 +- .../tri/rest/openapi/model/ExternalDocs.java | 4 +- .../tri/rest/openapi/model/Header.java | 8 +- .../protocol/tri/rest/openapi/model/Info.java | 4 +- .../tri/rest/openapi/model/License.java | 4 +- .../tri/rest/openapi/model/MediaType.java | 4 +- .../protocol/tri/rest/openapi/model/Node.java | 11 +- .../tri/rest/openapi/model/OAuthFlow.java | 4 +- .../tri/rest/openapi/model/OAuthFlows.java | 4 +- .../tri/rest/openapi/model/OpenAPI.java | 64 ++- .../tri/rest/openapi/model/Operation.java | 60 ++- .../tri/rest/openapi/model/Parameter.java | 41 +- .../tri/rest/openapi/model/PathItem.java | 8 +- .../tri/rest/openapi/model/RequestBody.java | 39 +- .../tri/rest/openapi/model/Schema.java | 4 +- .../openapi/model/SecurityRequirement.java | 4 +- .../rest/openapi/model/SecurityScheme.java | 4 +- .../tri/rest/openapi/model/Server.java | 4 +- .../rest/openapi/model/ServerVariable.java | 4 +- .../protocol/tri/rest/openapi/model/Tag.java | 4 +- .../protocol/tri/rest/openapi/model/XML.java | 4 +- .../support/basic/BeanArgumentBinder.java | 2 +- .../tri/rest/util/AbstractRestToolKit.java | 4 +- .../protocol/tri/rest/util/MethodWalker.java | 2 +- 72 files changed, 1975 insertions(+), 445 deletions(-) create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{WriteContext.java => DocumentPublisher.java} (75%) create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/NamingStrategy.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContextImpl.java rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{FilterContext.java => SchemaProvider.java} (83%) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java index 3267c661566..953078ca45b 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -100,17 +100,22 @@ public class OpenAPIConfig implements Serializable { /** * The default media types that are consumed. */ - private String[] defaultConsumesMediaType; + private String[] defaultConsumesMediaTypes; /** * The default media types that are produced. */ - private String[] defaultProducesMediaType; + private String[] defaultProducesMediaTypes; + + /** + * The default HTTP methods are used. + */ + private String[] defaultHttpMethods; /** * The default HTTP status codes are returned. */ - private String[] defaultHttpStatusCode; + private String[] defaultHttpStatusCodes; /** * The custom settings. @@ -229,28 +234,36 @@ public void setSchemaNameStrategy(String schemaNameStrategy) { this.schemaNameStrategy = schemaNameStrategy; } - public String[] getDefaultConsumesMediaType() { - return defaultConsumesMediaType; + public String[] getDefaultConsumesMediaTypes() { + return defaultConsumesMediaTypes; + } + + public void setDefaultConsumesMediaTypes(String[] defaultConsumesMediaTypes) { + this.defaultConsumesMediaTypes = defaultConsumesMediaTypes; + } + + public String[] getDefaultProducesMediaTypes() { + return defaultProducesMediaTypes; } - public void setDefaultConsumesMediaType(String[] defaultConsumesMediaType) { - this.defaultConsumesMediaType = defaultConsumesMediaType; + public void setDefaultProducesMediaTypes(String[] defaultProducesMediaTypes) { + this.defaultProducesMediaTypes = defaultProducesMediaTypes; } - public String[] getDefaultProducesMediaType() { - return defaultProducesMediaType; + public String[] getDefaultHttpMethods() { + return defaultHttpMethods; } - public void setDefaultProducesMediaType(String[] defaultProducesMediaType) { - this.defaultProducesMediaType = defaultProducesMediaType; + public void setDefaultHttpMethods(String[] defaultHttpMethods) { + this.defaultHttpMethods = defaultHttpMethods; } - public String[] getDefaultHttpStatusCode() { - return defaultHttpStatusCode; + public String[] getDefaultHttpStatusCodes() { + return defaultHttpStatusCodes; } - public void setDefaultHttpStatusCode(String[] defaultHttpStatusCode) { - this.defaultHttpStatusCode = defaultHttpStatusCode; + public void setDefaultHttpStatusCodes(String[] defaultHttpStatusCodes) { + this.defaultHttpStatusCodes = defaultHttpStatusCodes; } public Map getSettings() { diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java index 9e9d494a402..61b857f7569 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java @@ -38,6 +38,7 @@ import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_UNABLE_DESTROY_MODEL; +@SuppressWarnings({"unchecked", "rawtypes"}) public abstract class ScopeModel implements ExtensionAccessor { protected static final ErrorTypeAwareLogger LOGGER = LoggerFactory.getErrorTypeAwareLogger(ScopeModel.class); @@ -200,10 +201,18 @@ public ExtensionDirector getExtensionDirector() { return extensionDirector; } - public ScopeBeanFactory getBeanFactory() { + public final ScopeBeanFactory getBeanFactory() { return beanFactory; } + public final T getOrRegisterBean(Class type) { + return beanFactory.getOrRegisterBean(type); + } + + public final T getBean(Class type) { + return beanFactory.getBean(type); + } + public ScopeModel getParent() { return parent; } @@ -259,6 +268,7 @@ public Set getClassLoaders() { * @deprecated use modelEnvironment() instead */ @Deprecated + @SuppressWarnings("DeprecatedIsStillUsed") public final Environment getModelEnvironment() { try { return modelEnvironment(); diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java index 90f0da7955b..84cb8ffbf6f 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs; -import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.remoting.http12.HttpRequest; @@ -46,8 +45,7 @@ final class BeanArgumentBinder { private final ArgumentResolver argumentResolver; BeanArgumentBinder(FrameworkModel frameworkModel) { - ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); - argumentResolver = beanFactory.getOrRegisterBean(CompositeArgumentResolver.class); + argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); } public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) { diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java index d020e5425ab..7d340980755 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.support.spring; -import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.http12.HttpRequest; @@ -50,8 +49,7 @@ final class BeanArgumentBinder { private final ConversionService conversionService; BeanArgumentBinder(FrameworkModel frameworkModel, ConversionService conversionService) { - ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); - argumentResolver = beanFactory.getOrRegisterBean(CompositeArgumentResolver.class); + argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); this.conversionService = conversionService; } diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java index f182551087a..a354093f3f1 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java @@ -57,7 +57,7 @@ public class SpringResponseRestFilter implements RestFilter, Listener { private final Map> cache = CollectionUtils.newConcurrentHashMap(); public SpringResponseRestFilter(FrameworkModel frameworkModel) { - argumentResolver = frameworkModel.getBeanFactory().getOrRegisterBean(CompositeArgumentResolver.class); + argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); } @Override @@ -181,7 +181,7 @@ private static final class Key { } @Override - @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") + @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "EqualsDoesntCheckParameterClass"}) public boolean equals(Object obj) { Key other = (Key) obj; return method.equals(other.method) && type.equals(other.type); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java index c040e5914af..79254589a1a 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java @@ -83,8 +83,8 @@ public SpringRestToolKit(FrameworkModel frameworkModel) { } else { conversionService = DefaultConversionService.getSharedInstance(); } - typeConverter = frameworkModel.getBeanFactory().getOrRegisterBean(GeneralTypeConverter.class); - parameterNameReader = frameworkModel.getBeanFactory().getOrRegisterBean(DefaultParameterNameReader.class); + typeConverter = frameworkModel.getOrRegisterBean(GeneralTypeConverter.class); + parameterNameReader = frameworkModel.getOrRegisterBean(DefaultParameterNameReader.class); argumentBinder = new BeanArgumentBinder(frameworkModel, conversionService); } diff --git a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java index e93ed1cd09c..5802def926c 100644 --- a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java +++ b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java @@ -72,7 +72,7 @@ public class TripleFilter implements Filter { public void init(FilterConfig config) { FrameworkModel frameworkModel = FrameworkModel.defaultModel(); pathResolver = frameworkModel.getDefaultExtension(PathResolver.class); - mappingRegistry = frameworkModel.getBeanFactory().getOrRegisterBean(DefaultRequestMappingRegistry.class); + mappingRegistry = frameworkModel.getOrRegisterBean(DefaultRequestMappingRegistry.class); } @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java index 5b9644e5c39..0388606dfcd 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpMethods.java @@ -43,6 +43,10 @@ public boolean is(String name) { return name().equals(name); } + public boolean supportBody() { + return this == POST || this == PUT || this == PATCH; + } + @SuppressWarnings("StringEquality") public static HttpMethods of(String name) { // fast-path diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java index a43b1e4891e..13e25ec8c44 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java @@ -16,6 +16,8 @@ */ package org.apache.dubbo.remoting.http12.message; +import java.util.Objects; + public final class MediaType { public static final String WILDCARD = "*"; @@ -30,8 +32,6 @@ public final class MediaType { public static final MediaType APPLICATION_YAML = new MediaType("application", "yaml"); - public static final MediaType TEXT_PROTO = new MediaType("text", "proto"); - public static final MediaType APPLICATION_JAVASCRIPT = new MediaType("application", "javascript"); public static final MediaType APPLICATION_OCTET_STREAM = new MediaType("application", "octet-stream"); @@ -87,4 +87,22 @@ public String getSubType() { public boolean isPureText() { return TEXT.equals(type); } + + public static MediaType of(String name) { + Objects.requireNonNull(name); + if (APPLICATION_JSON.name.equals(name)) { + return APPLICATION_JSON; + } + if (APPLICATION_YAML.name.equals(name)) { + return APPLICATION_YAML; + } + if (APPLICATION_FROM_URLENCODED.name.equals(name)) { + return APPLICATION_FROM_URLENCODED; + } + int index = name.indexOf('/'); + if (index > 0) { + return new MediaType(name.substring(0, index), name.substring(index + 1)); + } + throw new IllegalArgumentException("Invalid media type: '" + name + "'"); + } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java index 17ea2490540..16d6b99302b 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java @@ -53,7 +53,7 @@ /** * The openAPI groups. */ - String[] groups() default {}; + String group() default ""; /** * The title of the application. @@ -79,4 +79,9 @@ * Ordering info. */ int order() default 0; + + /** + * The extensions of the OpenAPI. + */ + String[] extensions() default {}; } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java index 3cac2b11dba..cb5df99f658 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java @@ -16,8 +16,6 @@ */ package org.apache.dubbo.remoting.http12.rest; -import org.apache.dubbo.remoting.http12.HttpMethods; - import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -32,7 +30,7 @@ /** * The HTTP method for this operation. */ - HttpMethods[] method() default {}; + String method() default ""; /** * The operation tags. @@ -68,4 +66,9 @@ * Indicates whether the operation is hidden in OpenAPI. */ boolean hidden() default false; + + /** + * The extensions of the OpenAPI. + */ + String[] extensions() default {}; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java index 2df0c748d54..f3e53b25980 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java @@ -70,7 +70,7 @@ public TripleProtocol(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; triBuiltinService = new TriBuiltinService(frameworkModel); pathResolver = frameworkModel.getDefaultExtension(PathResolver.class); - mappingRegistry = frameworkModel.getBeanFactory().getOrRegisterBean(DefaultRequestMappingRegistry.class); + mappingRegistry = frameworkModel.getOrRegisterBean(DefaultRequestMappingRegistry.class); acceptEncodings = String.join(",", frameworkModel.getSupportedExtensions(DeCompressor.class)); // init env settings diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java index a6944a35108..be153abd880 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java @@ -73,7 +73,7 @@ protected AbstractServerTransportListener(FrameworkModel frameworkModel, URL url this.frameworkModel = frameworkModel; this.url = url; this.httpChannel = httpChannel; - requestRouter = frameworkModel.getBeanFactory().getOrRegisterBean(DefaultRequestRouter.class); + requestRouter = frameworkModel.getOrRegisterBean(DefaultRequestRouter.class); exceptionCustomizerWrapper = new ExceptionCustomizerWrapper(frameworkModel); headerFilters = frameworkModel .getExtensionLoader(HeaderFilter.class) diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/ExceptionCustomizerWrapper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/ExceptionCustomizerWrapper.java index ddb599f1cd5..b740de8ddf6 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/ExceptionCustomizerWrapper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/ExceptionCustomizerWrapper.java @@ -38,7 +38,7 @@ public final class ExceptionCustomizerWrapper { private boolean needWrap; public ExceptionCustomizerWrapper(FrameworkModel frameworkModel) { - exceptionHandler = frameworkModel.getBeanFactory().getOrRegisterBean(CompositeExceptionHandler.class); + exceptionHandler = frameworkModel.getOrRegisterBean(CompositeExceptionHandler.class); } public void setMetadata(RequestMetadata metadata) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java index fc368005345..bb754e24c32 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/RestConstants.java @@ -49,19 +49,6 @@ public final class RestConstants { /* Configuration Key */ public static final String CONFIG_PREFIX = "dubbo.protocol.triple.rest."; - public static final String SUFFIX_PATTERN_MATCH_KEY = CONFIG_PREFIX + "suffix-pattern-match"; - public static final String TRAILING_SLASH_MATCH_KEY = CONFIG_PREFIX + "trailing-slash-match"; - public static final String CASE_SENSITIVE_MATCH_KEY = CONFIG_PREFIX + "case-sensitive-match"; - public static final String FORMAT_PARAMETER_NAME_KEY = CONFIG_PREFIX + "format-parameter-name"; - - /* Cors Configuration Key */ - public static final String CORS_CONFIG_PREFIX = CONFIG_PREFIX + "cors."; - public static final String ALLOWED_ORIGINS = CORS_CONFIG_PREFIX + "allowed-origins"; - public static final String ALLOWED_METHODS = CORS_CONFIG_PREFIX + "allowed-methods"; - public static final String ALLOWED_HEADERS = CORS_CONFIG_PREFIX + "allowed-headers"; - public static final String ALLOW_CREDENTIALS = CORS_CONFIG_PREFIX + "allow-credentials"; - public static final String EXPOSED_HEADERS = CORS_CONFIG_PREFIX + "exposed-headers"; - public static final String MAX_AGE = CORS_CONFIG_PREFIX + "max-age"; private RestConstants() {} } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java index eaededb5f9f..c950aa64c15 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/GeneralTypeConverter.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.argument; -import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.common.io.StreamUtils; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -114,10 +113,9 @@ public class GeneralTypeConverter implements TypeConverter { private final HttpJsonUtils httpJsonUtils; public GeneralTypeConverter(FrameworkModel frameworkModel) { - ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); - converter = beanFactory.getOrRegisterBean(CompositeArgumentConverter.class); - codecUtils = beanFactory.getOrRegisterBean(CodecUtils.class); - httpJsonUtils = beanFactory.getOrRegisterBean(HttpJsonUtils.class); + converter = frameworkModel.getOrRegisterBean(CompositeArgumentConverter.class); + codecUtils = frameworkModel.getOrRegisterBean(CodecUtils.class); + httpJsonUtils = frameworkModel.getOrRegisterBean(HttpJsonUtils.class); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java index e0f53c91eba..c7cbec42b20 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java @@ -16,8 +16,8 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.mapping; -import org.apache.dubbo.common.config.Configuration; -import org.apache.dubbo.common.config.ConfigurationUtils; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpUtils; import org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory; @@ -31,8 +31,6 @@ import java.util.List; import java.util.Map; -import static org.apache.dubbo.config.nested.RestConfig.DEFAULT_FORMAT_PARAMETER_NAME; - public class ContentNegotiator { private final FrameworkModel frameworkModel; @@ -42,7 +40,7 @@ public class ContentNegotiator { public ContentNegotiator(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; - codecUtils = frameworkModel.getBeanFactory().getOrRegisterBean(CodecUtils.class); + codecUtils = frameworkModel.getOrRegisterBean(CodecUtils.class); } public String negotiate(HttpRequest request, HandlerMeta meta) { @@ -141,11 +139,11 @@ private String getSuitableMediaType(String name) { } public String getParameterName() { - String parameterName = this.parameterName; if (parameterName == null) { - Configuration conf = ConfigurationUtils.getGlobalConfiguration(frameworkModel.defaultApplication()); - parameterName = conf.getString(RestConstants.FORMAT_PARAMETER_NAME_KEY, DEFAULT_FORMAT_PARAMETER_NAME); - this.parameterName = parameterName; + parameterName = ConfigManager.getProtocolOrDefault(CommonConstants.TRIPLE) + .getTripleOrDefault() + .getRestOrDefault() + .getFormatParameterNameOrDefault(); } return parameterName; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java index ba570a5f174..13040756bfe 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java @@ -76,11 +76,13 @@ public DefaultRequestMappingRegistry(FrameworkModel frameworkModel) { } private void init(Invoker invoker) { - contentNegotiator = frameworkModel.getBeanFactory().getOrRegisterBean(ContentNegotiator.class); - openAPIService = frameworkModel.getBeanFactory().getOrRegisterBean(DefaultOpenAPIService.class); + contentNegotiator = frameworkModel.getOrRegisterBean(ContentNegotiator.class); + openAPIService = frameworkModel.getOrRegisterBean(DefaultOpenAPIService.class); openAPIService.setRequestMappingRegistry(this); resolvers = frameworkModel.getActivateExtensions(RequestMappingResolver.class); - restConfig = ConfigManager.getProtocolOrDefault(invoker.getUrl()).getTripleOrDefault().getRestOrDefault(); + restConfig = ConfigManager.getProtocolOrDefault(invoker.getUrl()) + .getTripleOrDefault() + .getRestOrDefault(); tree = new RadixTree<>(restConfig.getCaseSensitiveMatchOrDefault()); } @@ -128,7 +130,7 @@ public void register(Invoker invoker) { return; } RequestMapping methodMapping = resolver.resolve(methodMeta); - if (methodMapping == null) { + if (methodMapping == null || methodMapping.getPathCondition() == null) { return; } if (md == null) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java index 2057d8e3988..5428d1c8c8b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java @@ -17,7 +17,6 @@ package org.apache.dubbo.rpc.protocol.tri.rest.mapping; import org.apache.dubbo.common.URL; -import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -58,12 +57,11 @@ public final class RestRequestHandlerMapping implements RequestHandlerMapping { private final CodecUtils codecUtils; public RestRequestHandlerMapping(FrameworkModel frameworkModel) { - ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); - requestMappingRegistry = beanFactory.getOrRegisterBean(DefaultRequestMappingRegistry.class); - argumentResolver = beanFactory.getOrRegisterBean(CompositeArgumentResolver.class); - typeConverter = beanFactory.getOrRegisterBean(GeneralTypeConverter.class); - contentNegotiator = beanFactory.getOrRegisterBean(ContentNegotiator.class); - codecUtils = beanFactory.getOrRegisterBean(CodecUtils.class); + requestMappingRegistry = frameworkModel.getOrRegisterBean(DefaultRequestMappingRegistry.class); + argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); + typeConverter = frameworkModel.getOrRegisterBean(GeneralTypeConverter.class); + contentNegotiator = frameworkModel.getOrRegisterBean(ContentNegotiator.class); + codecUtils = frameworkModel.getOrRegisterBean(CodecUtils.class); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java index 06b48d4f09b..e769a6c4413 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java @@ -127,7 +127,7 @@ public String toString() { if (isDirect()) { return path; } - StringBuilder sb = new StringBuilder(32); + StringBuilder sb = new StringBuilder(path.length()); for (PathSegment segment : segments) { sb.append('/'); String value = segment.getValue(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java index 33f02fdb311..5698024a1c9 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java @@ -18,6 +18,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; @@ -121,6 +122,10 @@ public String getDescription() { return name; } + public ParamType getParamType() { + return ParamType.Param; + } + public abstract Class getType(); public abstract Type getGenericType(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java new file mode 100644 index 00000000000..2486f5a45f8 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java @@ -0,0 +1,75 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +import java.util.HashMap; +import java.util.Map; + +public abstract class AbstractContext { + + private final OpenAPI openAPI; + private final SchemaFactory schemaFactory; + private final ExtensionFactory extensionFactory; + + private Map attributes; + + AbstractContext(OpenAPI openAPI, SchemaFactory schemaFactory, ExtensionFactory extensionFactory) { + this.openAPI = openAPI; + this.schemaFactory = schemaFactory; + this.extensionFactory = extensionFactory; + } + + public final String getGroup() { + return openAPI.getGroup(); + } + + public final OpenAPI getOpenAPI() { + return openAPI; + } + + public final OpenAPIConfig getConfig() { + return openAPI.getConfig(); + } + + public final SchemaFactory getSchemaFactory() { + return schemaFactory; + } + + public final ExtensionFactory getExtensionFactory() { + return extensionFactory; + } + + @SuppressWarnings("unchecked") + public final T getAttribute(String name) { + return attributes == null ? null : (T) attributes.get(name); + } + + @SuppressWarnings("unchecked") + public final T removeAttribute(String name) { + return attributes == null ? null : (T) attributes.remove(name); + } + + public final void setAttribute(String name, Object value) { + if (attributes == null) { + attributes = new HashMap<>(); + } + attributes.put(name, value); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AnnotationResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AnnotationResolver.java index e6a0073e1a7..71c30f5a2b4 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AnnotationResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AnnotationResolver.java @@ -26,7 +26,11 @@ @SPI(scope = ExtensionScope.FRAMEWORK) public interface AnnotationResolver { + boolean hidden(ServiceMeta serviceMeta); + OpenAPI resolve(ServiceMeta serviceMeta); - Operation resolve(MethodMeta methodMeta, Operation operation, ResolveContext context); + boolean hidden(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context); + + Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java new file mode 100644 index 00000000000..d04d530eeb0 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java @@ -0,0 +1,168 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.config.Configuration; +import org.apache.dubbo.common.config.Environment; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.rpc.model.FrameworkModel; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public final class ConfigFactory { + + private static Map CONFIG_METHODS; + + private final FrameworkModel frameworkModel; + private volatile Map configMap; + + public ConfigFactory(FrameworkModel frameworkModel) { + this.frameworkModel = frameworkModel; + } + + public OpenAPIConfig getConfig(String group) { + return getConfigMap().get(group); + } + + public OpenAPIConfig getGlobalConfig() { + return getConfig(Constants.GLOBAL_GROUP); + } + + private Map getConfigMap() { + if (configMap == null) { + synchronized (this) { + if (configMap == null) { + configMap = readConfigMap(); + } + } + } + return configMap; + } + + private Map readConfigMap() { + Map map = new HashMap<>(); + + Environment environment = frameworkModel.defaultApplication().modelEnvironment(); + Configuration configuration = environment.getConfiguration(); + List> configMaps = environment.getConfigurationMaps(); + + Set allKeys = new HashSet<>(); + for (Map configMap : configMaps) { + for (String key : configMap.keySet()) { + if (key.startsWith(Constants.CONFIG_PREFIX)) { + allKeys.add(key); + } + } + } + + int len = Constants.CONFIG_PREFIX.length(); + for (String fullKey : allKeys) { + if (fullKey.length() > len) { + char c = fullKey.charAt(len); + String group, key; + if (c == '.') { + group = StringUtils.EMPTY_STRING; + key = fullKey.substring(len + 2); + } else if (c == 's') { + int end = fullKey.indexOf('.', len + 1); + group = fullKey.substring(len + 1, end); + key = fullKey.substring(end + 1); + } else { + continue; + } + applyConfigValue(map, group, key, configuration.getString(fullKey)); + } + } + return map; + } + + private static void applyConfigValue(Map map, String group, String key, String value) { + if (value == null) { + return; + } + + OpenAPIConfig config = map.computeIfAbsent(group, k -> new OpenAPIConfig()); + int index = key.indexOf("settings."); + if (index == 0) { + Map settings = config.getSettings(); + if (settings == null) { + config.setSettings(settings = new HashMap<>()); + } + settings.put(key.substring(9), value); + return; + } + + Map configMethods = CONFIG_METHODS; + if (configMethods == null) { + configMethods = new HashMap<>(); + for (Method method : OpenAPIConfig.class.getMethods()) { + String name = toConfigName(method); + if (name != null) { + configMethods.put(name, method); + } + } + CONFIG_METHODS = configMethods; + } + + Method method = configMethods.get(key); + if (method == null) { + return; + } + + Class valueType = method.getParameterTypes()[0]; + try { + if (valueType == String.class) { + method.invoke(config, value); + } else if (valueType == Boolean.class) { + method.invoke(config, Boolean.valueOf(value.toLowerCase())); + } else if (valueType.isArray()) { + method.invoke(config, new Object[] {StringUtils.tokenize(value)}); + } + } catch (Throwable ignored) { + } + } + + private static String toConfigName(Method method) { + if (method.getParameterCount() != 1) { + return null; + } + String name = method.getName(); + if (!name.startsWith("set")) { + return null; + } + int len = name.length(); + StringBuilder sb = new StringBuilder(len); + for (int i = 3; i < len; i++) { + char c = name.charAt(i); + if (Character.isUpperCase(c)) { + if (i > 3) { + sb.append('-'); + } + sb.append(Character.toLowerCase(c)); + } else { + sb.append(c); + } + } + return sb.toString(); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java new file mode 100644 index 00000000000..c7262593300 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java @@ -0,0 +1,30 @@ +/* + * 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.protocol.tri.rest.openapi; + +public final class Constants { + + public static final String VERSION_30 = "3.0.1"; + public static final String VERSION_31 = "3.1.0"; + + public static final String DEFAULT_GROUP = "default"; + public static final String GLOBAL_GROUP = ""; + + public static final String CONFIG_PREFIX = "dubbo.protocol.triple.rest.openapi"; + + private Constants() {} +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java new file mode 100644 index 00000000000..b94c8890d9e --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java @@ -0,0 +1,47 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +public interface Context { + + OpenAPIRequest getRequest(); + + HttpRequest getHttpRequest(); + + HttpResponse getHttpResponse(); + + String getGroup(); + + OpenAPI getOpenAPI(); + + OpenAPIConfig getConfig(); + + SchemaFactory getSchemaFactory(); + + ExtensionFactory getExtensionFactory(); + + T getAttribute(String name); + + T removeAttribute(String name); + + void setAttribute(String name, Object value); +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java new file mode 100644 index 00000000000..0bd53ccacd2 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java @@ -0,0 +1,56 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.rpc.RpcContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +final class ContextImpl extends AbstractContext implements Context { + + private final OpenAPIRequest request; + + private HttpRequest httpRequest; + private HttpResponse httpResponse; + + ContextImpl(OpenAPI openAPI, SchemaFactory schemaFactory, ExtensionFactory extFactory, OpenAPIRequest request) { + super(openAPI, schemaFactory, extFactory); + this.request = request; + } + + @Override + public OpenAPIRequest getRequest() { + return request; + } + + @Override + public HttpRequest getHttpRequest() { + if (httpRequest == null) { + httpRequest = RpcContext.getServiceContext().getRequest(HttpRequest.class); + } + return httpRequest; + } + + @Override + public HttpResponse getHttpResponse() { + if (httpResponse == null) { + httpResponse = RpcContext.getServiceContext().getResponse(HttpResponse.class); + } + return httpResponse; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index fde71c26927..49101dd9374 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -16,229 +16,139 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; -import org.apache.dubbo.common.resource.Disposable; -import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.remoting.http12.HttpMethods; -import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException; -import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; -import org.apache.dubbo.remoting.http12.message.codec.JsonCodec; -import org.apache.dubbo.remoting.http12.message.codec.YamlCodec; +import org.apache.dubbo.common.logger.FluentLogger; +import org.apache.dubbo.common.utils.LRUCache; +import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.Registration; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingRegistry; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.*; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -import java.io.ByteArrayOutputStream; +import java.lang.ref.SoftReference; import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.Map.Entry; - -public class DefaultOpenAPIService implements OpenAPIService, Disposable { - - private final List annotationResolvers; - private final List extensions; - private final SchemaFactory schemaFactory = new SchemaFactory(); - private final Map, List> extensionsCache = CollectionUtils.newConcurrentHashMap(); - - private Map, OpenAPI> openAPIMap; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +public class DefaultOpenAPIService implements OpenAPIService { + + private static final FluentLogger LOG = FluentLogger.of(DefaultOpenAPIService.class); + + private final ExtensionFactory extensionFactory; + private final DefinitionResolver definitionResolver; + private final DefinitionMerger definitionMerger; + private final DefinitionFilter definitionFilter; + private final DefinitionEncoder definitionEncoder; private RequestMappingRegistry requestMappingRegistry; + private final LRUCache> cache; + private volatile List openAPIs; + public DefaultOpenAPIService(FrameworkModel frameworkModel) { - annotationResolvers = frameworkModel.getActivateExtensions(AnnotationResolver.class); - extensions = frameworkModel.getActivateExtensions(OpenAPIExtension.class); + extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + definitionResolver = new DefinitionResolver(frameworkModel); + definitionMerger = new DefinitionMerger(frameworkModel); + definitionFilter = new DefinitionFilter(frameworkModel); + definitionEncoder = new DefinitionEncoder(frameworkModel); + cache = new LRUCache<>(64); } public void setRequestMappingRegistry(RequestMappingRegistry requestMappingRegistry) { this.requestMappingRegistry = requestMappingRegistry; } - @SuppressWarnings({"unchecked", "rawtypes"}) - private List getExtensions(Class clazz) { - return (List) extensionsCache.computeIfAbsent(clazz, k -> { - List list = new ArrayList<>(); - for (OpenAPIExtension extension : extensions) { - if (clazz.isInstance(extension)) { - list.add(extension); - } - } - return list; - }); - } - @Override public OpenAPI getOpenAPI(OpenAPIRequest request) { - Collection registrations = requestMappingRegistry.getRegistrations(); - Map, ServiceMeta> serviceMetaMap = new HashMap<>(); - for (Registration registration : registrations) { - ServiceMeta serviceMeta = registration.getMeta().getService(); - serviceMetaMap.putIfAbsent(serviceMeta.getType(), serviceMeta); - } - - Map, OpenAPI> openAPIMap = new IdentityHashMap<>(); - out: - for (Entry, ServiceMeta> entry : serviceMetaMap.entrySet()) { - for (int i = 0, size = annotationResolvers.size(); i < size; i++) { - OpenAPI openAPI = annotationResolvers.get(i).resolve(entry.getValue()); - if (openAPI == null) { - continue; + if (openAPIs == null) { + synchronized (this) { + if (openAPIs == null) { + openAPIs = resolveOpenAPIs(); } - openAPIMap.put(entry.getKey(), openAPI); - continue out; } } + return definitionFilter.filter(definitionMerger.merge(openAPIs, request), request); + } - Map> registrationsGroupMap = new IdentityHashMap<>(registrations.size()); - for (Registration registration : registrations) { - registrationsGroupMap - .computeIfAbsent(registration.getMeta().getMethod().getMethod(), k -> new ArrayList<>(1)) + private List resolveOpenAPIs() { + Map>> byClassMap = new HashMap<>(); + for (Registration registration : requestMappingRegistry.getRegistrations()) { + HandlerMeta meta = registration.getMeta(); + byClassMap + .computeIfAbsent(new Key(meta.getService()), k -> new IdentityHashMap<>()) + .computeIfAbsent(meta.getMethod().getMethod(), k -> new ArrayList<>(1)) .add(registration); } - - ResolveContext context = new ResolveContext(schemaFactory); - out: - for (List registrationsGroup : registrationsGroupMap.values()) { - String mainPath = null; - for (int i = 0, size = registrationsGroup.size(); i < size; i++) { - Registration registration = registrationsGroup.get(i); - HandlerMeta meta = registration.getMeta(); - OpenAPI openAPI = openAPIMap.get(meta.getService().getType()); - if (openAPI == null) { - continue out; - } - RequestMapping mapping = registration.getMapping(); - List expressions = mapping.getPathCondition().getExpressions(); - for (int j = 0, len = expressions.size(); j < len; j++) { - PathExpression expression = expressions.get(j); - String path = Helper.resolvePath(expression); - PathItem pathItem = openAPI.getOrAddPath(path); - if (pathItem.getRef() != null) { - path = pathItem.getRef(); - pathItem = openAPI.getOrAddPath(path); - } - if (mainPath == null) { - mainPath = path; - Set methods = mapping.getMethodsCondition().getMethods(); - for (String method : methods) { - HttpMethods httpMethod = HttpMethods.of(method); - Operation operation = pathItem.getOrAddOperation(httpMethod); - operation.setMeta(meta.getMethod()); - resolveOperation(openAPI, httpMethod, operation, expression, mapping, meta, context); - } - } else { - pathItem.setRef(Helper.pathToRef(mainPath)); - } - } + List openAPIs = new ArrayList<>(byClassMap.size()); + for (Map.Entry>> entry : byClassMap.entrySet()) { + OpenAPI openAPI = definitionResolver.resolve( + entry.getKey().serviceMeta, entry.getValue().values()); + if (openAPI != null) { + openAPIs.add(openAPI); } } - return null; + openAPIs.sort(Comparator.comparingInt(OpenAPI::getPriority)); + return openAPIs; } - private void resolveOperation( - OpenAPI openAPI, - HttpMethods method, - Operation operation, - PathExpression expression, - RequestMapping mapping, - HandlerMeta meta, - ResolveContext context) { - operation.setOperationId(meta.getMethodDescriptor().getMethodName()); - for (ParameterMeta paramMeta : meta.getMethod().getParameters()) { - Parameter parameter = resolveParameter(paramMeta); - if (parameter != null) { - operation.addParameter(parameter); + @Override + public String getDocument(OpenAPIRequest request) { + String cacheKey = request.toString(); + SoftReference ref = cache.get(cacheKey); + if (ref != null) { + String value = ref.get(); + if (value != null) { + return value; } } - resolveRequestBody(operation, mapping, meta); - for (String httpStatus : new String[] {"200", "500"}) { - resolveResponse(operation, httpStatus, mapping, meta); - } - } - - private Parameter resolveParameter(ParameterMeta paramMeta) { - if (paramMeta == null) { - return null; - } - Parameter parameter = new Parameter(); - parameter.setMeta(paramMeta); - return parameter; + String value = definitionEncoder.encode(getOpenAPI(request), request); + cache.put(cacheKey, new SoftReference<>(value)); + return value; } - private void resolveRequestBody(Operation operation, RequestMapping mapping, HandlerMeta meta) { - RequestBody body = new RequestBody(); - List mediaTypes = - mapping.getConsumesCondition().getMediaTypes(); - for (org.apache.dubbo.remoting.http12.message.MediaType mediaType : mediaTypes) { - MediaType mediaTypeModel = new MediaType(); - mediaTypeModel.setSchema(resolveSchema(meta.getMethod().getMethod().getParameterTypes()[0])); - body.addContent(mediaType.getName(), mediaTypeModel); - } - operation.setRequestBody(body); + @Override + public void refresh() { + LOG.debug("Refreshing OpenAPI documents"); + openAPIs = null; + cache.clear(); } - private void resolveResponse(Operation operation, String httpStatus, RequestMapping mapping, HandlerMeta meta) { - ApiResponse response = new ApiResponse(); - List mediaTypes = - mapping.getProducesCondition().getMediaTypes(); - for (org.apache.dubbo.remoting.http12.message.MediaType mediaType : mediaTypes) { - MediaType mediaTypeModel = new MediaType(); - mediaTypeModel.setSchema(resolveSchema(meta.getMethod().getReturnType())); - response.addContent(mediaType.getName(), mediaTypeModel); + @Override + public void export() { + for (DocumentPublisher publisher : extensionFactory.getExtensions(DocumentPublisher.class)) { + try { + publisher.publish(request -> { + OpenAPI openAPI = getOpenAPI(request); + String document = definitionEncoder.encode(openAPI, request); + return Pair.of(openAPI, document); + }); + } catch (Throwable t) { + LOG.internalWarn("Failed to publish OpenAPI document by {}", publisher, t); + } } - operation.addResponse(httpStatus, response); } - private Schema resolveSchema(Class returnType) { - return null; - } + private static final class Key { - @Override - public String getDocument(OpenAPIRequest request) { - Map document = new LinkedHashMap<>(); - OpenAPI openAPI = getOpenAPI(request); - openAPI.writeTo(document, new WriteContext() {}); - - HttpMessageEncoder encoder = getEncoder(request); - ByteArrayOutputStream os = new ByteArrayOutputStream(1024); - encoder.encode(os, document, StandardCharsets.UTF_8); - return new String(os.toByteArray(), StandardCharsets.UTF_8); - } + private final ServiceMeta serviceMeta; - private static HttpMessageEncoder getEncoder(OpenAPIRequest request) { - String format = request.getFormat(); - format = format == null ? "json" : format.toLowerCase(); - HttpMessageEncoder encoder; - switch (format) { - case "json": - encoder = JsonCodec.INSTANCE; - break; - case "yml": - case "yaml": - encoder = YamlCodec.INSTANCE; - break; - case "proto": - encoder = ProtoEncoder.INSTANCE; - break; - default: - throw new UnsupportedMediaTypeException("application/" + format); + public Key(ServiceMeta serviceMeta) { + this.serviceMeta = serviceMeta; } - return encoder; - } - - @Override - public void refresh() { - this.openAPIMap = null; - } - @Override - public void export() {} + @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "EqualsDoesntCheckParameterClass"}) + @Override + public boolean equals(Object obj) { + return serviceMeta.getType() == ((Key) obj).serviceMeta.getType(); + } - @Override - public void destroy() { + @Override + public int hashCode() { + return serviceMeta.getType().hashCode(); + } } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java new file mode 100644 index 00000000000..61fed4ead19 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java @@ -0,0 +1,69 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException; +import org.apache.dubbo.remoting.http12.message.codec.YamlCodec; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import java.util.Map; + +final class DefinitionEncoder { + + private final ExtensionFactory extensionFactory; + private final SchemaFactory schemaFactory; + + private ProtoEncoder protoEncoder; + + DefinitionEncoder(FrameworkModel frameworkModel) { + extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + schemaFactory = frameworkModel.getOrRegisterBean(SchemaFactory.class); + } + + public String encode(OpenAPI openAPI, OpenAPIRequest request) { + Map root = new LinkedHashMap<>(); + ContextImpl context = new ContextImpl(openAPI, schemaFactory, extensionFactory, request); + openAPI.writeTo(root, context); + + String format = request.getFormat(); + format = format == null ? "json" : format.toLowerCase(); + switch (format) { + case "json": + if (Boolean.TRUE.equals(request.getPretty())) { + return JsonUtils.toPrettyJson(root); + } + return JsonUtils.toJson(root); + case "yml": + case "yaml": + ByteArrayOutputStream os = new ByteArrayOutputStream(4096); + YamlCodec.INSTANCE.encode(os, root, StandardCharsets.UTF_8); + return new String(os.toByteArray(), StandardCharsets.UTF_8); + case "proto": + if (protoEncoder == null) { + protoEncoder = new ProtoEncoder(); + } + return protoEncoder.encode(openAPI); + default: + throw new UnsupportedMediaTypeException("application/" + format); + } + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java new file mode 100644 index 00000000000..ba6166f696d --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java @@ -0,0 +1,379 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Components; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Header; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Node; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme; + +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Consumer; +import java.util.function.Supplier; + +final class DefinitionFilter { + + private final ExtensionFactory extensionFactory; + private final SchemaFactory schemaFactory; + + public DefinitionFilter(FrameworkModel frameworkModel) { + extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + schemaFactory = frameworkModel.getOrRegisterBean(SchemaFactory.class); + } + + public OpenAPI filter(OpenAPI openAPI, OpenAPIRequest request) { + OpenAPIFilter[] filters = extensionFactory.getExtensions(OpenAPIFilter.class, request.getGroup()); + if (filters.length == 0) { + return openAPI; + } + + Context context = new ContextImpl(openAPI, schemaFactory, extensionFactory, request); + for (OpenAPIFilter filter : filters) { + openAPI = filter.filterOpenAPI(openAPI, context); + if (openAPI == null) { + return null; + } + } + + filterPaths(openAPI, filters, context); + + filterComponents(openAPI, filters, context); + + for (OpenAPIFilter filter : filters) { + openAPI = filter.filterOpenAPICompletion(openAPI, context); + if (openAPI == null) { + return null; + } + } + + return openAPI; + } + + private void filterPaths(OpenAPI openAPI, OpenAPIFilter[] filters, Context context) { + Map paths = openAPI.getPaths(); + if (paths == null) { + return; + } + + Iterator> it = paths.entrySet().iterator(); + out: + while (it.hasNext()) { + Entry entry = it.next(); + PathItem pathItem = entry.getValue(); + PathItem initialPathItem = pathItem; + for (OpenAPIFilter filter : filters) { + pathItem = filter.filterPathItem(entry.getKey(), pathItem, context); + if (pathItem == null) { + it.remove(); + continue out; + } + } + if (pathItem != initialPathItem) { + entry.setValue(pathItem); + } + + filterOperation(pathItem, filters, context); + } + } + + private void filterOperation(PathItem pathItem, OpenAPIFilter[] filters, Context context) { + Map operations = pathItem.getOperations(); + if (operations == null) { + return; + } + + Iterator> it = operations.entrySet().iterator(); + out: + while (it.hasNext()) { + Entry entry = it.next(); + HttpMethods httpMethod = entry.getKey(); + Operation operation = entry.getValue(); + Operation initialOperation = operation; + for (OpenAPIFilter filter : filters) { + operation = filter.filterOperation(httpMethod, operation, pathItem, context); + if (operation == null) { + it.remove(); + continue out; + } + } + if (operation != initialOperation) { + entry.setValue(operation); + } + + filterParameter(operation, filters, context); + filterRequestBody(operation, filters, context); + filterResponse(operation, filters, context); + } + } + + private void filterParameter(Operation operation, OpenAPIFilter[] filters, Context context) { + List parameters = operation.getParameters(); + if (parameters == null) { + return; + } + + ListIterator it = parameters.listIterator(); + out: + while (it.hasNext()) { + Parameter parameter = it.next(); + Parameter initialParameter = parameter; + for (OpenAPIFilter filter : filters) { + parameter = filter.filterParameter(parameter, operation, context); + if (parameter == null) { + it.remove(); + continue out; + } + } + if (parameter != initialParameter) { + it.set(parameter); + } + + filterContext(parameter.getContent(), filters, context); + } + } + + private void filterRequestBody(Operation operation, OpenAPIFilter[] filters, Context context) { + RequestBody body = operation.getRequestBody(); + if (body == null) { + return; + } + + RequestBody initialRequestBody = body; + for (OpenAPIFilter filter : filters) { + body = filter.filterRequestBody(body, operation, context); + if (body == null) { + operation.setRequestBody(null); + return; + } + } + if (body != initialRequestBody) { + operation.setRequestBody(body); + } + + filterContext(body.getContents(), filters, context); + } + + private void filterResponse(Operation operation, OpenAPIFilter[] filters, Context context) { + Map responses = operation.getResponses(); + if (responses == null) { + return; + } + + Iterator> it = responses.entrySet().iterator(); + out: + while (it.hasNext()) { + Entry entry = it.next(); + ApiResponse response = entry.getValue(); + ApiResponse initialApiResponse = response; + for (OpenAPIFilter filter : filters) { + response = filter.filterResponse(response, operation, context); + if (response == null) { + it.remove(); + continue out; + } + } + if (response != initialApiResponse) { + entry.setValue(response); + } + + filterHeader(response, operation, filters, context); + filterContext(response.getContents(), filters, context); + } + } + + private void filterHeader(ApiResponse response, Operation operation, OpenAPIFilter[] filters, Context context) { + Map headers = response.getHeaders(); + if (headers == null) { + return; + } + + Iterator> it = headers.entrySet().iterator(); + out: + while (it.hasNext()) { + Entry entry = it.next(); + Header header = entry.getValue(); + Header initialHeader = header; + for (OpenAPIFilter filter : filters) { + header = filter.filterHeader(header, response, operation, context); + if (header == null) { + it.remove(); + continue out; + } + } + if (header != initialHeader) { + entry.setValue(header); + } + + filterSchema(header::getSchema, header::setSchema, header, filters, context); + + Map contents = header.getContent(); + if (contents == null) { + continue; + } + + for (MediaType mediaType : contents.values()) { + filterSchema(mediaType::getSchema, mediaType::setSchema, mediaType, filters, context); + } + } + } + + private boolean filterContext(Map contents, OpenAPIFilter[] filters, Context context) { + if (contents == null) { + return true; + } + + for (MediaType mediaType : contents.values()) { + filterSchema(mediaType::getSchema, mediaType::setSchema, mediaType, filters, context); + } + return false; + } + + private void filterComponents(OpenAPI openAPI, OpenAPIFilter[] filters, Context context) { + Components components = openAPI.getComponents(); + if (components == null) { + return; + } + + filterSchemas(components, filters, context); + filterSecuritySchemes(components, filters, context); + } + + private void filterSchemas(Components components, OpenAPIFilter[] filters, Context context) { + if (components == null) { + return; + } + + Map schemas = components.getSchemas(); + if (schemas == null) { + return; + } + + for (Entry entry : schemas.entrySet()) { + filterSchema(entry::getValue, entry::setValue, components, filters, context); + } + } + + private void filterSchema( + Supplier getter, Consumer setter, Node node, OpenAPIFilter[] filters, Context context) { + Schema schema = getter.get(); + if (schema == null) { + return; + } + + Schema initialSchema = schema; + for (OpenAPIFilter filter : filters) { + schema = filter.filterSchema(schema, node, context); + if (schema == null) { + setter.accept(null); + return; + } + } + if (schema != initialSchema) { + setter.accept(schema); + } + + filterSchema(schema::getItems, schema::setItems, schema, filters, context); + + Map properties = schema.getProperties(); + if (properties != null) { + out: + for (Entry entry : properties.entrySet()) { + String name = entry.getKey(); + Schema valueSchema = entry.getValue(); + for (OpenAPIFilter filter : filters) { + valueSchema = filter.filterSchemaProperty(name, valueSchema, schema, context); + if (valueSchema == null) { + entry.setValue(null); + continue out; + } + } + + filterSchema(entry::getValue, entry::setValue, schema, filters, context); + } + } + + filterSchema( + schema::getAdditionalPropertiesSchema, schema::setAdditionalPropertiesSchema, schema, filters, context); + + List allOf = schema.getAllOf(); + if (allOf != null) { + ListIterator it = allOf.listIterator(); + while (it.hasNext()) { + filterSchema(it::next, it::set, schema, filters, context); + } + } + + List oneOf = schema.getOneOf(); + if (oneOf != null) { + ListIterator it = oneOf.listIterator(); + while (it.hasNext()) { + filterSchema(it::next, it::set, schema, filters, context); + } + } + + List anyOf = schema.getAnyOf(); + if (anyOf != null) { + ListIterator it = anyOf.listIterator(); + while (it.hasNext()) { + filterSchema(it::next, it::set, schema, filters, context); + } + } + } + + private void filterSecuritySchemes(Components components, OpenAPIFilter[] filters, Context context) { + if (components == null) { + return; + } + + Map securitySchemes = components.getSecuritySchemes(); + if (securitySchemes == null) { + return; + } + + Iterator> it = securitySchemes.entrySet().iterator(); + out: + while (it.hasNext()) { + Entry entry = it.next(); + SecurityScheme securityScheme = entry.getValue(); + SecurityScheme initialSecurityScheme = securityScheme; + for (OpenAPIFilter filter : filters) { + securityScheme = filter.filterSecurityScheme(securityScheme, context); + if (securityScheme == null) { + it.remove(); + continue out; + } + } + if (securityScheme != initialSecurityScheme) { + entry.setValue(securityScheme); + } + } + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java new file mode 100644 index 00000000000..44fe3a88e05 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -0,0 +1,119 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +final class DefinitionMerger { + + private final ExtensionFactory extensionFactory; + private final ConfigFactory configFactory; + + DefinitionMerger(FrameworkModel frameworkModel) { + extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); + } + + public OpenAPI merge(List openAPIs, OpenAPIRequest request) { + OpenAPI result = new OpenAPI(); + + if (openAPIs.isEmpty()) { + return result; + } + + String group = trim(request.getGroup()); + if (group == null) { + group = Constants.DEFAULT_GROUP; + } + String[] tagArray = trim(request.getTags()); + Set tags = tagArray == null ? null : new HashSet<>(Arrays.asList(tagArray)); + String service = trim(request.getService()); + + for (OpenAPI api : openAPIs) { + + result.setOpenapi(api.getOpenapi()); + result.setInfo(api.getInfo()); + result.setServers(api.getServers()); + result.setComponents(api.getComponents()); + result.setSecurity(api.getSecurity()); + result.setTags(api.getTags()); + result.setExternalDocs(api.getExternalDocs()); + result.setGroup(api.getGroup()); + result.setPriority(api.getPriority()); + } + + String version = request.getVersion(); + if (version == null) { + version = result.getOpenapi(); + } + if (version == null) { + version = Constants.VERSION_30; + } else { + if (version.startsWith("3.0")) { + version = Constants.VERSION_30; + } else if (version.startsWith("3.1")) { + version = Constants.VERSION_31; + } + } + result.setOpenapi(version); + + return result; + } + + private void mergeInfo(OpenAPI result, List openAPIs) { + if (openAPIs.size() == 1) { + result.setInfo(openAPIs.get(0).getInfo()); + return; + } + + for (OpenAPI api : openAPIs) { + if (api.getInfo() != null) { + result.setInfo(api.getInfo()); + return; + } + } + } + + public static String trim(String str) { + return str == null || str.isEmpty() ? null : str.trim(); + } + + public static String[] trim(String[] array) { + if (array == null) { + return null; + } + int len = array.length; + if (len == 0) { + return null; + } + int p = 0; + for (int i = 0; i < len; i++) { + String value = trim(array[i]); + if (value != null) { + array[p++] = value; + } + } + int newLen = p + 1; + return newLen == len ? array : Arrays.copyOf(array, newLen); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java new file mode 100644 index 00000000000..56824842706 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -0,0 +1,306 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.logger.FluentLogger; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.remoting.http12.ErrorResponse; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http12.HttpUtils; +import org.apache.dubbo.remoting.http12.message.MediaType; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.Registration; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathCondition; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +final class DefinitionResolver { + + private static final FluentLogger LOG = FluentLogger.of(DefaultOpenAPIService.class); + + private final List annotationResolvers; + private final ExtensionFactory extensionFactory; + private final ConfigFactory configFactory; + private final SchemaFactory schemaFactory; + + DefinitionResolver(FrameworkModel frameworkModel) { + annotationResolvers = frameworkModel.getActivateExtensions(AnnotationResolver.class); + extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); + schemaFactory = frameworkModel.getOrRegisterBean(SchemaFactory.class); + } + + public OpenAPI resolve(ServiceMeta serviceMeta, Collection> registrationsByMethod) { + OpenAPI openAPI = null; + List resolvers = annotationResolvers; + for (int i = 0, size = resolvers.size(); i < size; i++) { + AnnotationResolver resolver = resolvers.get(i); + if (resolver.hidden(serviceMeta)) { + return null; + } + openAPI = resolver.resolve(serviceMeta); + if (openAPI != null) { + break; + } + } + if (openAPI == null) { + openAPI = new OpenAPI(); + } + if (StringUtils.isEmpty(openAPI.getGroup())) { + openAPI.setGroup(Constants.DEFAULT_GROUP); + } + openAPI.setGlobalConfig(configFactory.getGlobalConfig()); + openAPI.setConfig(configFactory.getConfig(openAPI.getGroup())); + openAPI.setService(serviceMeta); + + ResolveContext context = new ResolveContextImpl(openAPI, schemaFactory, extensionFactory); + for (List registrations : registrationsByMethod) { + String mainPath = null; + for (Registration registration : registrations) { + RequestMapping mapping = registration.getMapping(); + PathCondition pathCondition = mapping.getPathCondition(); + if (pathCondition == null) { + continue; + } + for (PathExpression expression : pathCondition.getExpressions()) { + String path = Helper.toPathValue(expression); + PathItem pathItem = openAPI.getOrAddPath(path); + String ref = pathItem.getRef(); + if (ref != null) { + path = ref; + pathItem = openAPI.getOrAddPath(path); + } + if (mainPath != null) { + pathItem.setRef(mainPath); + continue; + } + MethodMeta methodMeta = registration.getMeta().getMethod(); + if (resolvePath(path, pathItem, openAPI, methodMeta, mapping, context)) { + mainPath = path; + } + } + } + } + + return openAPI; + } + + private boolean resolvePath( + String path, + PathItem pathItem, + OpenAPI openAPI, + MethodMeta meta, + RequestMapping mapping, + ResolveContext context) { + Operation operation = null; + Collection httpMethods = null; + List resolvers = annotationResolvers; + for (int i = 0, size = resolvers.size(); i < size; i++) { + AnnotationResolver resolver = resolvers.get(i); + if (resolver.hidden(meta, openAPI, context)) { + return false; + } + operation = resolver.resolve(meta, openAPI, context); + if (operation == null) { + continue; + } + if (operation.getHttpMethod() != null) { + httpMethods = + Collections.singletonList(operation.getHttpMethod().name()); + } + } + + if (httpMethods == null) { + if (mapping.getMethodsCondition() != null) { + httpMethods = mapping.getMethodsCondition().getMethods(); + } + if (httpMethods == null) { + String[] defaultHttpMethods = openAPI.getConfigValue(OpenAPIConfig::getDefaultHttpMethods); + if (defaultHttpMethods == null) { + httpMethods = Helper.guessHttpMethod(meta); + } else { + httpMethods = Arrays.asList(defaultHttpMethods); + } + } + } + + for (String hm : httpMethods) { + HttpMethods httpMethod = HttpMethods.of(hm.toUpperCase()); + Operation existsOperation = pathItem.getOperation(httpMethod); + if (existsOperation == null) { + if (operation == null) { + operation = new Operation(); + } + pathItem.addOperation(httpMethod, operation); + } else { + if (existsOperation.getMethod() != null) { + LOG.internalWarn("Operation already exists, path='{}', httpMethod='{}', method={}", path, hm, meta); + } + continue; + } + operation.setMethod(meta); + resolveOperation(httpMethod, operation, openAPI, meta, mapping); + } + return true; + } + + private void resolveOperation( + HttpMethods httpMethod, Operation operation, OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) { + if (operation.getOperationId() == null) { + String operationId = generateOperationId(meta, openAPI); + operation.setOperationId(operationId == null ? meta.getMethod().getName() : operationId); + } + if (operation.getDeprecated() == null && meta.isHierarchyAnnotated(Deprecated.class)) { + operation.setDeprecated(true); + } + if (operation.getGroup() == null) { + operation.setGroup(openAPI.getGroup()); + } + + if (CollectionUtils.isEmpty(operation.getParameters())) { + for (ParameterMeta paramMeta : meta.getParameters()) { + String name = paramMeta.getName(); + if (name == null) { + continue; + } + In in = Helper.toIn(paramMeta.getParamType()); + if (in == null) { + continue; + } + Parameter parameter = operation.getParameter(name, in); + if (parameter == null) { + parameter = new Parameter(name, in); + operation.addParameter(parameter); + } + resolveParameter(parameter, paramMeta); + } + } + + if (httpMethod.supportBody()) { + RequestBody body = operation.getRequestBody(); + if (body == null) { + body = new RequestBody(); + operation.setRequestBody(body); + } + if (CollectionUtils.isEmptyMap(body.getContents())) { + resolveRequestBody(body, openAPI, meta, mapping); + } + } + + if (CollectionUtils.isEmptyMap(operation.getResponses())) { + String[] httpStatusCodes = openAPI.getConfigValue(OpenAPIConfig::getDefaultHttpStatusCodes); + if (httpStatusCodes == null) { + httpStatusCodes = new String[] {"200", "400", "500"}; + } + for (String httpStatusCode : httpStatusCodes) { + ApiResponse response = operation.getOrAddResponse(httpStatusCode); + resolveResponse(httpStatusCode, response, openAPI, meta, mapping); + } + } + } + + private String generateOperationId(MethodMeta meta, OpenAPI openAPI) { + String name = openAPI.getConfigValue(OpenAPIConfig::getOperationIdStrategy); + if (name == null) { + return null; + } + NamingStrategy strategy = extensionFactory.getExtension(NamingStrategy.class, "naming-strategy-" + name); + if (strategy == null) { + return null; + } + return strategy.generateOperationId(meta, openAPI); + } + + private void resolveParameter(Parameter parameter, ParameterMeta meta) { + if (parameter.getSchema() == null) { + parameter.setSchema(schemaFactory.getSchema(meta.getActualGenericType())); + } + } + + private void resolveRequestBody(RequestBody body, OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) { + Collection mediaTypes = null; + if (mapping.getConsumesCondition() != null) { + mediaTypes = mapping.getConsumesCondition().getMediaTypes(); + } + if (mediaTypes == null) { + String[] defaultMediaTypes = openAPI.getConfigValue(OpenAPIConfig::getDefaultConsumesMediaTypes); + if (defaultMediaTypes == null) { + mediaTypes = Collections.singletonList(MediaType.APPLICATION_JSON); + } else { + mediaTypes = Arrays.stream(defaultMediaTypes).map(MediaType::of).collect(Collectors.toList()); + } + } + for (MediaType mediaType : mediaTypes) { + org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType content = + body.getOrAddContent(mediaType.getName()); + if (content.getSchema() == null) { + content.setSchema(schemaFactory.getSchema(meta.getParameters())); + } + } + } + + private void resolveResponse( + String httpStatusCode, ApiResponse response, OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) { + int httpStatus = Integer.parseInt(httpStatusCode); + if (httpStatus > 201 && httpStatus < 400) { + response.setDescription(HttpUtils.getStatusMessage(httpStatus)); + return; + } + + Collection mediaTypes = null; + if (mapping.getProducesCondition() != null) { + mediaTypes = mapping.getProducesCondition().getMediaTypes(); + } + if (mediaTypes == null) { + String[] defaultMediaTypes = openAPI.getConfigValue(OpenAPIConfig::getDefaultProducesMediaTypes); + if (defaultMediaTypes == null) { + mediaTypes = Collections.singletonList(MediaType.APPLICATION_JSON); + } else { + mediaTypes = Arrays.stream(defaultMediaTypes).map(MediaType::of).collect(Collectors.toList()); + } + } + for (MediaType mediaType : mediaTypes) { + org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType content = + response.getOrAddContent(mediaType.getName()); + if (content.getSchema() == null) { + if (httpStatus >= 400) { + content.setSchema(schemaFactory.getSchema(ErrorResponse.class)); + } else { + content.setSchema(schemaFactory.getSchema(meta.getParameters())); + } + } + } + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/WriteContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DocumentPublisher.java similarity index 75% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/WriteContext.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DocumentPublisher.java index f418b0ada89..25a216df91c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/WriteContext.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DocumentPublisher.java @@ -16,4 +16,12 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; -public interface WriteContext {} +import org.apache.dubbo.common.utils.Pair; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +import java.util.function.Function; + +public interface DocumentPublisher extends OpenAPIExtension { + + void publish(Function> fn); +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java new file mode 100644 index 00000000000..c3db141552e --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java @@ -0,0 +1,75 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.extension.ExtensionLoader; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.Pair; +import org.apache.dubbo.rpc.model.FrameworkModel; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("unchecked") +public final class ExtensionFactory { + + private final ExtensionLoader extensionLoader; + private final List extensions; + private final Map cache = CollectionUtils.newConcurrentHashMap(); + + public ExtensionFactory(FrameworkModel frameworkModel) { + extensionLoader = frameworkModel.getExtensionLoader(OpenAPIExtension.class); + extensions = extensionLoader.getActivateExtensions(); + } + + public T[] getExtensions(Class type) { + return (T[]) cache.computeIfAbsent(type, k -> { + List list = new ArrayList<>(); + for (OpenAPIExtension extension : extensions) { + if (type.isInstance(extension)) { + list.add(extension); + } + } + return list.toArray((T[]) Array.newInstance(type, list.size())); + }); + } + + public T[] getExtensions(Class type, String group) { + return (T[]) cache.computeIfAbsent(Pair.of(type, group), k -> { + List list = new ArrayList<>(); + for (OpenAPIExtension extension : extensions) { + if (type.isInstance(extension) && accept(extension, group)) { + list.add(extension); + } + } + return list.toArray((T[]) Array.newInstance(type, list.size())); + }); + } + + public T getExtension(Class type, String name) { + OpenAPIExtension extension = extensionLoader.getExtension(name, true); + return type.isInstance(extension) ? (T) extension : null; + } + + private static boolean accept(OpenAPIExtension extension, String group) { + String[] groups = extension.getGroups(); + return groups == null || groups.length == 0 || Arrays.asList(groups).contains(group); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index 733d0789eaa..a3688789134 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -16,21 +16,98 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathSegment; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static org.apache.dubbo.remoting.http12.HttpMethods.DELETE; +import static org.apache.dubbo.remoting.http12.HttpMethods.GET; +import static org.apache.dubbo.remoting.http12.HttpMethods.PATCH; +import static org.apache.dubbo.remoting.http12.HttpMethods.POST; +import static org.apache.dubbo.remoting.http12.HttpMethods.PUT; public final class Helper { + private static final String[][] VERBS_TABLE = { + {GET.name(), "get", "load", "fetch", "read", "retrieve", "list", "find", "query", "search", "is"}, + {PUT.name(), "put", "replace"}, + {PATCH.name(), "patch", "update", "modify", "edit", "change", "set"}, + {DELETE.name(), "delete", "remove", "erase", "destroy", "drop"} + }; + private Helper() {} - public static String resolvePath(PathExpression expr) { - return expr.getPath(); + public static String toPathValue(PathExpression expr) { + if (expr.isDirect()) { + return expr.getPath(); + } + StringBuilder sb = new StringBuilder(expr.getPath().length()); + int varIndex = 1; + for (PathSegment segment : expr.getSegments()) { + sb.append('/'); + switch (segment.getType()) { + case LITERAL: + sb.append(segment.getValue()); + break; + case WILDCARD_TAIL: + List variables = segment.getVariables(); + if (variables == null) { + sb.append("{path}"); + } else { + sb.append('{').append(variables.get(0)).append('}'); + } + break; + case VARIABLE: + sb.append('{'); + String value = segment.getValue(); + if (value.isEmpty()) { + sb.append("var").append(varIndex++); + } else { + sb.append(value); + } + sb.append('}'); + break; + case PATTERN: + case PATTERN_MULTI: + sb.append('{').append("var").append(varIndex++).append('}'); + break; + default: + break; + } + } + return sb.toString(); } - public static String pathToRef(String path) { - return path; + public static Collection guessHttpMethod(MethodMeta method) { + String name = method.getMethod().getName(); + for (String[] verbs : VERBS_TABLE) { + for (int i = 1, len = verbs.length; i < len; i++) { + if (name.startsWith(verbs[i])) { + return Collections.singletonList(verbs[0]); + } + } + } + return Collections.singletonList(POST.name()); } - public static String refToPath(String ref) { - return ref; + public static In toIn(ParamType paramType) { + switch (paramType) { + case PathVariable: + return In.PATH; + case Param: + return In.QUERY; + case Header: + return In.HEADER; + case Cookie: + return In.COOKIE; + default: + return null; + } } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/NamingStrategy.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/NamingStrategy.java new file mode 100644 index 00000000000..7beea21bd23 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/NamingStrategy.java @@ -0,0 +1,31 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +public interface NamingStrategy extends OpenAPIExtension { + + default String generateOperationId(MethodMeta methodMeta, OpenAPI openAPI) { + return null; + } + + default String generateSchemaName(Class type, OpenAPI openAPI) { + return null; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java index ff0297debc0..13e443942f0 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java @@ -16,7 +16,10 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Header; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Node; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; @@ -24,56 +27,50 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; public interface OpenAPIFilter extends OpenAPIExtension { - default OpenAPI filterOpenAPI(OpenAPI openAPI, FilterContext context) { + default OpenAPI filterOpenAPI(OpenAPI openAPI, Context context) { return openAPI; } - default PathItem filterPathItem(PathItem pathItem, FilterContext context) { + default PathItem filterPathItem(String key, PathItem pathItem, Context context) { return pathItem; } - default Operation filterOperation(Operation operation, FilterContext context) { + default Operation filterOperation(HttpMethods key, Operation operation, PathItem pathItem, Context context) { return operation; } - default Parameter filterParameter(Parameter parameter, FilterContext context) { + default Parameter filterParameter(Parameter parameter, Operation operation, Context context) { return parameter; } - default RequestBody filterRequestBody(RequestBody requestBody, FilterContext context) { - return requestBody; + default RequestBody filterRequestBody(RequestBody body, Operation operation, Context context) { + return body; } - default ApiResponse filterResponse(ApiResponse apiResponse, FilterContext context) { - return apiResponse; + default ApiResponse filterResponse(ApiResponse response, Operation operation, Context context) { + return response; } - default Schema filterSchema(Schema schema, FilterContext context) { - return schema; + default Header filterHeader(Header header, ApiResponse response, Operation operation, Context context) { + return header; } - default Schema filterSchemaProperty(Schema schema, FilterContext context) { + default Schema filterSchema(Schema schema, Node node, Context context) { return schema; } - default Server filterServer(Server server, FilterContext context) { - return server; + default Schema filterSchemaProperty(String name, Schema schema, Schema owner, Context context) { + return schema; } - default SecurityScheme filterSecurityScheme(SecurityScheme securityScheme, FilterContext context) { + default SecurityScheme filterSecurityScheme(SecurityScheme securityScheme, Context context) { return securityScheme; } - default Tag filterTag(Tag tag, FilterContext context) { - return tag; - } - - default OpenAPI filterOpenAPICompletion(OpenAPI openAPI, FilterContext context) { + default OpenAPI filterOpenAPICompletion(OpenAPI openAPI, Context context) { return openAPI; } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequest.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequest.java index 7e101bf9520..530c5b96164 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequest.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequest.java @@ -27,10 +27,10 @@ public class OpenAPIRequest implements Serializable { private String group; private String[] tags; private String service; - private String version; + private String format; - private boolean pretty; + private Boolean pretty; public String getGroup() { return group; @@ -72,12 +72,13 @@ public void setFormat(String format) { this.format = format; } - public boolean isPretty() { + public Boolean getPretty() { return pretty; } - public void setPretty(boolean pretty) { + public OpenAPIRequest setPretty(Boolean pretty) { this.pretty = pretty; + return this; } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java index 7b95b70486f..f35cb1b52ce 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java @@ -16,25 +16,11 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; -import org.apache.dubbo.remoting.http12.exception.EncodeException; -import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; -import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -import java.io.OutputStream; -import java.nio.charset.Charset; +final class ProtoEncoder { -final class ProtoEncoder implements HttpMessageEncoder { - - static final ProtoEncoder INSTANCE = new ProtoEncoder(); - - @Override - public void encode(OutputStream outputStream, Object data, Charset charset) throws EncodeException { - OpenAPI openAPI = (OpenAPI) data; - } - - @Override - public MediaType mediaType() { - return MediaType.TEXT_PLAIN; + public String encode(OpenAPI openAPI) { + return ""; } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java index eb62043ab2e..0b0f53f9b2b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java @@ -17,26 +17,23 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -public final class ResolveContext { +public interface ResolveContext { - private final SchemaFactory schemaFactory; - private OpenAPIConfig config; + String getGroup(); - public ResolveContext(SchemaFactory schemaFactory) { - this.schemaFactory = schemaFactory; - } + OpenAPI getOpenAPI(); - public SchemaFactory getSchemaFactory() { - return schemaFactory; - } + OpenAPIConfig getConfig(); - public OpenAPIConfig getConfig() { - return config; - } + SchemaFactory getSchemaFactory(); - public ResolveContext setConfig(OpenAPIConfig config) { - this.config = config; - return this; - } + ExtensionFactory getExtensionFactory(); + + T getAttribute(String name); + + T removeAttribute(String name); + + void setAttribute(String name, Object value); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContextImpl.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContextImpl.java new file mode 100644 index 00000000000..920f4b922e7 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContextImpl.java @@ -0,0 +1,26 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; + +final class ResolveContextImpl extends AbstractContext implements ResolveContext { + + ResolveContextImpl(OpenAPI openAPI, SchemaFactory schemaFactory, ExtensionFactory extensionFactory) { + super(openAPI, schemaFactory, extensionFactory); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java index dcfbccac3bf..a2ee6a83d9b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java @@ -16,11 +16,18 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; -public class SchemaFactory { +import java.lang.reflect.Type; - public static Schema getSchema(Class clazz) { +public final class SchemaFactory { + + public Schema getSchema(Type type) { + return new Schema(); + } + + public Schema getSchema(ParameterMeta[] parameters) { return new Schema(); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/FilterContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaProvider.java similarity index 83% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/FilterContext.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaProvider.java index f5abd5212fa..dd84c4adf4d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/FilterContext.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaProvider.java @@ -16,4 +16,9 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; -public interface FilterContext {} +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; + +public interface SchemaProvider extends OpenAPIExtension { + + Schema getSchema(Class clazz); +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java index 4279cf7b819..38d9fe835dd 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.LinkedHashMap; import java.util.Map; @@ -26,7 +26,7 @@ public final class ApiResponse extends Node { private String ref; private String description; private Map headers; - private Map content; + private Map contents; public String getRef() { return ref; @@ -50,6 +50,10 @@ public Map getHeaders() { return headers; } + public Header getHeader(String name) { + return headers == null ? null : headers.get(name); + } + public ApiResponse setHeaders(Map headers) { this.headers = headers; return this; @@ -70,26 +74,37 @@ public ApiResponse removeHeader(String name) { return this; } - public Map getContent() { - return content; + public Map getContents() { + return contents; + } + + public MediaType getContent(String name) { + return contents == null ? null : contents.get(name); + } + + public MediaType getOrAddContent(String name) { + if (contents == null) { + contents = new LinkedHashMap<>(); + } + return contents.computeIfAbsent(name, k -> new MediaType()); } - public ApiResponse setContent(Map content) { - this.content = content; + public ApiResponse setContents(Map contents) { + this.contents = contents; return this; } public ApiResponse addContent(String name, MediaType mediaType) { - if (content == null) { - content = new LinkedHashMap<>(); + if (contents == null) { + contents = new LinkedHashMap<>(); } - content.put(name, mediaType); + contents.put(name, mediaType); return this; } public ApiResponse removeContent(String name) { - if (content != null) { - content.remove(name); + if (contents != null) { + contents.remove(name); } return this; } @@ -97,14 +112,14 @@ public ApiResponse removeContent(String name) { @Override public ApiResponse clone() { ApiResponse clone = super.clone(); - clone.content = clone(content); + clone.contents = clone(contents); return clone; } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "description", description); - write(node, "content", content, context); + write(node, "content", contents, context); writeExtensions(node); return node; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java index 0180c7af7ca..5859a52bc14 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.LinkedHashMap; import java.util.Map; @@ -83,7 +83,7 @@ public Components clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "schemas", schemas, context); write(node, "securitySchemes", securitySchemes, context); writeExtensions(node); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java index a37d76cc06e..897e28b9cd0 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.Map; @@ -54,7 +54,7 @@ public Contact setEmail(String email) { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "name", name); write(node, "url", url); write(node, "email", email); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java index c3b9ca8cdb6..e658f28c119 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.LinkedHashMap; import java.util.Map; @@ -69,7 +69,7 @@ public Discriminator clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "propertyName", propertyName); write(node, "mapping", mapping); writeExtensions(node); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java index d70b18da1f2..578c086de54 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.LinkedHashMap; import java.util.Map; @@ -60,6 +60,10 @@ public Map getHeaders() { return headers; } + public Parameter getHeader(String name) { + return headers == null ? null : headers.get(name); + } + public Encoding setHeaders(Map headers) { this.headers = headers; return this; @@ -115,7 +119,7 @@ public Encoding clone() { } @Override - public Map writeTo(Map encoding, WriteContext context) { + public Map writeTo(Map encoding, Context context) { write(encoding, "contentType", contentType); write(encoding, "headers", headers, context); write(encoding, "style", style); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java index b7c0d2bd525..03dd029b55c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.Map; @@ -64,7 +64,7 @@ public Example setExternalValue(String externalValue) { } @Override - public Map writeTo(Map exampleNode, WriteContext context) { + public Map writeTo(Map exampleNode, Context context) { write(exampleNode, "summary", summary); write(exampleNode, "description", description); write(exampleNode, "value", value); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java index 04075d81e07..a4824648696 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.Map; @@ -44,7 +44,7 @@ public ExternalDocs setUrl(String url) { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "description", description); write(node, "url", url); writeExtensions(node); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java index a7d237a9b6a..15eaff62433 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.LinkedHashMap; import java.util.Map; @@ -144,6 +144,10 @@ public Map getContent() { return content; } + public MediaType getContent(String name) { + return content == null ? null : content.get(name); + } + public Header setContent(Map content) { this.content = content; return this; @@ -174,7 +178,7 @@ public Header clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "description", description); write(node, "required", required); write(node, "deprecated", deprecated); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java index bd0339d3ce2..fd1cc84ce47 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.Map; @@ -102,7 +102,7 @@ public Info clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "title", title); write(node, "summary", summary); write(node, "description", description); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java index 9f0965d54a8..36c68f0b564 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.Map; @@ -44,7 +44,7 @@ public License setUrl(String url) { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "name", name); write(node, "url", url); writeExtensions(node); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java index 109e744e516..85477145261 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.LinkedHashMap; import java.util.Map; @@ -104,7 +104,7 @@ public MediaType clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "schema", schema, context); write(node, "example", example); write(node, "examples", examples, context); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java index 125de5a7640..2a28c6fc8d5 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java @@ -17,7 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; import org.apache.dubbo.common.utils.ToStringUtils; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -112,15 +112,14 @@ protected static void write(Map node, String name, Object value) node.put(name, value); } - protected static void write(Map node, String name, Node value, WriteContext context) { + protected static void write(Map node, String name, Node value, Context context) { if (value == null) { return; } node.put(name, value.writeTo(new LinkedHashMap<>(), context)); } - protected static void write( - Map node, String name, List> value, WriteContext context) { + protected static void write(Map node, String name, List> value, Context context) { if (value == null) { return; } @@ -135,7 +134,7 @@ protected static void write( } protected static void write( - Map node, String name, Map> value, WriteContext context) { + Map node, String name, Map> value, Context context) { if (value == null) { return; } @@ -160,5 +159,5 @@ protected final void writeExtensions(Map node) { node.putAll(extensions); } - public abstract Map writeTo(Map node, WriteContext context); + public abstract Map writeTo(Map node, Context context); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java index 10e78591904..4ef8578e518 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.LinkedHashMap; import java.util.Map; @@ -88,7 +88,7 @@ public OAuthFlow clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "authorizationUrl", authorizationUrl); write(node, "tokenUrl", tokenUrl); write(node, "refreshUrl", refreshUrl); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java index 55a17e347c6..619c1cb10eb 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.Map; @@ -74,7 +74,7 @@ public OAuthFlows clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "implicit", implicit); write(node, "password", password); write(node, "clientCredentials", clientCredentials); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java index c1fe5c26367..ed1047be5b4 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java @@ -16,12 +16,15 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.Function; public final class OpenAPI extends Node { @@ -34,8 +37,12 @@ public final class OpenAPI extends Node { private List tags; private ExternalDocs externalDocs; - private String[] groups; - private transient int priority; + private String group; + private int priority; + + private transient OpenAPIConfig globalConfig; + private transient OpenAPIConfig config; + private transient ServiceMeta service; public String getOpenapi() { return openapi; @@ -83,6 +90,10 @@ public Map getPaths() { return paths; } + public PathItem getPath(String path) { + return paths == null ? null : paths.get(path); + } + public PathItem getOrAddPath(String path) { if (paths == null) { paths = new LinkedHashMap<>(); @@ -169,12 +180,12 @@ public OpenAPI setExternalDocs(ExternalDocs externalDocs) { return this; } - public String[] getGroups() { - return groups; + public String getGroup() { + return group; } - public OpenAPI setGroups(String[] groups) { - this.groups = groups; + public OpenAPI setGroup(String group) { + this.group = group; return this; } @@ -187,6 +198,43 @@ public OpenAPI setPriority(int priority) { return this; } + public OpenAPIConfig getGlobalConfig() { + return globalConfig; + } + + public OpenAPI setGlobalConfig(OpenAPIConfig globalConfig) { + this.globalConfig = globalConfig; + return this; + } + + public OpenAPIConfig getConfig() { + return config; + } + + public OpenAPI setConfig(OpenAPIConfig config) { + this.config = config; + return this; + } + + public T getConfigValue(Function fn) { + if (config != null) { + T value = fn.apply(config); + if (value != null) { + return value; + } + } + return globalConfig == null ? null : fn.apply(globalConfig); + } + + public ServiceMeta getService() { + return service; + } + + public OpenAPI setService(ServiceMeta service) { + this.service = service; + return this; + } + @Override public OpenAPI clone() { OpenAPI clone = super.clone(); @@ -201,7 +249,7 @@ public OpenAPI clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { node.put("openapi", openapi); write(node, "info", info, context); write(node, "servers", servers, context); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java index 09222c44269..f5eb8ac429a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java @@ -16,8 +16,10 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; +import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -38,9 +40,9 @@ public final class Operation extends Node { private List security; private List servers; - private String[] groups; - private transient int priority; - private transient MethodMeta meta; + private String group; + private HttpMethods httpMethod; + private transient MethodMeta method; public List getTags() { return tags; @@ -106,6 +108,19 @@ public List getParameters() { return parameters; } + public Parameter getParameter(String name, In in) { + if (parameters == null || name == null || in == null) { + return null; + } + for (int i = 0, size = parameters.size(); i < size; i++) { + Parameter parameter = parameters.get(i); + if (name.equals(parameter.getName()) && in == parameter.getIn()) { + return parameter; + } + } + return null; + } + public Operation setParameters(List parameters) { this.parameters = parameters; return this; @@ -139,6 +154,17 @@ public Map getResponses() { return responses; } + public ApiResponse getResponse(String httpStatusCode) { + return responses == null ? null : responses.get(httpStatusCode); + } + + public ApiResponse getOrAddResponse(String httpStatusCode) { + if (responses == null) { + responses = new LinkedHashMap<>(); + } + return responses.computeIfAbsent(httpStatusCode, k -> new ApiResponse()); + } + public Operation setResponses(Map responses) { this.responses = responses; return this; @@ -216,30 +242,30 @@ public Operation removeServer(Server server) { return this; } - public String[] getGroups() { - return groups; + public String getGroup() { + return group; } - public Operation setGroups(String[] groups) { - this.groups = groups; + public Operation setGroup(String group) { + this.group = group; return this; } - public int getPriority() { - return priority; + public HttpMethods getHttpMethod() { + return httpMethod; } - public Operation setPriority(int priority) { - this.priority = priority; + public Operation setHttpMethod(HttpMethods httpMethod) { + this.httpMethod = httpMethod; return this; } - public MethodMeta getMeta() { - return meta; + public MethodMeta getMethod() { + return method; } - public Operation setMeta(MethodMeta meta) { - this.meta = meta; + public Operation setMethod(MethodMeta method) { + this.method = method; return this; } @@ -259,7 +285,7 @@ public Operation clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "tags", tags); write(node, "summary", summary); write(node, "description", description); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java index 9308039ac76..7489ef82495 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java @@ -17,10 +17,11 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; public final class Parameter extends Node { @@ -63,8 +64,8 @@ public String toString() { } } - private String name; - private In in; + private final String name; + private final In in; private String description; private Boolean required; private Boolean deprecated; @@ -79,24 +80,19 @@ public String toString() { private transient ParameterMeta meta; - public String getName() { - return name; + public Parameter(String name, In in) { + this.name = Objects.requireNonNull(name); + this.in = Objects.requireNonNull(in); } - public Parameter setName(String name) { - this.name = name; - return this; + public String getName() { + return name; } public In getIn() { return in; } - public Parameter setIn(In in) { - this.in = in; - return this; - } - public String getDescription() { return description; } @@ -235,6 +231,23 @@ public Parameter setMeta(ParameterMeta meta) { return this; } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || obj.getClass() != Parameter.class) { + return false; + } + Parameter other = (Parameter) obj; + return name.equals(other.name) && in == other.in; + } + + @Override + public int hashCode() { + return 31 * name.hashCode() + in.hashCode(); + } + @Override public Parameter clone() { Parameter clone = super.clone(); @@ -245,7 +258,7 @@ public Parameter clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "name", name); write(node, "in", in); write(node, "description", description); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java index bd77f481f1b..0d87d7c8612 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java @@ -17,7 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; import org.apache.dubbo.remoting.http12.HttpMethods; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -64,8 +64,8 @@ public Map getOperations() { return operations; } - public Operation getOrAddOperation(HttpMethods method) { - return operations.computeIfAbsent(method, k -> new Operation()); + public Operation getOperation(HttpMethods method) { + return operations == null ? null : operations.get(method); } public PathItem setOperations(Map operations) { @@ -146,7 +146,7 @@ public PathItem clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "$ref", ref); write(node, "summary", summary); write(node, "description", description); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java index 9f063398e7d..d0bf06dc172 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.LinkedHashMap; import java.util.Map; @@ -24,7 +24,7 @@ public final class RequestBody extends Node { private String description; - private Map content; + private Map contents; private boolean required; public String getDescription() { @@ -36,26 +36,37 @@ public RequestBody setDescription(String description) { return this; } - public Map getContent() { - return content; + public Map getContents() { + return contents; } - public RequestBody setContent(Map content) { - this.content = content; + public MediaType getContent(String mediaType) { + return contents == null ? null : contents.get(mediaType); + } + + public MediaType getOrAddContent(String mediaType) { + if (contents == null) { + contents = new LinkedHashMap<>(); + } + return contents.computeIfAbsent(mediaType, k -> new MediaType()); + } + + public RequestBody setContents(Map contents) { + this.contents = contents; return this; } public RequestBody addContent(String name, MediaType mediaType) { - if (content == null) { - content = new LinkedHashMap<>(); + if (contents == null) { + contents = new LinkedHashMap<>(); } - content.put(name, mediaType); + contents.put(name, mediaType); return this; } public RequestBody removeContent(String name) { - if (content != null) { - content.remove(name); + if (contents != null) { + contents.remove(name); } return this; } @@ -72,15 +83,15 @@ public RequestBody setRequired(boolean required) { @Override public RequestBody clone() { RequestBody clone = super.clone(); - clone.content = clone(content); + clone.contents = clone(contents); return clone; } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "description", description); write(node, "required", required); - write(node, "content", content, context); + write(node, "content", contents, context); return node; } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java index dd2c34626dd..66ff84f7098 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.math.BigDecimal; import java.util.ArrayList; @@ -519,7 +519,7 @@ public Schema clone() { } @Override - public Map writeTo(Map schema, WriteContext context) { + public Map writeTo(Map schema, Context context) { write(schema, "$ref", ref); write(schema, "format", format); write(schema, "name", name); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java index d7d1f206eba..bea8a691fac 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.ArrayList; import java.util.Arrays; @@ -72,7 +72,7 @@ public SecurityRequirement clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "requirements", requirements); writeExtensions(node); return node; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java index b068fc30f27..7ac3f4e0d01 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.Map; @@ -146,7 +146,7 @@ public SecurityScheme clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "type", type); write(node, "description", description); write(node, "name", name); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java index 0f1deb9053a..4b3c978f2fb 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.LinkedHashMap; import java.util.Map; @@ -77,7 +77,7 @@ public Server clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "url", url); write(node, "description", description); write(node, "variables", variables, context); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java index e82074fcc3a..b3977c50482 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.ArrayList; import java.util.List; @@ -80,7 +80,7 @@ public ServerVariable clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { write(node, "enum", enumeration); write(node, "default", defaultValue); write(node, "description", description); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java index 6b5ce936056..11820f7b825 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.Map; @@ -61,7 +61,7 @@ public Tag clone() { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { node.put("name", name); node.put("description", description); write(node, "externalDocs", externalDocs, context); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java index 5df87dece44..20ab6a44b5f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java @@ -16,7 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.WriteContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.Map; @@ -74,7 +74,7 @@ public XML setWrapped(Boolean wrapped) { } @Override - public Map writeTo(Map node, WriteContext context) { + public Map writeTo(Map node, Context context) { node.put("name", name); writeExtensions(node); return node; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java index 93214b2bff2..379ddf97c12 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java @@ -51,7 +51,7 @@ final class BeanArgumentBinder { private final CompositeArgumentResolver argumentResolver; public BeanArgumentBinder(FrameworkModel frameworkModel) { - argumentResolver = frameworkModel.getBeanFactory().getOrRegisterBean(CompositeArgumentResolver.class); + argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); } public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java index 51b36b3cadf..e8e84355e6c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java @@ -40,8 +40,8 @@ public abstract class AbstractRestToolKit implements RestToolKit { public AbstractRestToolKit(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; - typeConverter = frameworkModel.getBeanFactory().getOrRegisterBean(GeneralTypeConverter.class); - parameterNameReader = frameworkModel.getBeanFactory().getOrRegisterBean(DefaultParameterNameReader.class); + typeConverter = frameworkModel.getOrRegisterBean(GeneralTypeConverter.class); + parameterNameReader = frameworkModel.getOrRegisterBean(DefaultParameterNameReader.class); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/MethodWalker.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/MethodWalker.java index ccb7e95fdcf..de5b63faf66 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/MethodWalker.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/MethodWalker.java @@ -82,7 +82,7 @@ private static Key of(Method method) { } @Override - @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") + @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "EqualsDoesntCheckParameterClass"}) public boolean equals(Object obj) { Key key = (Key) obj; return name.equals(key.name) && Arrays.equals(parameterTypes, key.parameterTypes); From 5a6e247176650e13fb4173b20c0b4de68a714326 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Mon, 11 Nov 2024 23:07:13 +0800 Subject: [PATCH 03/23] Refine openapi model --- .../dubbo/config/nested/OpenAPIConfig.java | 13 + .../tri/rest/openapi/ConfigFactory.java | 2 +- .../tri/rest/openapi/DefinitionMerger.java | 408 ++++++++++++++++-- .../tri/rest/openapi/DefinitionResolver.java | 6 +- .../protocol/tri/rest/openapi/model/Node.java | 43 +- .../tri/rest/openapi/model/OpenAPI.java | 13 +- .../tri/rest/openapi/model/Operation.java | 10 +- .../tri/rest/openapi/model/PathItem.java | 14 +- 8 files changed, 453 insertions(+), 56 deletions(-) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java index 953078ca45b..f3a2f059649 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -62,6 +62,11 @@ public class OpenAPIConfig implements Serializable { */ private String infoContactName; + /** + * The url of the contact. + */ + private String infoContactUrl; + /** * The email address of the contact. */ @@ -186,6 +191,14 @@ public void setInfoContactName(String infoContactName) { this.infoContactName = infoContactName; } + public String getInfoContactUrl() { + return infoContactUrl; + } + + public void setInfoContactUrl(String infoContactUrl) { + this.infoContactUrl = infoContactUrl; + } + public String getInfoContactEmail() { return infoContactEmail; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java index d04d530eeb0..ae5f66913a5 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java @@ -97,7 +97,7 @@ private Map readConfigMap() { } private static void applyConfigValue(Map map, String group, String key, String value) { - if (value == null) { + if (value == null || value.isEmpty()) { return; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index 44fe3a88e05..848c8e82b1c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -16,16 +16,38 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +import org.apache.dubbo.common.logger.FluentLogger; +import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Components; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Contact; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.License; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Node; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityRequirement; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; +import java.lang.reflect.Type; import java.util.Arrays; -import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; +import java.util.TreeMap; final class DefinitionMerger { + private static final FluentLogger LOG = FluentLogger.of(DefinitionMerger.class); + private final ExtensionFactory extensionFactory; private final ConfigFactory configFactory; @@ -45,60 +67,376 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { if (group == null) { group = Constants.DEFAULT_GROUP; } - String[] tagArray = trim(request.getTags()); - Set tags = tagArray == null ? null : new HashSet<>(Arrays.asList(tagArray)); + String[] tags = trim(request.getTags()); String service = trim(request.getService()); + String version = trim(request.getVersion()); + if (version != null) { + result.setOpenapi(formatVersion(version)); + } + + applyConfig(result, configFactory.getConfig(group)); + + for (OpenAPI openAPI : openAPIs) { + if (service != null) { + String serviceName = openAPI.getService().getServiceDescriptor().getInterfaceName(); + if (serviceName != null && !serviceName.regionMatches(true, 0, service, 0, service.length())) { + continue; + } + } + + if (group.equals(openAPI.getGroup())) { + mergeBasic(result, openAPI); + } + + mergePaths(result, openAPI, group, tags); - for (OpenAPI api : openAPIs) { + mergeSecuritySchemes(result, openAPI); - result.setOpenapi(api.getOpenapi()); - result.setInfo(api.getInfo()); - result.setServers(api.getServers()); - result.setComponents(api.getComponents()); - result.setSecurity(api.getSecurity()); - result.setTags(api.getTags()); - result.setExternalDocs(api.getExternalDocs()); - result.setGroup(api.getGroup()); - result.setPriority(api.getPriority()); + mergeTags(result, openAPI); } - String version = request.getVersion(); - if (version == null) { - version = result.getOpenapi(); + applyConfig(result, configFactory.getGlobalConfig()); + + addRefSchemas(result); + + cleanup(result); + + return result; + } + + private void applyConfig(OpenAPI api, OpenAPIConfig config) { + if (config == null) { + return; } - if (version == null) { - version = Constants.VERSION_30; - } else { - if (version.startsWith("3.0")) { - version = Constants.VERSION_30; - } else if (version.startsWith("3.1")) { - version = Constants.VERSION_31; + + if (api.getOpenapi() == null) { + api.setOpenapi(formatVersion(config.getVersion())); + } + + Info info = api.getInfo(); + if (info == null) { + api.setInfo(info = new Info()); + } + if (info.getTitle() == null) { + info.setTitle(config.getInfoTitle()); + } + if (info.getDescription() == null) { + info.setDescription(config.getInfoDescription()); + } + + Contact contact = info.getContact(); + if (contact == null) { + info.setContact(contact = new Contact()); + } + if (contact.getName() == null) { + contact.setName(config.getInfoContactName()); + } + if (contact.getUrl() == null) { + contact.setUrl(config.getInfoContactUrl()); + } + if (contact.getEmail() == null) { + contact.setEmail(config.getInfoContactEmail()); + } + + if (info.getVersion() == null) { + info.setVersion(config.getInfoVersion()); + } + + ExternalDocs externalDocs = api.getExternalDocs(); + if (externalDocs == null) { + api.setExternalDocs(externalDocs = new ExternalDocs()); + } + if (externalDocs.getDescription() == null) { + externalDocs.setDescription(config.getExternalDocsDescription()); + } + if (externalDocs.getUrl() == null) { + externalDocs.setUrl(config.getExternalDocsUrl()); + } + + if (api.getServers() == null) { + String[] servers = config.getServers(); + if (servers != null) { + for (String server : servers) { + api.addServer(new Server().setUrl(server)); + } } } - result.setOpenapi(version); - return result; + Components components = api.getComponents(); + if (api.getComponents() == null) { + api.setComponents(components = new Components()); + } + if (components.getSecuritySchemes() == null) { + String securityScheme = config.getSecurityScheme(); + if (securityScheme != null) { + try { + Type type = + Components.class.getDeclaredField("securitySchemes").getGenericType(); + components.setSecuritySchemes(JsonUtils.toJavaObject(securityScheme, type)); + } catch (NoSuchFieldException ignored) { + } + } + } + } + + private void mergeBasic(OpenAPI api, OpenAPI from) { + if (api.getOpenapi() == null) { + api.setOpenapi(formatVersion(from.getOpenapi())); + } + + mergeInfo(api, from); + + List fromServers = from.getServers(); + if (fromServers != null) { + List servers = api.getServers(); + if (servers == null) { + api.setServers(Node.clone(fromServers)); + } + } + + List fromSecurity = from.getSecurity(); + if (fromSecurity != null) { + List security = api.getSecurity(); + if (security == null) { + api.setSecurity(Node.clone(fromSecurity)); + } + } + + ExternalDocs fromExternalDocs = from.getExternalDocs(); + if (fromExternalDocs != null) { + ExternalDocs externalDocs = api.getExternalDocs(); + if (externalDocs.getDescription() == null) { + externalDocs.setDescription(fromExternalDocs.getDescription()); + } + if (externalDocs.getUrl() == null) { + externalDocs.setUrl(fromExternalDocs.getUrl()); + } + externalDocs.addExtensions(fromExternalDocs.getExtensions()); + } + + api.addExtensions(from.getExtensions()); + } + + private void mergeInfo(OpenAPI api, OpenAPI from) { + Info fromInfo = from.getInfo(); + if (fromInfo != null) { + Info info = api.getInfo(); + if (info.getTitle() == null) { + info.setTitle(fromInfo.getTitle()); + } + if (info.getSummary() == null) { + info.setDescription(fromInfo.getSummary()); + } + if (info.getDescription() == null) { + info.setDescription(fromInfo.getDescription()); + } + if (info.getTermsOfService() == null) { + info.setTermsOfService(fromInfo.getTermsOfService()); + } + + Contact fromContact = fromInfo.getContact(); + if (fromContact != null) { + Contact contact = info.getContact(); + if (contact.getName() == null) { + contact.setName(fromContact.getName()); + } + if (contact.getUrl() == null) { + contact.setUrl(fromContact.getUrl()); + } + if (contact.getEmail() == null) { + contact.setEmail(fromContact.getEmail()); + } + + if (info.getVersion() == null) { + info.setVersion(fromInfo.getVersion()); + } + contact.addExtensions(fromContact.getExtensions()); + } + + License fromLicense = fromInfo.getLicense(); + if (fromLicense != null) { + License license = info.getLicense(); + if (license.getName() == null) { + license.setName(fromLicense.getName()); + } + if (license.getUrl() == null) { + license.setUrl(fromLicense.getUrl()); + } + license.addExtensions(fromLicense.getExtensions()); + } + + if (info.getVersion() == null) { + info.setVersion(fromInfo.getVersion()); + } + + info.addExtensions(fromInfo.getExtensions()); + } } - private void mergeInfo(OpenAPI result, List openAPIs) { - if (openAPIs.size() == 1) { - result.setInfo(openAPIs.get(0).getInfo()); + private void mergePaths(OpenAPI api, OpenAPI from, String group, String[] tags) { + Map fromPaths = from.getPaths(); + if (fromPaths == null) { return; } - for (OpenAPI api : openAPIs) { - if (api.getInfo() != null) { - result.setInfo(api.getInfo()); - return; + Map paths = api.getPaths(); + if (paths == null) { + api.setPaths(paths = new TreeMap<>()); + } + + for (Entry entry : fromPaths.entrySet()) { + String path = entry.getKey(); + PathItem fromPathItem = entry.getValue(); + PathItem pathItem = paths.get(path); + if (pathItem != null) { + String ref = fromPathItem.getRef(); + if (ref != null) { + pathItem = paths.get(ref); + } } + if (pathItem == null) { + paths.put(path, pathItem = new PathItem()); + } + mergePathItem(path, pathItem, fromPathItem, group, tags); } } - public static String trim(String str) { - return str == null || str.isEmpty() ? null : str.trim(); + private void mergePathItem(String path, PathItem pathItem, PathItem from, String group, String[] tags) { + if (pathItem.getSummary() == null) { + pathItem.setSummary(from.getSummary()); + } + if (pathItem.getDescription() == null) { + pathItem.setDescription(from.getDescription()); + } + + Map fromOperations = from.getOperations(); + if (fromOperations != null) { + Map operations = pathItem.getOperations(); + if (operations == null) { + pathItem.setOperations(Node.clone(fromOperations)); + } else { + for (Entry entry : fromOperations.entrySet()) { + HttpMethods httpMethod = entry.getKey(); + Operation fromOperation = entry.getValue(); + if (!group.equals(fromOperation.getGroup())) { + continue; + } + + if (tags != null) { + Set operationTags = fromOperation.getTags(); + if (operationTags == null) { + continue; + } + boolean exclude = false; + for (String tag : tags) { + if (operationTags.contains(tag)) { + continue; + } + exclude = true; + break; + } + if (exclude) { + continue; + } + } + + Operation operation = operations.get(httpMethod); + if (operation == null) { + operations.put(httpMethod, fromOperation.clone()); + } else if (operation.getMethod() != null) { + LOG.internalWarn( + "Operation already exists, path='{}', httpMethod='{}', method={}", + path, + httpMethod, + fromOperation.getMethod()); + } + } + } + } + + if (pathItem.getServers() == null) { + List fromServers = from.getServers(); + if (fromServers != null) { + pathItem.setServers(Node.clone(fromServers)); + } + } + + List fromParameters = from.getParameters(); + if (fromParameters != null) { + if (pathItem.getParameters() == null) { + pathItem.setParameters(Node.clone(fromParameters)); + } else { + for (Parameter parameter : fromParameters) { + pathItem.addParameter(parameter.clone()); + } + } + } + + pathItem.addExtensions(from.getExtensions()); + } + + private void mergeSecuritySchemes(OpenAPI api, OpenAPI from) { + Components fromComponents = from.getComponents(); + if (fromComponents == null) { + return; + } + + Map fromSecuritySchemes = fromComponents.getSecuritySchemes(); + if (fromSecuritySchemes == null) { + return; + } + + Components components = api.getComponents(); + Map securitySchemes = components.getSecuritySchemes(); + if (securitySchemes == null) { + components.setSecuritySchemes(Node.clone(fromSecuritySchemes)); + } else { + for (Entry entry : fromSecuritySchemes.entrySet()) { + String key = entry.getKey(); + if (securitySchemes.containsKey(key)) { + continue; + } + securitySchemes.put(key, entry.getValue().clone()); + } + } + } + + private void mergeTags(OpenAPI api, OpenAPI from) { + List fromTags = from.getTags(); + if (fromTags != null) { + if (api.getTags() == null) { + api.setTags(Node.clone(fromTags)); + } else { + for (Tag tag : fromTags) { + api.addTag(tag.clone()); + } + } + } + } + + private void addRefSchemas(OpenAPI api) {} + + private void cleanup(OpenAPI api) {} + + private static String formatVersion(String version) { + if (version == null) { + return null; + } + if (version.startsWith("3.1")) { + return Constants.VERSION_31; + } + return Constants.VERSION_30; + } + + private static String trim(String str) { + if (str == null || str.isEmpty()) { + return null; + } + str = str.trim(); + return str.isEmpty() ? null : str; } - public static String[] trim(String[] array) { + private static String[] trim(String[] array) { if (array == null) { return null; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index 56824842706..e7411a4adf5 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -158,14 +158,14 @@ private boolean resolvePath( for (String hm : httpMethods) { HttpMethods httpMethod = HttpMethods.of(hm.toUpperCase()); - Operation existsOperation = pathItem.getOperation(httpMethod); - if (existsOperation == null) { + Operation existingOperation = pathItem.getOperation(httpMethod); + if (existingOperation == null) { if (operation == null) { operation = new Operation(); } pathItem.addOperation(httpMethod, operation); } else { - if (existsOperation.getMethod() != null) { + if (existingOperation.getMethod() != null) { LOG.internalWarn("Operation already exists, path='{}', httpMethod='{}', method={}", path, hm, meta); } continue; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java index 2a28c6fc8d5..df76078537f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java @@ -42,6 +42,23 @@ public T addExtension(String name, Object value) { return (T) this; } + @SuppressWarnings("unchecked") + public T addExtensions(Map extensions) { + if (extensions == null || extensions.isEmpty()) { + return (T) this; + } + + Map thisExtensions = this.extensions; + if (thisExtensions == null) { + this.extensions = new LinkedHashMap<>(extensions); + } else { + for (Map.Entry entry : extensions.entrySet()) { + thisExtensions.putIfAbsent(entry.getKey(), entry.getValue()); + } + } + return (T) this; + } + public void removeExtension(String name) { if (extensions != null) { extensions.remove(name); @@ -71,11 +88,11 @@ public String toString() { return ToStringUtils.printToString(this); } - protected static > T clone(T node) { + public static > T clone(T node) { return node == null ? null : node.clone(); } - protected static > List clone(List list) { + public static > List clone(List list) { if (list == null) { return null; } @@ -90,7 +107,7 @@ protected static > List clone(List list) { return clone; } - protected static > Map clone(Map map) { + public static > Map clone(Map map) { if (map == null) { return null; } @@ -106,7 +123,7 @@ protected static > Map clone(Map map) { } protected static void write(Map node, String name, Object value) { - if (value == null) { + if (value == null || "".equals(value)) { return; } node.put(name, value); @@ -116,7 +133,11 @@ protected static void write(Map node, String name, Node value if (value == null) { return; } - node.put(name, value.writeTo(new LinkedHashMap<>(), context)); + Map valueMap = value.writeTo(new LinkedHashMap<>(), context); + if (valueMap == null || valueMap.isEmpty()) { + return; + } + node.put(name, valueMap); } protected static void write(Map node, String name, List> value, Context context) { @@ -127,7 +148,11 @@ protected static void write(Map node, String name, List 0) { List> list = new ArrayList<>(size); for (int i = 0; i < size; i++) { - list.add(value.get(i).writeTo(new LinkedHashMap<>(), context)); + Map valueMap = value.get(i).writeTo(new LinkedHashMap<>(), context); + if (valueMap == null || valueMap.isEmpty()) { + continue; + } + list.add(valueMap); } node.put(name, list); } @@ -142,7 +167,11 @@ protected static void write( if (size > 0) { Map> map = newMap(size); for (Map.Entry> entry : value.entrySet()) { - map.put(entry.getKey(), entry.getValue().writeTo(new LinkedHashMap<>(), context)); + Map valueMap = entry.getValue().writeTo(new LinkedHashMap<>(), context); + if (valueMap == null || valueMap.isEmpty()) { + continue; + } + map.put(entry.getKey(), valueMap); } node.put(name, map); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java index ed1047be5b4..239791e94d7 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java @@ -157,10 +157,17 @@ public OpenAPI setTags(List tags) { } public OpenAPI addTag(Tag tag) { - if (tags == null) { - tags = new ArrayList<>(); + List thisTags = tags; + if (thisTags == null) { + tags = thisTags = new ArrayList<>(); + } else { + for (int i = 0, size = thisTags.size(); i < size; i++) { + if (thisTags.get(i).getName().equals(tag.getName())) { + return this; + } + } } - tags.add(tag); + thisTags.add(tag); return this; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java index f5eb8ac429a..c3a26e79d76 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java @@ -23,12 +23,14 @@ import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; public final class Operation extends Node { - private List tags; + private Set tags; private String summary; private String description; private ExternalDocs externalDocs; @@ -44,18 +46,18 @@ public final class Operation extends Node { private HttpMethods httpMethod; private transient MethodMeta method; - public List getTags() { + public Set getTags() { return tags; } - public Operation setTags(List tags) { + public Operation setTags(Set tags) { this.tags = tags; return this; } public Operation addTag(String tag) { if (tags == null) { - tags = new ArrayList<>(); + tags = new LinkedHashSet<>(); } tags.add(tag); return this; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java index 0d87d7c8612..ee375dd7955 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java @@ -122,10 +122,18 @@ public PathItem setParameters(List parameters) { } public PathItem addParameter(Parameter parameter) { - if (parameters == null) { - parameters = new ArrayList<>(); + List thisParameters = parameters; + if (thisParameters == null) { + parameters = thisParameters = new ArrayList<>(); + } else { + for (int i = 0, size = thisParameters.size(); i < size; i++) { + Parameter tParameter = thisParameters.get(i); + if (tParameter.getName().equals(parameter.getName())) { + return this; + } + } } - parameters.add(parameter); + thisParameters.add(parameter); return this; } From cd12f66cbe5dc27ac88ab6d7445f1a735827b567 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Tue, 12 Nov 2024 12:07:50 +0800 Subject: [PATCH 04/23] Openapi schema impl --- dubbo-distribution/dubbo-all-shaded/pom.xml | 3 + dubbo-distribution/dubbo-all/pom.xml | 3 + dubbo-distribution/dubbo-core-spi/pom.xml | 3 + .../support/jaxrs/BeanArgumentBinder.java | 16 +- .../metadata/MetadataServiceDelegation.java | 2 +- .../dubbo/remoting/http12/rest/OpenAPI.java | 23 +- .../argument/CompositeArgumentConverter.java | 28 +- .../tri/rest/mapping/meta/BeanMeta.java | 240 +++++++++-------- .../tri/rest/mapping/meta/MethodMeta.java | 41 +++ .../rest/mapping/meta/TypeParameterMeta.java | 53 ++++ .../tri/rest/openapi/AbstractContext.java | 1 + .../protocol/tri/rest/openapi/Context.java | 1 + .../tri/rest/openapi/ContextImpl.java | 1 + .../rest/openapi/DefaultOpenAPIService.java | 35 ++- .../tri/rest/openapi/DefinitionEncoder.java | 5 + .../tri/rest/openapi/DefinitionFilter.java | 3 +- .../tri/rest/openapi/DefinitionMerger.java | 248 +++++++++++------- .../tri/rest/openapi/DefinitionResolver.java | 30 ++- .../tri/rest/openapi/ExtensionFactory.java | 13 +- .../rpc/protocol/tri/rest/openapi/Helper.java | 60 +++++ .../tri/rest/openapi/NamingStrategy.java | 2 + ...er.java => OpenAPIDefinitionResolver.java} | 13 +- .../tri/rest/openapi/OpenAPIExtension.java | 3 +- .../tri/rest/openapi/ResolveContext.java | 1 + .../tri/rest/openapi/ResolveContextImpl.java | 26 -- .../tri/rest/openapi/SchemaProvider.java | 24 -- .../protocol/tri/rest/openapi/model/Node.java | 6 +- .../tri/rest/openapi/model/OpenAPI.java | 3 +- .../tri/rest/openapi/model/Operation.java | 2 +- .../tri/rest/openapi/model/Parameter.java | 24 +- .../tri/rest/openapi/model/Schema.java | 37 ++- .../openapi/{ => proto}/ProtoEncoder.java | 4 +- .../rest/openapi/schema/PrimitiveSchema.java | 139 ++++++++++ .../rest/openapi/schema/SchemaFactory.java | 210 +++++++++++++++ .../SchemaResolver.java} | 23 +- .../tri/rest/support/basic/Annotations.java | 2 + .../basic/BasicOpenAPIDefinitionResolver.java | 114 ++++++++ .../support/basic/BeanArgumentBinder.java | 22 +- .../tri/rest/util/AbstractRestToolKit.java | 11 +- .../rpc/protocol/tri/rest/util/RestUtils.java | 148 ++++++++++- .../rpc/protocol/tri/rest/util/TypeUtils.java | 17 ++ ...protocol.tri.rest.openapi.OpenAPIExtension | 1 + 42 files changed, 1268 insertions(+), 373 deletions(-) create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/TypeParameterMeta.java rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{AnnotationResolver.java => OpenAPIDefinitionResolver.java} (80%) delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContextImpl.java delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaProvider.java rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{ => proto}/ProtoEncoder.java (90%) create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/PrimitiveSchema.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaFactory.java rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{SchemaFactory.java => schema/SchemaResolver.java} (62%) create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension diff --git a/dubbo-distribution/dubbo-all-shaded/pom.xml b/dubbo-distribution/dubbo-all-shaded/pom.xml index c38df014a28..86dcd6e473a 100644 --- a/dubbo-distribution/dubbo-all-shaded/pom.xml +++ b/dubbo-distribution/dubbo-all-shaded/pom.xml @@ -882,6 +882,9 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver + + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml index ea3b05d3f47..9e3ca1976dd 100644 --- a/dubbo-distribution/dubbo-all/pom.xml +++ b/dubbo-distribution/dubbo-all/pom.xml @@ -880,6 +880,9 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver + + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping diff --git a/dubbo-distribution/dubbo-core-spi/pom.xml b/dubbo-distribution/dubbo-core-spi/pom.xml index e535005b44a..0c6c789847f 100644 --- a/dubbo-distribution/dubbo-core-spi/pom.xml +++ b/dubbo-distribution/dubbo-core-spi/pom.xml @@ -483,6 +483,9 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver + + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.route.RequestHandlerMapping diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java index 84cb8ffbf6f..3c2f77d0de7 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java @@ -28,8 +28,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.ConstructorMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.FieldMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.SetMethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; @@ -92,17 +91,10 @@ private Object resolveArgument(ParameterMeta paramMeta, HttpRequest request, Htt bean = constructor.newInstance(args); } - Set resolved = new HashSet<>(); - for (FieldMeta fieldMeta : beanMeta.getFields()) { - resolved.add(fieldMeta.getName()); - fieldMeta.setValue(bean, resolveArgument(fieldMeta, request, response)); - } - - for (SetMethodMeta methodMeta : beanMeta.getMethods()) { - if (resolved.contains(methodMeta.getName())) { - continue; + for (PropertyMeta propertyMeta : beanMeta.getProperties()) { + if (propertyMeta.canSetValue()) { + propertyMeta.setValue(bean, resolveArgument(propertyMeta, request, response)); } - methodMeta.setValue(bean, resolveArgument(methodMeta, request, response)); } return bean; diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java index 741a3a5f100..ae2f5057f10 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java @@ -71,7 +71,7 @@ public class MetadataServiceDelegation implements MetadataService, Disposable { public MetadataServiceDelegation(ApplicationModel applicationModel) { this.applicationModel = applicationModel; registryManager = RegistryManager.getInstance(applicationModel); - openAPIService = applicationModel.getFrameworkModel().getBeanFactory().getBean(OpenAPIService.class); + openAPIService = applicationModel.getBean(OpenAPIService.class); if (openAPIService != null) { openAPIService.export(); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java index 16d6b99302b..c2669d34f9a 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java @@ -39,6 +39,13 @@ @Documented public @interface OpenAPI { + /** + * The version of OpenAPI being used. + * e.g. 3.0.1, 3.1.0 + *

The default value is '3.0.1'. + */ + String version() default ""; + /** * The openAPI tags. *

Supported Syntax
@@ -58,17 +65,27 @@ /** * The title of the application. **/ - String title() default ""; + String infoTitle() default ""; /** * A short description of the application. **/ - String description() default ""; + String infoDescription() default ""; /** * The version of the API definition. **/ - String version() default ""; + String infoVersion() default ""; + + /** + * A description of the external documentation. + */ + String docDescription() default ""; + + /** + * The URL of the external documentation. + */ + String docUrl() default ""; /** * Indicates whether the mapping is hidden in OpenAPI. diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentConverter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentConverter.java index 6dd685706a4..2799b1b60b5 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentConverter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentConverter.java @@ -22,10 +22,9 @@ import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.TypeParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -114,29 +113,4 @@ private List getSuitableConverters(Class sourceType, Class ta return result; }); } - - private static final class TypeParameterMeta extends ParameterMeta { - - private final Class type; - - TypeParameterMeta(Class type) { - super(null, null); - this.type = type; - } - - @Override - public Class getType() { - return type; - } - - @Override - public Type getGenericType() { - return type; - } - - @Override - protected AnnotatedElement getAnnotatedElement() { - return Object.class; - } - } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java index 5c827876d16..15b213b8552 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java @@ -33,43 +33,50 @@ import java.lang.reflect.Type; import java.util.Collection; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; +import java.util.Set; public final class BeanMeta { - private final Map fields = new LinkedHashMap<>(); - private final Map methods = new LinkedHashMap<>(); + private final Class type; private final ConstructorMeta constructor; + private final Map properties = new LinkedHashMap<>(); - public BeanMeta(RestToolKit toolKit, String prefix, Class type) { - constructor = resolveConstructor(toolKit, prefix, type); - resolveFieldAndMethod(toolKit, prefix, type); - } - - public BeanMeta(RestToolKit toolKit, Class type) { - this(toolKit, null, type); + public BeanMeta(RestToolKit toolKit, String prefix, Class type, boolean skipConstructor) { + this.type = type; + constructor = skipConstructor ? null : resolveConstructor(toolKit, null, type); + resolveProperties(toolKit, prefix, type); } - public Collection getFields() { - return fields.values(); + public BeanMeta(RestToolKit toolKit, Class type, boolean skipConstructor) { + this(toolKit, null, type, skipConstructor); } - public FieldMeta getField(String name) { - return fields.get(name); + public BeanMeta(RestToolKit toolKit, String prefix, Class type) { + this(toolKit, prefix, type, false); } - public Collection getMethods() { - return methods.values(); + public BeanMeta(RestToolKit toolKit, Class type) { + this(toolKit, null, type, false); } - public SetMethodMeta getMethod(String name) { - return methods.get(name); + public Class getType() { + return type; } public ConstructorMeta getConstructor() { return constructor; } + public Collection getProperties() { + return properties.values(); + } + + public PropertyMeta getProperty(String name) { + return properties.get(name); + } + public Object newInstance() { return constructor.newInstance(); } @@ -91,46 +98,66 @@ public static ConstructorMeta resolveConstructor(RestToolKit toolKit, String pre return new ConstructorMeta(toolKit, prefix, ct); } - private void resolveFieldAndMethod(RestToolKit toolKit, String prefix, Class type) { - if (type == Object.class) { + private void resolveProperties(RestToolKit toolKit, String prefix, Class type) { + if (type == null || type == Object.class) { return; } + + Set allNames = new LinkedHashSet<>(); + Map fieldMap = new LinkedHashMap<>(); for (Field field : type.getDeclaredFields()) { - int modifiers = field.getModifiers(); - if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) { - continue; - } - if (field.getAnnotations().length == 0) { + if (Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())) { continue; } if (!field.isAccessible()) { field.setAccessible(true); } - FieldMeta fieldMeta = new FieldMeta(toolKit, prefix, field); - fields.put(fieldMeta.getName(), fieldMeta); + fieldMap.put(field.getName(), field); + allNames.add(field.getName()); } + Map getMethodMap = new LinkedHashMap<>(); + Map setMethodMap = new LinkedHashMap<>(); for (Method method : type.getDeclaredMethods()) { - if (method.getParameterCount() != 1) { - continue; - } int modifiers = method.getModifiers(); if ((modifiers & (Modifier.PUBLIC | Modifier.ABSTRACT | Modifier.STATIC)) == Modifier.PUBLIC) { - Parameter parameter = method.getParameters()[0]; String name = method.getName(); - if (name.length() > 3 && name.startsWith("set")) { - String getMethodName = "get" + name.substring(3); - Method getMethod = null; - try { - getMethod = type.getDeclaredMethod(getMethodName); - } catch (NoSuchMethodException ignored) { + int count = method.getParameterCount(); + if (count == 0) { + Class returnType = method.getReturnType(); + if (returnType == Void.TYPE) { + continue; + } + if (name.startsWith("get")) { + name = toName(name, 3); + getMethodMap.put(name, method); + allNames.add(name); + } else if (name.startsWith("is") && returnType == Boolean.TYPE) { + name = toName(name, 2); + getMethodMap.put(name, method); + allNames.add(name); + } + } else if (count == 1) { + if (name.startsWith("set")) { + name = toName(name, 3); + setMethodMap.put(name, method); + allNames.add(name); } - name = Character.toLowerCase(name.charAt(3)) + name.substring(4); - SetMethodMeta methodMeta = new SetMethodMeta(toolKit, method, getMethod, parameter, prefix, name); - methods.put(methodMeta.getName(), methodMeta); } } } - resolveFieldAndMethod(toolKit, prefix, type.getSuperclass()); + for (String name : allNames) { + Field field = fieldMap.get(name); + Method getMethod = getMethodMap.get(name); + Method setMethod = setMethodMap.get(name); + PropertyMeta meta = new PropertyMeta(toolKit, field, getMethod, setMethod, prefix, name); + properties.put(meta.getName(), meta); + } + + resolveProperties(toolKit, prefix, type.getSuperclass()); + } + + private static String toName(String name, int index) { + return Character.toLowerCase(name.charAt(index)) + name.substring(index + 1); } public static final class ConstructorMeta { @@ -222,12 +249,12 @@ public final String getName() { return name; } - public void setValue(Object bean, Object value) {} - public Object getValue(Object bean) { return null; } + public void setValue(Object bean, Object value) {} + public final NestableParameterMeta getNestedMeta() { return nestedMeta; } @@ -251,104 +278,95 @@ protected final void initNestedMeta() { } } - public static final class FieldMeta extends NestableParameterMeta { + public static final class PropertyMeta extends NestableParameterMeta { private final Field field; - - FieldMeta(RestToolKit toolKit, String prefix, Field field) { - super(toolKit, prefix, field.getName()); - this.field = field; - initNestedMeta(); - } - - @Override - public Class getType() { - return field.getType(); - } - - @Override - public Type getGenericType() { - return field.getGenericType(); - } - - @Override - protected AnnotatedElement getAnnotatedElement() { - return field; - } - - public void setValue(Object bean, Object value) { - try { - field.set(bean, value); - } catch (Throwable t) { - throw ExceptionUtils.wrap(t); - } - } - - public Object getValue(Object bean) { - try { - return field.get(bean); - } catch (Throwable t) { - throw ExceptionUtils.wrap(t); - } - } - - @Override - public String getDescription() { - return "FieldParameter{" + field + '}'; - } - } - - public static final class SetMethodMeta extends NestableParameterMeta { - - private final Method method; private final Method getMethod; + private final Method setMethod; private final Parameter parameter; - SetMethodMeta(RestToolKit toolKit, Method m, Method gm, Parameter p, String prefix, String name) { + PropertyMeta(RestToolKit toolKit, Field f, Method gm, Method sm, String prefix, String name) { super(toolKit, prefix, name); - method = m; + field = f; getMethod = gm; - parameter = p; + setMethod = sm; + parameter = setMethod == null ? null : setMethod.getParameters()[0]; initNestedMeta(); } @Override public Class getType() { - return parameter.getType(); + if (field != null) { + return field.getType(); + } + if (parameter != null) { + return parameter.getType(); + } + return getMethod.getReturnType(); } @Override public Type getGenericType() { - return parameter.getParameterizedType(); + if (field != null) { + return field.getGenericType(); + } + if (parameter != null) { + return parameter.getParameterizedType(); + } + return getMethod.getGenericReturnType(); } @Override protected AnnotatedElement getAnnotatedElement() { - return parameter; - } - - public void setValue(Object bean, Object value) { - try { - method.invoke(bean, value); - } catch (Throwable t) { - throw ExceptionUtils.wrap(t); + if (field != null) { + return field; } + if (parameter != null) { + return parameter; + } + return getMethod; } public Object getValue(Object bean) { - if (getMethod == null) { - return null; + if (getMethod != null) { + try { + return getMethod.invoke(bean); + } catch (Throwable t) { + throw ExceptionUtils.wrap(t); + } + } else if (field != null) { + try { + return field.get(bean); + } catch (Throwable t) { + throw ExceptionUtils.wrap(t); + } } - try { - return getMethod.invoke(bean); - } catch (Throwable t) { - throw ExceptionUtils.wrap(t); + return null; + } + + public void setValue(Object bean, Object value) { + if (setMethod != null) { + try { + setMethod.invoke(bean, value); + } catch (Throwable t) { + throw ExceptionUtils.wrap(t); + } + } else if (field != null) { + try { + field.set(bean, value); + } catch (Throwable t) { + throw ExceptionUtils.wrap(t); + } } } @Override public String getDescription() { - return "SetMethodParameter{" + method + '}'; + return "PropertyMeta{" + (field == null ? (parameter == null ? getMethod : parameter) : field) + '}'; + } + + public boolean canSetValue() { + return setMethod != null || field != null; } } @@ -376,7 +394,7 @@ public Type getGenericType() { @Override protected AnnotatedElement getAnnotatedElement() { - return null; + return type; } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java index 87667690738..9e7fce0cae5 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java @@ -35,6 +35,7 @@ public final class MethodMeta extends AnnotationSupport { private final Method method; private MethodDescriptor methodDescriptor; private ParameterMeta[] parameters; + private ParameterMeta returnParameter; private final ServiceMeta serviceMeta; public MethodMeta(List hierarchy, MethodDescriptor methodDescriptor, ServiceMeta serviceMeta) { @@ -106,6 +107,14 @@ public ParameterMeta[] getParameters() { return parameters; } + public ParameterMeta getReturnParameter() { + ParameterMeta returnParameter = this.returnParameter; + if (returnParameter == null) { + this.returnParameter = returnParameter = new ReturnParameterMeta(getToolKit(), hierarchy, method); + } + return returnParameter; + } + public ServiceMeta getServiceMeta() { return serviceMeta; } @@ -197,4 +206,36 @@ protected List getAnnotatedElements() { return elements; } } + + private static final class ReturnParameterMeta extends ParameterMeta { + + private final List hierarchy; + private final Method method; + + ReturnParameterMeta(RestToolKit toolKit, List hierarchy, Method method) { + super(toolKit, null); + this.hierarchy = hierarchy; + this.method = method; + } + + @Override + public Class getType() { + return method.getReturnType(); + } + + @Override + public Type getGenericType() { + return method.getGenericReturnType(); + } + + @Override + protected List getAnnotatedElements() { + return hierarchy; + } + + @Override + protected AnnotatedElement getAnnotatedElement() { + return method; + } + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/TypeParameterMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/TypeParameterMeta.java new file mode 100644 index 00000000000..edbf75f196a --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/TypeParameterMeta.java @@ -0,0 +1,53 @@ +/* + * 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.protocol.tri.rest.mapping.meta; + +import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; +import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Type; + +public final class TypeParameterMeta extends ParameterMeta { + + private final Type type; + + public TypeParameterMeta(RestToolKit toolKit, Type type) { + super(toolKit, null); + this.type = type; + } + + public TypeParameterMeta(Type type) { + super(null, null); + this.type = type; + } + + @Override + public Class getType() { + return TypeUtils.getActualType(type); + } + + @Override + public Type getGenericType() { + return type; + } + + @Override + protected AnnotatedElement getAnnotatedElement() { + return getActualType(); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java index 2486f5a45f8..450e63c49bd 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java @@ -18,6 +18,7 @@ import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; import java.util.HashMap; import java.util.Map; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java index b94c8890d9e..6ff8a875e3e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java @@ -20,6 +20,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; public interface Context { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java index 0bd53ccacd2..083a657e498 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java @@ -20,6 +20,7 @@ import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; final class ContextImpl extends AbstractContext implements Context { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index 49101dd9374..9c9656eddd3 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.common.logger.FluentLogger; +import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; import org.apache.dubbo.common.utils.LRUCache; import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.rpc.model.FrameworkModel; @@ -34,11 +35,15 @@ import java.util.IdentityHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; public class DefaultOpenAPIService implements OpenAPIService { private static final FluentLogger LOG = FluentLogger.of(DefaultOpenAPIService.class); + private final LRUCache> cache = new LRUCache<>(64); + private final FrameworkModel frameworkModel; private final ExtensionFactory extensionFactory; private final DefinitionResolver definitionResolver; private final DefinitionMerger definitionMerger; @@ -46,16 +51,17 @@ public class DefaultOpenAPIService implements OpenAPIService { private final DefinitionEncoder definitionEncoder; private RequestMappingRegistry requestMappingRegistry; - private final LRUCache> cache; private volatile List openAPIs; + private boolean exported; + private ScheduledFuture exportFuture; public DefaultOpenAPIService(FrameworkModel frameworkModel) { + this.frameworkModel = frameworkModel; extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); definitionResolver = new DefinitionResolver(frameworkModel); definitionMerger = new DefinitionMerger(frameworkModel); definitionFilter = new DefinitionFilter(frameworkModel); definitionEncoder = new DefinitionEncoder(frameworkModel); - cache = new LRUCache<>(64); } public void setRequestMappingRegistry(RequestMappingRegistry requestMappingRegistry) { @@ -83,6 +89,7 @@ private List resolveOpenAPIs() { .computeIfAbsent(meta.getMethod().getMethod(), k -> new ArrayList<>(1)) .add(registration); } + List openAPIs = new ArrayList<>(byClassMap.size()); for (Map.Entry>> entry : byClassMap.entrySet()) { OpenAPI openAPI = definitionResolver.resolve( @@ -92,6 +99,7 @@ private List resolveOpenAPIs() { } } openAPIs.sort(Comparator.comparingInt(OpenAPI::getPriority)); + return openAPIs; } @@ -115,10 +123,32 @@ public void refresh() { LOG.debug("Refreshing OpenAPI documents"); openAPIs = null; cache.clear(); + if (exported) { + export(); + } + OpenAPIRequest request = new OpenAPIRequest(); + request.setPretty(true); + String openAPI = getDocument(request); + LOG.info("Refreshed OpenAPI documents: {}", openAPI); } @Override public void export() { + if (extensionFactory.getExtensions(DocumentPublisher.class).length == 0) { + return; + } + + if (exportFuture != null) { + exportFuture.cancel(false); + } + exportFuture = frameworkModel + .getBean(FrameworkExecutorRepository.class) + .getMetadataRetryExecutor() + .schedule(this::doExport, 30, TimeUnit.SECONDS); + exported = true; + } + + private void doExport() { for (DocumentPublisher publisher : extensionFactory.getExtensions(DocumentPublisher.class)) { try { publisher.publish(request -> { @@ -130,6 +160,7 @@ public void export() { LOG.internalWarn("Failed to publish OpenAPI document by {}", publisher, t); } } + exportFuture = null; } private static final class Key { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java index 61fed4ead19..962d9c10eba 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java @@ -21,6 +21,8 @@ import org.apache.dubbo.remoting.http12.message.codec.YamlCodec; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.proto.ProtoEncoder; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; @@ -40,6 +42,9 @@ final class DefinitionEncoder { } public String encode(OpenAPI openAPI, OpenAPIRequest request) { + if (openAPI == null) { + openAPI = new OpenAPI(); + } Map root = new LinkedHashMap<>(); ContextImpl context = new ContextImpl(openAPI, schemaFactory, extensionFactory, request); openAPI.writeTo(root, context); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java index ba6166f696d..9234cfcad75 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java @@ -30,6 +30,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; import java.util.Iterator; import java.util.List; @@ -156,7 +157,7 @@ private void filterParameter(Operation operation, OpenAPIFilter[] filters, Conte it.set(parameter); } - filterContext(parameter.getContent(), filters, context); + filterContext(parameter.getContents(), filters, context); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index 848c8e82b1c..99f2853fd61 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -21,38 +21,42 @@ import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Components; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Contact; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Header; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.License; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Node; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityRequirement; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; -import java.lang.reflect.Type; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.formatVersion; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim; + final class DefinitionMerger { private static final FluentLogger LOG = FluentLogger.of(DefinitionMerger.class); - private final ExtensionFactory extensionFactory; private final ConfigFactory configFactory; DefinitionMerger(FrameworkModel frameworkModel) { - extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); } @@ -60,6 +64,7 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { OpenAPI result = new OpenAPI(); if (openAPIs.isEmpty()) { + applyConfig(result, configFactory.getGlobalConfig()); return result; } @@ -67,8 +72,6 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { if (group == null) { group = Constants.DEFAULT_GROUP; } - String[] tags = trim(request.getTags()); - String service = trim(request.getService()); String version = trim(request.getVersion()); if (version != null) { result.setOpenapi(formatVersion(version)); @@ -76,28 +79,30 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { applyConfig(result, configFactory.getConfig(group)); - for (OpenAPI openAPI : openAPIs) { + String[] tags = trim(request.getTags()); + String service = trim(request.getService()); + for (OpenAPI api : openAPIs) { if (service != null) { - String serviceName = openAPI.getService().getServiceDescriptor().getInterfaceName(); - if (serviceName != null && !serviceName.regionMatches(true, 0, service, 0, service.length())) { + String apiService = api.getService().getServiceInterface(); + if (apiService != null && !apiService.regionMatches(true, 0, service, 0, service.length())) { continue; } } - if (group.equals(openAPI.getGroup())) { - mergeBasic(result, openAPI); + if (group.equals(api.getGroup())) { + mergeBasic(result, api); } - mergePaths(result, openAPI, group, tags); + mergePaths(result, api, group, tags); - mergeSecuritySchemes(result, openAPI); + mergeSecuritySchemes(result, api); - mergeTags(result, openAPI); + mergeTags(result, api); } applyConfig(result, configFactory.getGlobalConfig()); - addRefSchemas(result); + addSchemas(result); cleanup(result); @@ -170,9 +175,9 @@ private void applyConfig(OpenAPI api, OpenAPIConfig config) { String securityScheme = config.getSecurityScheme(); if (securityScheme != null) { try { - Type type = - Components.class.getDeclaredField("securitySchemes").getGenericType(); - components.setSecuritySchemes(JsonUtils.toJavaObject(securityScheme, type)); + components.setSecuritySchemes(JsonUtils.toJavaObject( + securityScheme, + Components.class.getDeclaredField("securitySchemes").getGenericType())); } catch (NoSuchFieldException ignored) { } } @@ -219,58 +224,60 @@ private void mergeBasic(OpenAPI api, OpenAPI from) { private void mergeInfo(OpenAPI api, OpenAPI from) { Info fromInfo = from.getInfo(); - if (fromInfo != null) { - Info info = api.getInfo(); - if (info.getTitle() == null) { - info.setTitle(fromInfo.getTitle()); - } - if (info.getSummary() == null) { - info.setDescription(fromInfo.getSummary()); - } - if (info.getDescription() == null) { - info.setDescription(fromInfo.getDescription()); - } - if (info.getTermsOfService() == null) { - info.setTermsOfService(fromInfo.getTermsOfService()); - } + if (fromInfo == null) { + return; + } - Contact fromContact = fromInfo.getContact(); - if (fromContact != null) { - Contact contact = info.getContact(); - if (contact.getName() == null) { - contact.setName(fromContact.getName()); - } - if (contact.getUrl() == null) { - contact.setUrl(fromContact.getUrl()); - } - if (contact.getEmail() == null) { - contact.setEmail(fromContact.getEmail()); - } + Info info = api.getInfo(); + if (info.getTitle() == null) { + info.setTitle(fromInfo.getTitle()); + } + if (info.getSummary() == null) { + info.setDescription(fromInfo.getSummary()); + } + if (info.getDescription() == null) { + info.setDescription(fromInfo.getDescription()); + } + if (info.getTermsOfService() == null) { + info.setTermsOfService(fromInfo.getTermsOfService()); + } - if (info.getVersion() == null) { - info.setVersion(fromInfo.getVersion()); - } - contact.addExtensions(fromContact.getExtensions()); + Contact fromContact = fromInfo.getContact(); + if (fromContact != null) { + Contact contact = info.getContact(); + if (contact.getName() == null) { + contact.setName(fromContact.getName()); } - - License fromLicense = fromInfo.getLicense(); - if (fromLicense != null) { - License license = info.getLicense(); - if (license.getName() == null) { - license.setName(fromLicense.getName()); - } - if (license.getUrl() == null) { - license.setUrl(fromLicense.getUrl()); - } - license.addExtensions(fromLicense.getExtensions()); + if (contact.getUrl() == null) { + contact.setUrl(fromContact.getUrl()); + } + if (contact.getEmail() == null) { + contact.setEmail(fromContact.getEmail()); } if (info.getVersion() == null) { info.setVersion(fromInfo.getVersion()); } + contact.addExtensions(fromContact.getExtensions()); + } + + License fromLicense = fromInfo.getLicense(); + if (fromLicense != null) { + License license = info.getLicense(); + if (license.getName() == null) { + license.setName(fromLicense.getName()); + } + if (license.getUrl() == null) { + license.setUrl(fromLicense.getUrl()); + } + license.addExtensions(fromLicense.getExtensions()); + } - info.addExtensions(fromInfo.getExtensions()); + if (info.getVersion() == null) { + info.setVersion(fromInfo.getVersion()); } + + info.addExtensions(fromInfo.getExtensions()); } private void mergePaths(OpenAPI api, OpenAPI from, String group, String[] tags) { @@ -318,6 +325,7 @@ private void mergePathItem(String path, PathItem pathItem, PathItem from, String for (Entry entry : fromOperations.entrySet()) { HttpMethods httpMethod = entry.getKey(); Operation fromOperation = entry.getValue(); + if (!group.equals(fromOperation.getGroup())) { continue; } @@ -403,55 +411,103 @@ private void mergeSecuritySchemes(OpenAPI api, OpenAPI from) { private void mergeTags(OpenAPI api, OpenAPI from) { List fromTags = from.getTags(); - if (fromTags != null) { - if (api.getTags() == null) { - api.setTags(Node.clone(fromTags)); - } else { - for (Tag tag : fromTags) { - api.addTag(tag.clone()); - } + if (fromTags == null) { + return; + } + + if (api.getTags() == null) { + api.setTags(Node.clone(fromTags)); + } else { + for (Tag tag : fromTags) { + api.addTag(tag.clone()); } } } - private void addRefSchemas(OpenAPI api) {} - - private void cleanup(OpenAPI api) {} - - private static String formatVersion(String version) { - if (version == null) { - return null; + private void addSchemas(OpenAPI api) { + Components components = api.getComponents(); + if (components == null) { + api.setComponents(components = new Components()); } - if (version.startsWith("3.1")) { - return Constants.VERSION_31; + Map schemas = components.getSchemas(); + if (schemas == null) { + components.setSchemas(schemas = new TreeMap<>()); } - return Constants.VERSION_30; - } - private static String trim(String str) { - if (str == null || str.isEmpty()) { - return null; + for (PathItem pathItem : api.getPaths().values()) { + for (Operation operation : pathItem.getOperations().values()) { + List parameters = operation.getParameters(); + if (parameters != null) { + for (Parameter parameter : parameters) { + addSchema(parameter.getSchema(), schemas); + Map contents = parameter.getContents(); + if (contents == null) { + continue; + } + for (MediaType mediaType : contents.values()) { + addSchema(mediaType.getSchema(), schemas); + } + } + } + RequestBody requestBody = operation.getRequestBody(); + if (requestBody != null) { + Map contents = requestBody.getContents(); + if (contents == null) { + continue; + } + for (MediaType mediaType : contents.values()) { + addSchema(mediaType.getSchema(), schemas); + } + } + Map responses = operation.getResponses(); + if (responses != null) { + for (ApiResponse response : responses.values()) { + Map headers = response.getHeaders(); + if (headers != null) { + for (Header header : headers.values()) { + addSchema(header.getSchema(), schemas); + } + } + + Map contents = response.getContents(); + if (contents == null) { + continue; + } + for (MediaType mediaType : contents.values()) { + addSchema(mediaType.getSchema(), schemas); + } + } + } + } } - str = str.trim(); - return str.isEmpty() ? null : str; } - private static String[] trim(String[] array) { - if (array == null) { - return null; + private void addSchema(Schema schema, Map schemas) { + if (schema == null) { + return; } - int len = array.length; - if (len == 0) { - return null; + Schema targetSchema = schema.getTargetSchema(); + if (targetSchema == null) { + return; } - int p = 0; - for (int i = 0; i < len; i++) { - String value = trim(array[i]); - if (value != null) { - array[p++] = value; + + String name = targetSchema.getJavaType().getName(); + schema.setRef(name); + if (schemas.putIfAbsent(name, targetSchema) != null) { + return; + } + + addSchema(targetSchema.getItems(), schemas); + + Map properties = targetSchema.getProperties(); + if (properties != null) { + for (Schema property : properties.values()) { + addSchema(property, schemas); } } - int newLen = p + 1; - return newLen == len ? array : Arrays.copyOf(array, newLen); + + addSchema(targetSchema.getAdditionalPropertiesSchema(), schemas); } + + private void cleanup(OpenAPI api) {} } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index e7411a4adf5..89554400349 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -39,6 +39,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; import java.util.Arrays; import java.util.Collection; @@ -50,23 +51,22 @@ final class DefinitionResolver { private static final FluentLogger LOG = FluentLogger.of(DefaultOpenAPIService.class); - private final List annotationResolvers; private final ExtensionFactory extensionFactory; private final ConfigFactory configFactory; private final SchemaFactory schemaFactory; + private final OpenAPIDefinitionResolver[] resolvers; DefinitionResolver(FrameworkModel frameworkModel) { - annotationResolvers = frameworkModel.getActivateExtensions(AnnotationResolver.class); extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); schemaFactory = frameworkModel.getOrRegisterBean(SchemaFactory.class); + resolvers = extensionFactory.getExtensions(OpenAPIDefinitionResolver.class); } public OpenAPI resolve(ServiceMeta serviceMeta, Collection> registrationsByMethod) { OpenAPI openAPI = null; - List resolvers = annotationResolvers; - for (int i = 0, size = resolvers.size(); i < size; i++) { - AnnotationResolver resolver = resolvers.get(i); + + for (OpenAPIDefinitionResolver resolver : resolvers) { if (resolver.hidden(serviceMeta)) { return null; } @@ -75,6 +75,7 @@ public OpenAPI resolve(ServiceMeta serviceMeta, Collection> r break; } } + if (openAPI == null) { openAPI = new OpenAPI(); } @@ -126,9 +127,8 @@ private boolean resolvePath( ResolveContext context) { Operation operation = null; Collection httpMethods = null; - List resolvers = annotationResolvers; - for (int i = 0, size = resolvers.size(); i < size; i++) { - AnnotationResolver resolver = resolvers.get(i); + + for (OpenAPIDefinitionResolver resolver : resolvers) { if (resolver.hidden(meta, openAPI, context)) { return false; } @@ -173,6 +173,7 @@ private boolean resolvePath( operation.setMethod(meta); resolveOperation(httpMethod, operation, openAPI, meta, mapping); } + return true; } @@ -236,7 +237,7 @@ private String generateOperationId(MethodMeta meta, OpenAPI openAPI) { if (name == null) { return null; } - NamingStrategy strategy = extensionFactory.getExtension(NamingStrategy.class, "naming-strategy-" + name); + NamingStrategy strategy = extensionFactory.getExtension(NamingStrategy.class, NamingStrategy.PREFIX + name); if (strategy == null) { return null; } @@ -245,7 +246,7 @@ private String generateOperationId(MethodMeta meta, OpenAPI openAPI) { private void resolveParameter(Parameter parameter, ParameterMeta meta) { if (parameter.getSchema() == null) { - parameter.setSchema(schemaFactory.getSchema(meta.getActualGenericType())); + parameter.setSchema(schemaFactory.getSchema(meta)); } } @@ -298,9 +299,16 @@ private void resolveResponse( if (httpStatus >= 400) { content.setSchema(schemaFactory.getSchema(ErrorResponse.class)); } else { - content.setSchema(schemaFactory.getSchema(meta.getParameters())); + content.setSchema(schemaFactory.getSchema(meta.getReturnParameter())); } } } } + + static final class ResolveContextImpl extends AbstractContext implements ResolveContext { + + ResolveContextImpl(OpenAPI openAPI, SchemaFactory schemaFactory, ExtensionFactory extensionFactory) { + super(openAPI, schemaFactory, extensionFactory); + } + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java index c3db141552e..b88cb3bf05a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java @@ -26,23 +26,28 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.function.Supplier; @SuppressWarnings("unchecked") public final class ExtensionFactory { private final ExtensionLoader extensionLoader; private final List extensions; - private final Map cache = CollectionUtils.newConcurrentHashMap(); + private final Map cache; public ExtensionFactory(FrameworkModel frameworkModel) { extensionLoader = frameworkModel.getExtensionLoader(OpenAPIExtension.class); extensions = extensionLoader.getActivateExtensions(); + cache = CollectionUtils.newConcurrentHashMap(); } public T[] getExtensions(Class type) { return (T[]) cache.computeIfAbsent(type, k -> { List list = new ArrayList<>(); for (OpenAPIExtension extension : extensions) { + if (extension instanceof Supplier) { + extension = ((Supplier) extension).get(); + } if (type.isInstance(extension)) { list.add(extension); } @@ -55,6 +60,9 @@ public T[] getExtensions(Class type, String grou return (T[]) cache.computeIfAbsent(Pair.of(type, group), k -> { List list = new ArrayList<>(); for (OpenAPIExtension extension : extensions) { + if (extension instanceof Supplier) { + extension = ((Supplier) extension).get(); + } if (type.isInstance(extension) && accept(extension, group)) { list.add(extension); } @@ -65,6 +73,9 @@ public T[] getExtensions(Class type, String grou public T getExtension(Class type, String name) { OpenAPIExtension extension = extensionLoader.getExtension(name, true); + if (extension instanceof Supplier) { + extension = ((Supplier) extension).get(); + } return type.isInstance(extension) ? (T) extension : null; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index a3688789134..32796bd8b5d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -16,15 +16,18 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathSegment; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import static org.apache.dubbo.remoting.http12.HttpMethods.DELETE; import static org.apache.dubbo.remoting.http12.HttpMethods.GET; @@ -110,4 +113,61 @@ public static In toIn(ParamType paramType) { return null; } } + + public static String formatVersion(String version) { + if (version == null) { + return null; + } + if (version.startsWith("3.1")) { + return Constants.VERSION_31; + } + return Constants.VERSION_30; + } + + public static String trim(String str) { + if (str == null || str.isEmpty()) { + return null; + } + str = str.trim(); + return str.isEmpty() ? null : str; + } + + public static String[] trim(String[] array) { + if (array == null) { + return null; + } + int len = array.length; + if (len == 0) { + return null; + } + int p = 0; + for (int i = 0; i < len; i++) { + String value = trim(array[i]); + if (value != null) { + array[p++] = value; + } + } + int newLen = p + 1; + return newLen == len ? array : Arrays.copyOf(array, newLen); + } + + public static Map toProperties(String[] array) { + if (array == null) { + return Collections.emptyMap(); + } + int len = array.length; + if (len == 0) { + return Collections.emptyMap(); + } + Map properties = CollectionUtils.newLinkedHashMap(len); + for (String item : array) { + int index = item.indexOf('='); + if (index > 0) { + properties.put(trim(item.substring(0, index)), trim(item.substring(index + 1))); + } else { + properties.put(trim(item), null); + } + } + return properties; + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/NamingStrategy.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/NamingStrategy.java index 7beea21bd23..1c2d0c04a76 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/NamingStrategy.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/NamingStrategy.java @@ -21,6 +21,8 @@ public interface NamingStrategy extends OpenAPIExtension { + String PREFIX = "naming-strategy-"; + default String generateOperationId(MethodMeta methodMeta, OpenAPI openAPI) { return null; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AnnotationResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java similarity index 80% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AnnotationResolver.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java index 71c30f5a2b4..f2701691467 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AnnotationResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java @@ -16,21 +16,22 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; -import org.apache.dubbo.common.extension.ExtensionScope; -import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; -@SPI(scope = ExtensionScope.FRAMEWORK) -public interface AnnotationResolver { +public interface OpenAPIDefinitionResolver extends OpenAPIExtension { - boolean hidden(ServiceMeta serviceMeta); + default boolean hidden(ServiceMeta serviceMeta) { + return false; + } OpenAPI resolve(ServiceMeta serviceMeta); - boolean hidden(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context); + default boolean hidden(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { + return false; + } Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java index 5ffc8c0baf2..0ab0b54b08a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java @@ -18,10 +18,9 @@ import org.apache.dubbo.common.extension.ExtensionScope; import org.apache.dubbo.common.extension.SPI; -import org.apache.dubbo.common.lang.Prioritized; @SPI(scope = ExtensionScope.FRAMEWORK) -public interface OpenAPIExtension extends Prioritized { +public interface OpenAPIExtension { default String[] getGroups() { return null; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java index 0b0f53f9b2b..c68aa8c91ab 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java @@ -18,6 +18,7 @@ import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; public interface ResolveContext { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContextImpl.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContextImpl.java deleted file mode 100644 index 920f4b922e7..00000000000 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContextImpl.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.protocol.tri.rest.openapi; - -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; - -final class ResolveContextImpl extends AbstractContext implements ResolveContext { - - ResolveContextImpl(OpenAPI openAPI, SchemaFactory schemaFactory, ExtensionFactory extensionFactory) { - super(openAPI, schemaFactory, extensionFactory); - } -} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaProvider.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaProvider.java deleted file mode 100644 index dd84c4adf4d..00000000000 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaProvider.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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.protocol.tri.rest.openapi; - -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; - -public interface SchemaProvider extends OpenAPIExtension { - - Schema getSchema(Class clazz); -} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java index df76078537f..06eac439c85 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java @@ -43,7 +43,7 @@ public T addExtension(String name, Object value) { } @SuppressWarnings("unchecked") - public T addExtensions(Map extensions) { + public T addExtensions(Map extensions) { if (extensions == null || extensions.isEmpty()) { return (T) this; } @@ -52,7 +52,7 @@ public T addExtensions(Map extensions) { if (thisExtensions == null) { this.extensions = new LinkedHashMap<>(extensions); } else { - for (Map.Entry entry : extensions.entrySet()) { + for (Map.Entry entry : extensions.entrySet()) { thisExtensions.putIfAbsent(entry.getKey(), entry.getValue()); } } @@ -65,7 +65,7 @@ public void removeExtension(String name) { } } - public void setExtensions(Map extensions) { + public void setExtensions(Map extensions) { this.extensions = new LinkedHashMap<>(extensions); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java index 239791e94d7..584cee0212d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java @@ -18,6 +18,7 @@ import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.util.ArrayList; @@ -257,7 +258,7 @@ public OpenAPI clone() { @Override public Map writeTo(Map node, Context context) { - node.put("openapi", openapi); + node.put("openapi", openapi == null ? Constants.VERSION_30 : openapi); write(node, "info", info, context); write(node, "servers", servers, context); write(node, "paths", paths, context); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java index c3a26e79d76..25e3d64e6a7 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java @@ -275,7 +275,7 @@ public Operation setMethod(MethodMeta method) { public Operation clone() { Operation clone = super.clone(); if (tags != null) { - clone.tags = new ArrayList<>(tags); + clone.tags = new LinkedHashSet<>(tags); } clone.externalDocs = clone(externalDocs); clone.parameters = clone(parameters); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java index 7489ef82495..77bec3c5ee8 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java @@ -76,7 +76,7 @@ public String toString() { private Schema schema; private Object example; private Map examples; - private Map content; + private Map contents; private transient ParameterMeta meta; @@ -198,26 +198,26 @@ public Parameter removeExample(String name) { return this; } - public Map getContent() { - return content; + public Map getContents() { + return contents; } - public Parameter setContent(Map content) { - this.content = content; + public Parameter setContents(Map contents) { + this.contents = contents; return this; } public Parameter addContent(String name, MediaType mediaType) { - if (content == null) { - content = new LinkedHashMap<>(); + if (contents == null) { + contents = new LinkedHashMap<>(); } - content.put(name, mediaType); + contents.put(name, mediaType); return this; } public Parameter removeContent(String name) { - if (content != null) { - content.remove(name); + if (contents != null) { + contents.remove(name); } return this; } @@ -253,7 +253,7 @@ public Parameter clone() { Parameter clone = super.clone(); clone.schema = clone(schema); clone.examples = clone(examples); - clone.content = clone(content); + clone.contents = clone(contents); return clone; } @@ -271,7 +271,7 @@ public Map writeTo(Map node, Context context) { write(node, "schema", schema, context); write(node, "example", example); write(node, "examples", examples, context); - write(node, "content", content, context); + write(node, "content", contents, context); writeExtensions(node); return node; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java index 66ff84f7098..25bbf010c78 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java @@ -85,6 +85,9 @@ public String toString() { private Boolean writeOnly; private Boolean deprecated; + private transient Schema targetSchema; + private transient Class javaType; + public String getRef() { return ref; } @@ -326,12 +329,19 @@ public Map getProperties() { return properties; } + public Schema getProperty(String name) { + return properties == null ? null : properties.get(name); + } + public Schema setProperties(Map properties) { this.properties = properties; return this; } public Schema addProperty(String name, Schema schema) { + if (schema == null) { + return this; + } if (properties == null) { properties = new LinkedHashMap<>(); } @@ -496,6 +506,24 @@ public Schema setDeprecated(Boolean deprecated) { return this; } + public Schema getTargetSchema() { + return targetSchema; + } + + public Schema setTargetSchema(Schema targetSchema) { + this.targetSchema = targetSchema; + return this; + } + + public Class getJavaType() { + return javaType; + } + + public Schema setJavaType(Class javaType) { + this.javaType = javaType; + return this; + } + @Override public Schema clone() { Schema clone = super.clone(); @@ -520,7 +548,10 @@ public Schema clone() { @Override public Map writeTo(Map schema, Context context) { - write(schema, "$ref", ref); + if (ref != null) { + schema.put("$ref", ref); + return schema; + } write(schema, "format", format); write(schema, "name", name); write(schema, "title", title); @@ -541,7 +572,9 @@ public Map writeTo(Map schema, Context context) write(schema, "minProperties", minProperties); write(schema, "required", required); write(schema, "enum", enumeration); - write(schema, "type", type); + if (type != null) { + write(schema, "type", type.toString()); + } write(schema, "items", items, context); write(schema, "properties", properties, context); if (additionalPropertiesBoolean == null) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/proto/ProtoEncoder.java similarity index 90% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/proto/ProtoEncoder.java index f35cb1b52ce..43215707984 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/proto/ProtoEncoder.java @@ -14,11 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +package org.apache.dubbo.rpc.protocol.tri.rest.openapi.proto; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -final class ProtoEncoder { +public final class ProtoEncoder { public String encode(OpenAPI openAPI) { return ""; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/PrimitiveSchema.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/PrimitiveSchema.java new file mode 100644 index 00000000000..9fe18392b17 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/PrimitiveSchema.java @@ -0,0 +1,139 @@ +/* + * 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.protocol.tri.rest.openapi.schema; + +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Primitive Schema + * Format: Formats Registry + */ +public enum PrimitiveSchema { + STRING(String.class, Type.STRING), + BOOLEAN(Boolean.class, Type.BOOLEAN), + BYTE(Byte.class, Type.STRING, "byte"), + BINARY(Byte.class, Type.STRING, "binary"), + URI(java.net.URI.class, Type.STRING, "uri"), + URL(java.net.URL.class, Type.STRING, "url"), + EMAIL(String.class, Type.STRING, "email"), + PASSWORD(String.class, Type.STRING, "password"), + UUID(java.util.UUID.class, Type.STRING, "uuid"), + INT(Integer.class, Type.INTEGER, "int32"), + LONG(Long.class, Type.INTEGER, "int64"), + FLOAT(Float.class, Type.NUMBER, "float"), + DOUBLE(Double.class, Type.NUMBER, "double"), + INTEGER(java.math.BigInteger.class, Type.INTEGER), + DECIMAL(java.math.BigDecimal.class, Type.NUMBER, "number"), + NUMBER(Number.class, Type.NUMBER), + IP_V4(java.net.Inet4Address.class, Type.STRING, "ipv4"), + IP_V6(java.net.Inet6Address.class, Type.STRING, "ipv6"), + DATE_TIME(java.util.Date.class, Type.STRING, "date-time"), + DATE(java.time.LocalDate.class, Type.STRING, "date"), + TIME(java.time.LocalTime.class, Type.STRING, "time"), + DURATION(java.time.Duration.class, Type.STRING, "duration"), + FILE(java.io.File.class, Type.STRING, "binary"), + OBJECT(Object.class, Type.OBJECT), + ARRAY(Object[].class, Type.ARRAY); + + private static final Map TYPE_MAPPING = new ConcurrentHashMap<>(); + private static final List SYSTEM_PREFIXES = new CopyOnWriteArrayList<>(); + + static { + for (PrimitiveSchema schema : values()) { + TYPE_MAPPING.putIfAbsent(schema.keyClass, schema); + } + TYPE_MAPPING.put(boolean.class, BOOLEAN); + TYPE_MAPPING.put(byte.class, BYTE); + TYPE_MAPPING.put(char.class, STRING); + TYPE_MAPPING.put(Character.class, STRING); + TYPE_MAPPING.put(short.class, INT); + TYPE_MAPPING.put(Short.class, INT); + TYPE_MAPPING.put(int.class, INT); + TYPE_MAPPING.put(long.class, LONG); + TYPE_MAPPING.put(float.class, FLOAT); + TYPE_MAPPING.put(double.class, DOUBLE); + TYPE_MAPPING.put(byte[].class, BYTE); + + TYPE_MAPPING.put(java.util.Calendar.class, DATE_TIME); + TYPE_MAPPING.put(java.sql.Date.class, DATE_TIME); + TYPE_MAPPING.put(java.time.Instant.class, DATE_TIME); + TYPE_MAPPING.put(java.time.LocalDateTime.class, DATE_TIME); + TYPE_MAPPING.put(java.time.ZonedDateTime.class, DATE_TIME); + TYPE_MAPPING.put(java.time.OffsetDateTime.class, DATE_TIME); + TYPE_MAPPING.put(java.time.OffsetTime.class, TIME); + TYPE_MAPPING.put(java.time.Period.class, DURATION); + TYPE_MAPPING.put("javax.xml.datatype.XMLGregorianCalendar", DATE_TIME); + TYPE_MAPPING.put("org.joda.time.LocalDateTime", DATE_TIME); + TYPE_MAPPING.put("org.joda.time.ReadableDateTime", DATE_TIME); + TYPE_MAPPING.put("org.joda.time.DateTime", DATE_TIME); + TYPE_MAPPING.put("org.joda.time.LocalTime", TIME); + + TYPE_MAPPING.put(CharSequence.class, STRING); + TYPE_MAPPING.put(StringBuffer.class, STRING); + TYPE_MAPPING.put(StringBuilder.class, STRING); + TYPE_MAPPING.put(java.nio.charset.Charset.class, STRING); + TYPE_MAPPING.put(java.time.ZoneId.class, STRING); + TYPE_MAPPING.put(java.util.Currency.class, STRING); + TYPE_MAPPING.put(java.util.Locale.class, STRING); + TYPE_MAPPING.put(java.util.TimeZone.class, STRING); + TYPE_MAPPING.put(java.util.regex.Pattern.class, STRING); + + TYPE_MAPPING.put(java.io.InputStream.class, BYTE); + TYPE_MAPPING.put(java.net.InetAddress.class, IP_V4); + + TYPE_MAPPING.put("int", INT); + TYPE_MAPPING.put("object", OBJECT); + } + + private final Class keyClass; + private final Type type; + private final String format; + + PrimitiveSchema(Class keyClass, Type type, String format) { + this.keyClass = keyClass; + this.type = type; + this.format = format; + } + + PrimitiveSchema(Class keyClass, Type type) { + this.keyClass = keyClass; + this.type = type; + format = null; + } + + public Schema newSchema() { + return new Schema().setType(type).setFormat(format); + } + + public static Schema newSchemaOf(Class type) { + PrimitiveSchema schema = TYPE_MAPPING.get(type); + if (schema == null) { + schema = TYPE_MAPPING.get(type.getName()); + } + return schema == null ? null : schema.newSchema(); + } + + public static void addTypeMapping(Object key, PrimitiveSchema schema) { + TYPE_MAPPING.put(key, schema); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaFactory.java new file mode 100644 index 00000000000..d7d828d2882 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaFactory.java @@ -0,0 +1,210 @@ +/* + * 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.protocol.tri.rest.openapi.schema; + +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.TypeParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ExtensionFactory; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaResolver.Chain; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaResolver.Context; +import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; + +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.PrimitiveSchema.ARRAY; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.PrimitiveSchema.OBJECT; + +public final class SchemaFactory { + + private final SchemaResolver[] resolvers; + private final Map, Optional> schemaMap = CollectionUtils.newConcurrentHashMap(); + private final Map, String> nameMap = CollectionUtils.newConcurrentHashMap(); + + public SchemaFactory(FrameworkModel frameworkModel) { + resolvers = frameworkModel.getOrRegisterBean(ExtensionFactory.class).getExtensions(SchemaResolver.class); + } + + public Map, Optional> getSchemaMap() { + return schemaMap; + } + + public Map, String> getNameMap() { + return nameMap; + } + + public Schema getSchema(Type type) { + return getSchema(new TypeParameterMeta(type)); + } + + public Schema getSchema(ParameterMeta parameter) { + return new ChainImpl(resolvers, p -> resolveSchema(p.getActualGenericType(), p)) + .resolve(parameter, new Context() { + @Override + public void defineSchema(String name, Class type, Schema schema) { + schemaMap.putIfAbsent(type, Optional.of(schema)); + nameMap.put(type, name); + } + + @Override + public void defineSchema(Class type, Schema schema) { + schemaMap.putIfAbsent(type, Optional.of(schema)); + } + + @Override + public Schema getSchema(ParameterMeta parameter) { + return SchemaFactory.this.getSchema(parameter); + } + + @Override + public Schema getSchema(Type type) { + return SchemaFactory.this.getSchema(type); + } + }); + } + + public Schema getSchema(ParameterMeta[] parameters) { + Schema schema = OBJECT.newSchema(); + for (ParameterMeta parameter : parameters) { + String name = parameter.getName(); + if (name == null) { + return ARRAY.newSchema(); + } + schema.addProperty(name, getSchema(parameter)); + } + return schema; + } + + private Schema resolveSchema(Type type, ParameterMeta parameter) { + if (type instanceof Class) { + return resolveClassSchema((Class) type, parameter); + } + if (type instanceof ParameterizedType) { + ParameterizedType pType = (ParameterizedType) type; + Type rawType = pType.getRawType(); + if (rawType instanceof Class) { + Class clazz = (Class) rawType; + Type[] argTypes = pType.getActualTypeArguments(); + if (Iterable.class.isAssignableFrom(clazz)) { + Type itemType = TypeUtils.getActualGenericType(argTypes[0]); + return ARRAY.newSchema().setItems(resolveNestedSchema(itemType, parameter)); + } + + if (Map.class.isAssignableFrom(clazz)) { + Schema nestedSchema = resolveNestedSchema(argTypes[1], parameter); + return OBJECT.newSchema().setAdditionalPropertiesSchema(nestedSchema); + } + + return resolveClassSchema(clazz, parameter); + } + } + if (type instanceof TypeVariable) { + return resolveNestedSchema(((TypeVariable) type).getBounds()[0], parameter); + } + if (type instanceof WildcardType) { + return resolveNestedSchema(((WildcardType) type).getUpperBounds()[0], parameter); + } + if (type instanceof GenericArrayType) { + Type nestedType = ((GenericArrayType) type).getGenericComponentType(); + return ARRAY.newSchema().setItems(resolveNestedSchema(nestedType, parameter)); + } + return OBJECT.newSchema(); + } + + private Schema resolveClassSchema(Class clazz, ParameterMeta parameter) { + Schema schema = PrimitiveSchema.newSchemaOf(clazz); + if (schema != null) { + return schema; + } + + if (clazz.isArray()) { + return ARRAY.newSchema().setItems(resolveNestedSchema(clazz.getComponentType(), parameter)); + } + + Optional existingSchema = schemaMap.get(clazz); + if (existingSchema != null) { + return existingSchema.map(s -> new Schema().setTargetSchema(s)).orElseGet(OBJECT::newSchema); + } + + String name = clazz.getName(); + List systemPrefixes = TypeUtils.getSystemPrefixes(); + for (int i = 0, size = systemPrefixes.size(); i < size; i++) { + if (name.startsWith(systemPrefixes.get(i))) { + schemaMap.put(clazz, Optional.empty()); + return OBJECT.newSchema(); + } + } + + if (clazz.isEnum()) { + schema = PrimitiveSchema.STRING.newSchema().setJavaType(clazz); + for (Object value : clazz.getEnumConstants()) { + schema.addEnumeration(value); + } + schemaMap.put(clazz, Optional.of(schema)); + return schema.clone(); + } + + Schema beanSchema = OBJECT.newSchema().setJavaType(clazz); + schemaMap.put(clazz, Optional.of(beanSchema)); + BeanMeta beanMeta = new BeanMeta(parameter.getToolKit(), clazz, true); + for (ParameterMeta param : beanMeta.getProperties()) { + beanSchema.addProperty(param.getName(), getSchema(param)); + } + return new Schema().setTargetSchema(beanSchema); + } + + private Schema resolveNestedSchema(Type nestedType, ParameterMeta parameter) { + return resolveSchema(nestedType, new TypeParameterMeta(parameter.getToolKit(), nestedType)); + } + + private Schema cacheSchema(Class clazz, Schema schema) { + schemaMap.put(clazz, Optional.ofNullable(schema)); + return schema; + } + + static final class ChainImpl implements Chain { + + private final SchemaResolver[] resolvers; + private final Function fallback; + + private int cursor; + + ChainImpl(SchemaResolver[] resolvers, Function fallback) { + this.resolvers = resolvers; + this.fallback = fallback; + } + + @Override + public Schema resolve(ParameterMeta parameter, Context context) { + if (cursor < resolvers.length) { + return resolvers[cursor++].resolve(parameter, context, this); + } + return fallback.apply(parameter); + } + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaResolver.java similarity index 62% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaResolver.java index a2ee6a83d9b..d59005da621 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaResolver.java @@ -14,20 +14,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +package org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import java.lang.reflect.Type; -public final class SchemaFactory { +public interface SchemaResolver extends OpenAPIExtension { - public Schema getSchema(Type type) { - return new Schema(); + Schema resolve(ParameterMeta parameter, Context context, Chain chain); + + interface Chain { + + Schema resolve(ParameterMeta parameter, Context context); } - public Schema getSchema(ParameterMeta[] parameters) { - return new Schema(); + interface Context { + + void defineSchema(String name, Class type, Schema schema); + + void defineSchema(Class type, Schema schema); + + Schema getSchema(ParameterMeta parameter); + + Schema getSchema(Type type); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java index 5a1ef216aa0..8942f6984a9 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java @@ -23,6 +23,8 @@ public enum Annotations implements AnnotationEnum { Mapping, Param, + OpenAPI, + Operation, Nonnull("javax.annotation.Nonnull"); private final String className; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java new file mode 100644 index 00000000000..708f2c1ce6f --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java @@ -0,0 +1,114 @@ +/* + * 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.protocol.tri.rest.support.basic; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ResolveContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Map; + +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim; + +@Activate(order = 100) +public final class BasicOpenAPIDefinitionResolver implements OpenAPIDefinitionResolver { + + @Override + public boolean hidden(ServiceMeta serviceMeta) { + AnnotationMeta openAPI = serviceMeta.getAnnotation(Annotations.OpenAPI); + return openAPI != null && openAPI.getBoolean("hidden"); + } + + @Override + public OpenAPI resolve(ServiceMeta serviceMeta) { + AnnotationMeta openAPI = serviceMeta.getAnnotation(Annotations.OpenAPI); + if (openAPI == null) { + return null; + } + + OpenAPI model = new OpenAPI(); + model.setOpenapi(trim(openAPI.getString("version"))); + Map tags = Helper.toProperties(openAPI.getStringArray("tags")); + for (Map.Entry entry : tags.entrySet()) { + model.addTag(new Tag().setName(entry.getKey()).setDescription(entry.getValue())); + } + model.setGroup(trim(openAPI.getString("group"))); + + String title = trim(openAPI.getString("title")); + String description = trim(openAPI.getString("description")); + String version = trim(openAPI.getString("version")); + if (title != null || description != null || version != null) { + model.setInfo(new Info().setTitle(title).setDescription(description).setVersion(version)); + } + + String docDescription = trim(openAPI.getString("docDescription")); + String docUrl = trim(openAPI.getString("docUrl")); + if (docDescription != null || docUrl != null) { + model.setExternalDocs( + new ExternalDocs().setDescription(docDescription).setUrl(docUrl)); + } + + model.setPriority(openAPI.getNumber("order")); + model.setExtensions(Helper.toProperties(openAPI.getStringArray("extensions"))); + return model; + } + + @Override + public boolean hidden(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { + AnnotationMeta operation = methodMeta.getAnnotation(Annotations.Operation); + return operation != null && operation.getBoolean("hidden"); + } + + @Override + public Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { + AnnotationMeta operation = methodMeta.getAnnotation(Annotations.Operation); + if (operation == null) { + return null; + } + + Operation model = new Operation(); + String method = trim(operation.getString("method")); + if (method != null) { + model.setHttpMethod(HttpMethods.of(method.toUpperCase())); + } + + String[] tags = Helper.trim(operation.getStringArray("tags")); + if (tags != null) { + model.setTags(new LinkedHashSet<>(Arrays.asList(tags))); + } + + model.setGroup(trim(operation.getString("group"))); + model.setOperationId(trim(operation.getString("operationId"))); + model.setSummary(trim(operation.getString("summary"))); + model.setDescription(trim(operation.getString("description"))); + model.setDeprecated(operation.getBoolean("deprecated")); + model.setExtensions(Helper.toProperties(operation.getStringArray("extensions"))); + return model; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java index 379ddf97c12..332b214c85e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java @@ -30,9 +30,8 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.ConstructorMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.FieldMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.NestableParameterMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.SetMethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; @@ -124,12 +123,8 @@ public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse re current.setValue(argumentResolver.getArgumentConverter().convert(value, current.paramMeta)); } - for (FieldMeta fieldMeta : beanMeta.getFields()) { - resolveParam(fieldMeta, bean, request, response); - } - - for (SetMethodMeta methodMeta : beanMeta.getMethods()) { - resolveParam(methodMeta, bean, request, response); + for (PropertyMeta propertyMeta : beanMeta.getProperties()) { + resolveParam(propertyMeta, bean, request, response); } return bean; @@ -208,14 +203,9 @@ public Node getChild(String name) { return null; } - NestableParameterMeta methodMeta = beanMeta.getMethod(name); - if (methodMeta != null) { - return createChild(name, methodMeta, v -> methodMeta.setValue(value, v)); - } - - NestableParameterMeta fieldMeta = beanMeta.getField(name); - if (fieldMeta != null) { - return createChild(name, fieldMeta, v -> fieldMeta.setValue(value, v)); + PropertyMeta propertyMeta = beanMeta.getProperty(name); + if (propertyMeta != null) { + return createChild(name, propertyMeta, v -> propertyMeta.setValue(value, v)); } return null; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java index e8e84355e6c..d92c27aa30a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.util; -import org.apache.dubbo.common.config.Environment; import org.apache.dubbo.common.utils.AnnotationUtils; import org.apache.dubbo.common.utils.DefaultParameterNameReader; import org.apache.dubbo.common.utils.ParameterNameReader; @@ -46,11 +45,11 @@ public AbstractRestToolKit(FrameworkModel frameworkModel) { @Override public String resolvePlaceholders(String text) { - return RestUtils.hasPlaceholder(text) ? getEnvironment().resolvePlaceholders(text) : text; - } - - private Environment getEnvironment() { - return frameworkModel.defaultApplication().modelEnvironment(); + return RestUtils.replacePlaceholder(text, k -> frameworkModel + .defaultApplication() + .modelEnvironment() + .getConfiguration() + .getString(k)); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestUtils.java index 1155d3860a4..d14016640bc 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestUtils.java @@ -20,6 +20,8 @@ import org.apache.dubbo.common.lang.Prioritized; import org.apache.dubbo.rpc.protocol.tri.rest.filter.RestExtension; +import java.util.function.Function; + public final class RestUtils { private RestUtils() {} @@ -39,7 +41,7 @@ public static boolean hasPlaceholder(String text) { state = 1; } else if (c == '{') { if (state == 1) { - if (text.charAt(i + 1) != '$') { + if (text.charAt(i - 1) != '$') { return false; } state = 2; @@ -51,6 +53,150 @@ public static boolean hasPlaceholder(String text) { return false; } + public static String replacePlaceholder(String text, Function resolver) { + if (text == null) { + return null; + } + int len = text.length(); + if (len < 2) { + return text; + } + + int p = 0, nameStart = 0, nameEnd = 0, valueStart = 0, valueEnd = 0; + String value; + StringBuilder buf = null; + int state = State.START; + for (int i = 0; i < len; i++) { + char c = text.charAt(i); + switch (c) { + case '$': + if (state == State.START) { + if (buf == null) { + buf = new StringBuilder(len); + } + buf.append(text, p, i); + p = i; + state = State.DOLLAR; + } else if (state == State.DOLLAR) { + if (buf == null) { + buf = new StringBuilder(len); + } + buf.append(text, p, i - 1); + p = i; + state = State.START; + } + break; + case '{': + state = state == State.DOLLAR ? State.BRACE_OPEN : State.START; + break; + case ':': + state = state == State.NAME_START ? State.COLON : State.START; + break; + case '}': + switch (state) { + case State.DOLLAR: + case State.BRACE_OPEN: + state = State.START; + break; + case State.COLON: + state = State.START; + valueStart = i; + break; + case State.DOLLAR_NAME_START: + case State.NAME_START: + case State.VALUE_START: + value = resolver.apply(text.substring(nameStart, nameEnd)); + if (buf == null) { + buf = new StringBuilder(len); + } + if (value == null) { + if (state == State.VALUE_START) { + buf.append(text, valueStart, valueEnd); + } else { + buf.append(text, p, i + 1); + } + } else { + buf.append(value); + } + p = i + 1; + state = State.START; + break; + default: + } + break; + case ' ': + case '\t': + case '\n': + case '\r': + if (state == State.DOLLAR_NAME_START) { + state = State.START; + value = resolver.apply(text.substring(nameStart, nameEnd)); + if (buf == null) { + buf = new StringBuilder(len); + } + if (value == null) { + buf.append(text, p, i); + } else { + buf.append(value); + } + p = i; + } + break; + default: + switch (state) { + case State.DOLLAR: + state = State.DOLLAR_NAME_START; + nameStart = i; + break; + case State.BRACE_OPEN: + state = State.NAME_START; + nameStart = i; + break; + case State.COLON: + state = State.VALUE_START; + valueStart = i; + break; + case State.DOLLAR_NAME_START: + case State.NAME_START: + nameEnd = i + 1; + break; + case State.VALUE_START: + valueEnd = i + 1; + break; + default: + } + } + } + if (state == State.DOLLAR_NAME_START) { + value = resolver.apply(text.substring(nameStart, nameEnd)); + if (buf == null) { + buf = new StringBuilder(len); + } + if (value == null) { + buf.append(text, p, len); + } else { + buf.append(value); + } + } else { + if (buf == null) { + return text; + } + buf.append(text, p, len); + } + return buf.toString(); + } + + private interface State { + + int START = 0; + int DOLLAR = 1; + int BRACE_OPEN = 2; + int COLON = 3; + int DOLLAR_NAME_START = 4; + int NAME_START = 5; + int VALUE_START = 6; + } + public static boolean isMaybeJSONObject(String str) { if (str == null) { return false; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java index 60b551eed84..a5f3210b46d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java @@ -38,6 +38,7 @@ import java.time.ZoneId; import java.time.temporal.Temporal; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Currency; @@ -61,11 +62,13 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.regex.Pattern; public final class TypeUtils { private static final Set> SIMPLE_TYPES = new ConcurrentHashSet<>(); + private static final List SYSTEM_PREFIXES = new CopyOnWriteArrayList<>(); static { Collections.addAll( @@ -80,6 +83,8 @@ public final class TypeUtils { Currency.class, Pattern.class, Class.class); + + Collections.addAll(SYSTEM_PREFIXES, "java.", "javax.", "sun.", "com.sun.", "com.google.protobuf."); } private TypeUtils() {} @@ -112,6 +117,18 @@ private static boolean isSimpleValueType(Class type) { return false; } + public static void addSimpleTypes(Class... types) { + SIMPLE_TYPES.addAll(Arrays.asList(types)); + } + + public static List getSystemPrefixes() { + return SYSTEM_PREFIXES; + } + + public static void addSystemPrefixes(String... prefixes) { + SYSTEM_PREFIXES.addAll(Arrays.asList(prefixes)); + } + public static Class getMapValueType(Class targetClass) { for (Type gi : targetClass.getGenericInterfaces()) { if (gi instanceof ParameterizedType) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension new file mode 100644 index 00000000000..dca2e05d85a --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension @@ -0,0 +1 @@ +resolver-basic=org.apache.dubbo.rpc.protocol.tri.rest.support.basic.BasicOpenAPIDefinitionResolver From 0a062c844b3383420ab9cfdea75f0b331190c231 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Fri, 15 Nov 2024 11:40:15 +0800 Subject: [PATCH 05/23] Request handler impl --- .../apache/dubbo/common/utils/ClassUtils.java | 5 + .../dubbo/config/nested/OpenAPIConfig.java | 2 +- .../dubbo/metadata/MetadataService.java | 7 +- .../metadata/MetadataServiceV2Detector.java | 17 +-- .../tri/rest/support/jaxrs/Helper.java | 6 +- .../metadata/MetadataServiceDelegation.java | 8 +- .../AbstractServerHttpChannelObserver.java | 2 +- .../dubbo/remoting/http12/HttpUtils.java | 7 +- .../http12/message/DefaultHttpRequest.java | 2 +- .../http12/message/DefaultHttpResult.java | 4 + .../remoting/http12/message/MediaType.java | 30 ++-- .../message/codec/JsonPbCodecFactory.java | 3 +- .../dubbo/remoting/http12/rest/Mapping.java | 5 + .../dubbo/remoting/http12/rest/OpenAPI.java | 15 +- .../remoting/http12/rest}/OpenAPIRequest.java | 46 ++++-- .../dubbo/remoting/http12/rest/Operation.java | 17 ++- .../dubbo/remoting/http12/rest/Param.java | 5 + .../dubbo/remoting/http12/rest/Schema.java | 134 +++++++++++++++++ .../java/org/apache/dubbo/rpc/Constants.java | 1 + .../org/apache/dubbo/rpc/RpcInvocation.java | 4 + .../tri/h12/AbstractServerCallListener.java | 17 ++- ...pcHttp3ServerTransportListenerFactory.java | 3 +- .../tri/rest/mapping/ContentNegotiator.java | 5 +- .../DefaultRequestMappingRegistry.java | 16 +- .../protocol/tri/rest/mapping/RadixTree.java | 56 ++++++- .../mapping/RestRequestHandlerMapping.java | 12 +- .../mapping/condition/PathExpression.java | 39 +++-- .../tri/rest/mapping/meta/BeanMeta.java | 76 +++++++--- .../tri/rest/mapping/meta/ParameterMeta.java | 8 +- .../tri/rest/mapping/meta/ProtoBean.java | 45 ++++++ .../tri/rest/openapi/AbstractContext.java | 1 - .../tri/rest/openapi/ConfigFactory.java | 17 ++- .../protocol/tri/rest/openapi/Constants.java | 2 - .../protocol/tri/rest/openapi/Context.java | 2 +- .../tri/rest/openapi/ContextImpl.java | 25 ++-- .../rest/openapi/DefaultOpenAPIService.java | 73 ++++++++- .../tri/rest/openapi/DefinitionEncoder.java | 10 +- .../tri/rest/openapi/DefinitionFilter.java | 16 +- .../tri/rest/openapi/DefinitionMerger.java | 140 ++++++++++-------- .../tri/rest/openapi/DefinitionResolver.java | 10 +- .../tri/rest/openapi/ExtensionFactory.java | 3 + .../rpc/protocol/tri/rest/openapi/Helper.java | 61 +++++++- ...her.java => OpenAPIDocumentPublisher.java} | 3 +- ...rategy.java => OpenAPINamingStrategy.java} | 2 +- .../rest/openapi/OpenAPIRequestHandler.java | 30 ++++ .../rest/openapi/OpenAPISchemaPredicate.java | 28 ++++ ...solver.java => OpenAPISchemaResolver.java} | 5 +- .../tri/rest/openapi/OpenAPIService.java | 1 + .../openapi/{schema => }/PrimitiveSchema.java | 5 +- .../openapi/{proto => }/ProtoEncoder.java | 2 +- .../tri/rest/openapi/ResolveContext.java | 1 - .../openapi/{schema => }/SchemaFactory.java | 60 +++++--- .../tri/rest/openapi/model/ApiResponse.java | 4 +- .../tri/rest/openapi/model/Header.java | 28 ++-- .../tri/rest/openapi/model/Parameter.java | 6 +- .../tri/rest/openapi/model/PathItem.java | 17 ++- .../tri/rest/openapi/model/RequestBody.java | 12 +- .../basic/BasicOpenAPIDefinitionResolver.java | 26 ++-- .../protocol/tri/rest/util/RequestUtils.java | 17 +++ .../rpc/protocol/tri/rest/util/TypeUtils.java | 17 +++ .../protocol/tri/stream/AbstractStream.java | 11 +- 61 files changed, 927 insertions(+), 305 deletions(-) rename {dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi => dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest}/OpenAPIRequest.java (70%) create mode 100644 dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Schema.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ProtoBean.java rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{DocumentPublisher.java => OpenAPIDocumentPublisher.java} (89%) rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{NamingStrategy.java => OpenAPINamingStrategy.java} (94%) create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{schema/SchemaResolver.java => OpenAPISchemaResolver.java} (87%) rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{schema => }/PrimitiveSchema.java (96%) rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{proto => }/ProtoEncoder.java (94%) rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{schema => }/SchemaFactory.java (79%) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java index 52cb2782fd5..96442b0c05a 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ClassUtils.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.common.utils; +import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.convert.ConverterUtil; import org.apache.dubbo.rpc.model.FrameworkModel; @@ -670,4 +671,8 @@ public static String[] getDeclaredMethodNames(Class tClass) { dmns.sort(Comparator.naturalOrder()); return dmns.toArray(new String[0]); } + + public static boolean hasProtobuf() { + return isPresent(CommonConstants.PROTOBUF_MESSAGE_CLASS_NAME); + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java index f3a2f059649..6668e2238ab 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -31,7 +31,7 @@ public class OpenAPIConfig implements Serializable { /** * The HTTP path where OpenAPI will be registered. - *

The default value is 'api-docs'. + *

The default value is '/dubbo/openapi'. */ private String path; diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java index eec8bcd7c7b..859523c7e6e 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java @@ -19,7 +19,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.remoting.http12.rest.Mapping; import org.apache.dubbo.remoting.http12.rest.OpenAPI; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequest; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import java.util.Collections; import java.util.List; @@ -32,6 +32,7 @@ import static java.util.Collections.unmodifiableSortedSet; import static org.apache.dubbo.common.URL.buildKey; +import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_OPENAPI_PREFIX; /** * This service is used to expose the metadata information inside a Dubbo process. @@ -39,7 +40,7 @@ * 1. The Consumer queries the metadata information of the Provider to list the interfaces and each interface's configuration * 2. The Console (dubbo-admin) queries for the metadata of a specific process, or aggregate data of all processes. */ -@OpenAPI(hidden = true) +@OpenAPI(hidden = false) public interface MetadataService { /** @@ -234,6 +235,6 @@ static boolean isMetadataService(String interfaceName) { /** * 1. Get the openAPI definition */ - @Mapping({"getOpenAPI", "//_meta/openapi"}) + @Mapping({"getOpenAPI", "//${" + H2_SETTINGS_OPENAPI_PREFIX + ".path:dubbo/openapi}/{*path}"}) String getOpenAPI(OpenAPIRequest request); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2Detector.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2Detector.java index 59962281568..171b370ab5e 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2Detector.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2Detector.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.rpc.model.BuiltinServiceDetector; public class MetadataServiceV2Detector implements BuiltinServiceDetector { @@ -29,20 +30,14 @@ public class MetadataServiceV2Detector implements BuiltinServiceDetector { @Override public Class getService() { - if (!support()) { - logger.info( - "To use MetadataServiceV2, Protobuf dependencies are required. Fallback to MetadataService(V1)."); - return null; + if (ClassUtils.hasProtobuf()) { + return MetadataServiceV2.class; } - return org.apache.dubbo.metadata.MetadataServiceV2.class; + logger.info("To use MetadataServiceV2, Protobuf dependencies are required. Fallback to MetadataService(V1)."); + return null; } public static boolean support() { - try { - Class.forName("com.google.protobuf.Message"); - } catch (ClassNotFoundException classNotFoundException) { - return false; - } - return true; + return ClassUtils.hasProtobuf(); } } diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/Helper.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/Helper.java index 9abde6219ac..cc2e56e5352 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/Helper.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/Helper.java @@ -35,11 +35,11 @@ public final class Helper { private Helper() {} public static boolean isRequired(ParameterMeta parameter) { - return parameter.isAnnotated(Annotations.Nonnull); + return parameter.isHierarchyAnnotated(Annotations.Nonnull); } - public static String defaultValue(ParameterMeta annotation) { - AnnotationMeta meta = annotation.getAnnotation(Annotations.DefaultValue); + public static String defaultValue(ParameterMeta parameter) { + AnnotationMeta meta = parameter.findAnnotation(Annotations.DefaultValue); return meta == null ? null : meta.getValue(); } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java index ae2f5057f10..ab3ba7cec0a 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java @@ -28,8 +28,8 @@ import org.apache.dubbo.registry.support.RegistryManager; import org.apache.dubbo.remoting.http12.HttpStatus; import org.apache.dubbo.remoting.http12.exception.HttpStatusException; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequest; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIService; import java.util.ArrayList; @@ -59,7 +59,6 @@ public class MetadataServiceDelegation implements MetadataService, Disposable { private final ApplicationModel applicationModel; private final RegistryManager registryManager; - private final OpenAPIService openAPIService; private final ConcurrentMap instanceMetadataChangedListenerMap = new ConcurrentHashMap<>(); private URL url; @@ -71,10 +70,6 @@ public class MetadataServiceDelegation implements MetadataService, Disposable { public MetadataServiceDelegation(ApplicationModel applicationModel) { this.applicationModel = applicationModel; registryManager = RegistryManager.getInstance(applicationModel); - openAPIService = applicationModel.getBean(OpenAPIService.class); - if (openAPIService != null) { - openAPIService.export(); - } } /** @@ -225,6 +220,7 @@ public String getAndListenInstanceMetadata(String consumerId, InstanceMetadataCh @Override public String getOpenAPI(OpenAPIRequest request) { + OpenAPIService openAPIService = applicationModel.getBean(OpenAPIService.class); if (openAPIService == null) { throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode(), "OpenAPI is not available"); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java index c1edd74d504..c7f620644ca 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java @@ -168,7 +168,7 @@ protected final HttpMetadata buildMetadata( if (data instanceof HttpResult) { HttpResult result = (HttpResult) data; if (result.getHeaders() != null) { - headers.add(result.getHeaders()); + headers.set(result.getHeaders()); } } customizeHeaders(headers, throwable, message); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java index 7ffde474662..40383e3d977 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpUtils.java @@ -124,10 +124,10 @@ public static float parseQuality(String expr, int index) { } public static List parseAcceptLanguage(String header) { - List> locales = new ArrayList<>(); if (header == null) { return new ArrayList<>(); } + List> locales = new ArrayList<>(); for (String item : StringUtils.tokenize(header, ',')) { String[] pair = StringUtils.tokenize(item, ';'); locales.add(new Item<>(parseLocale(pair[0]), pair.length > 1 ? Float.parseFloat(pair[1]) : 1.0F)); @@ -136,10 +136,10 @@ public static List parseAcceptLanguage(String header) { } public static List parseContentLanguage(String header) { - List locales = new ArrayList<>(); if (header == null) { return new ArrayList<>(); } + List locales = new ArrayList<>(); for (String item : StringUtils.tokenize(header, ',')) { locales.add(parseLocale(item)); } @@ -268,6 +268,9 @@ public int compareTo(Item o) { public static List sortAndGet(List> items) { int size = items.size(); + if (size == 0) { + return Collections.emptyList(); + } if (size == 1) { return Collections.singletonList(items.get(0).value); } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java index f1909169e69..5ed4c0ef9bb 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java @@ -287,7 +287,7 @@ public List locales() { if (locales == null) { locales = HttpUtils.parseAcceptLanguage(headers.getFirst(HttpHeaderNames.CONTENT_LANGUAGE.getKey())); if (locales.isEmpty()) { - locales.add(Locale.getDefault()); + locales = Collections.singletonList(Locale.getDefault()); } this.locales = locales; } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java index 1a70259b732..8e0f695286a 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpResult.java @@ -172,6 +172,10 @@ public Builder addHeader(String key, String value) { return this; } + public Builder contentType(String value) { + return headerIf(HttpHeaderNames.CONTENT_TYPE.getName(), value); + } + public Builder from(HttpResult result) { status = result.getStatus(); headers = result.getHeaders() == null ? null : new LinkedHashMap<>(result.getHeaders()); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java index 13e25ec8c44..1b11e8ec17f 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java @@ -22,33 +22,41 @@ public final class MediaType { public static final String WILDCARD = "*"; + public static final String APPLICATION = "application"; + public static final String TEXT = "text"; + public static final String JSON = "json"; + + public static final String XML = "xml"; + + public static final String YAML = "yaml"; + public static final MediaType ALL = new MediaType(WILDCARD, WILDCARD); - public static final MediaType APPLICATION_JSON = new MediaType("application", "json"); + public static final MediaType APPLICATION_JSON = new MediaType(APPLICATION, JSON); - public static final MediaType APPLICATION_XML = new MediaType("application", "xml"); + public static final MediaType APPLICATION_XML = new MediaType(APPLICATION, XML); - public static final MediaType APPLICATION_YAML = new MediaType("application", "yaml"); + public static final MediaType APPLICATION_YAML = new MediaType(APPLICATION, YAML); - public static final MediaType APPLICATION_JAVASCRIPT = new MediaType("application", "javascript"); + public static final MediaType APPLICATION_JAVASCRIPT = new MediaType(APPLICATION, "javascript"); - public static final MediaType APPLICATION_OCTET_STREAM = new MediaType("application", "octet-stream"); + public static final MediaType APPLICATION_OCTET_STREAM = new MediaType(APPLICATION, "octet-stream"); - public static final MediaType APPLICATION_GRPC = new MediaType("application", "grpc"); + public static final MediaType APPLICATION_GRPC = new MediaType(APPLICATION, "grpc"); - public static final MediaType APPLICATION_GRPC_PROTO = new MediaType("application", "grpc+proto"); + public static final MediaType APPLICATION_GRPC_PROTO = new MediaType(APPLICATION, "grpc+proto"); - public static final MediaType APPLICATION_FROM_URLENCODED = new MediaType("application", "x-www-form-urlencoded"); + public static final MediaType APPLICATION_FROM_URLENCODED = new MediaType(APPLICATION, "x-www-form-urlencoded"); public static final MediaType MULTIPART_FORM_DATA = new MediaType("multipart", "form-data"); - public static final MediaType TEXT_JSON = new MediaType(TEXT, "json"); + public static final MediaType TEXT_JSON = new MediaType(TEXT, JSON); - public static final MediaType TEXT_XML = new MediaType(TEXT, "xml"); + public static final MediaType TEXT_XML = new MediaType(TEXT, XML); - public static final MediaType TEXT_YAML = new MediaType(TEXT, "yaml"); + public static final MediaType TEXT_YAML = new MediaType(TEXT, YAML); public static final MediaType TEXT_CSS = new MediaType(TEXT, "css"); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodecFactory.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodecFactory.java index 398225255d0..0a5f63ee919 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodecFactory.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodecFactory.java @@ -17,6 +17,7 @@ package org.apache.dubbo.remoting.http12.message.codec; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.message.HttpMessageCodec; import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory; @@ -24,7 +25,7 @@ import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.rpc.model.FrameworkModel; -@Activate(order = -100, onClass = "com.google.protobuf.Message") +@Activate(order = -100, onClass = CommonConstants.PROTOBUF_MESSAGE_CLASS_NAME) public final class JsonPbCodecFactory implements HttpMessageEncoderFactory, HttpMessageDecoderFactory { @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java index f42e11768f3..6f3171d4fe4 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java @@ -47,6 +47,11 @@ */ String[] value() default {}; + /** + * A title to explain the purpose of the mapping. + **/ + String title() default ""; + /** * Specifies the path patterns to be mapped. * If not specified, the method or class name is used as the default. diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java index c2669d34f9a..a40d411a47d 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java @@ -39,6 +39,16 @@ @Documented public @interface OpenAPI { + /** + * Alias for {@link #infoTitle()}. + */ + String value() default ""; + + /** + * The openAPI groups. + */ + String group() default ""; + /** * The version of OpenAPI being used. * e.g. 3.0.1, 3.1.0 @@ -57,11 +67,6 @@ */ String[] tags() default {}; - /** - * The openAPI groups. - */ - String group() default ""; - /** * The title of the application. **/ diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequest.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java similarity index 70% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequest.java rename to dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java index 530c5b96164..22805c2a04d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequest.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java @@ -14,22 +14,50 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +package org.apache.dubbo.remoting.http12.rest; import org.apache.dubbo.common.utils.ToStringUtils; import java.io.Serializable; +/** + * OpenAPI request model. + */ public class OpenAPIRequest implements Serializable { private static final long serialVersionUID = 1L; + /** + * The openAPI group. + */ private String group; - private String[] tags; - private String service; + + /** + * The openAPI tags. Each tag is an or condition. + */ + private String[] tag; + + /** + * The openAPI services. Each service is an or condition. + */ + private String[] service; + + /** + * The openAPI version. + * e.g. 3.0.1, 3.1.0 + *

The default value is '3.0.1' if not set. + */ private String version; + /** + * The format of the response. + *

The default value is '3.0.1' if not set. + */ private String format; + + /** + * Whether to pretty print for json. + */ private Boolean pretty; public String getGroup() { @@ -40,19 +68,19 @@ public void setGroup(String group) { this.group = group; } - public String[] getTags() { - return tags; + public String[] getTag() { + return tag; } - public void setTags(String[] tags) { - this.tags = tags; + public void setTag(String[] tag) { + this.tag = tag; } - public String getService() { + public String[] getService() { return service; } - public void setService(String service) { + public void setService(String[] service) { this.service = service; } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java index cb5df99f658..9343130cfe1 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java @@ -27,6 +27,16 @@ @Documented public @interface Operation { + /** + * Alias for {@link #summary()}. + */ + String value() default ""; + + /** + * The operation group. + */ + String group() default ""; + /** * The HTTP method for this operation. */ @@ -37,15 +47,10 @@ */ String[] tags() default {}; - /** - * The operation group. - */ - String group() default ""; - /** * The ID of this operation. **/ - String operationId() default ""; + String id() default ""; /** * A brief description of this operation. Should be 120 characters or fewer. diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Param.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Param.java index 108dfd44db6..0ee100a8e21 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Param.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Param.java @@ -45,6 +45,11 @@ */ String value() default ""; + /** + * A title to explain the purpose of the param. + **/ + String title() default ""; + /** * The type of the parameter, such as query, header, or path variable. * Defaults to {@link ParamType#Param}. diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Schema.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Schema.java new file mode 100644 index 00000000000..8f83764d0bb --- /dev/null +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Schema.java @@ -0,0 +1,134 @@ +/* + * 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.remoting.http12.rest; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Schema { + + /** + * Alias for {@link #title()}. + */ + String value() default ""; + + /** + * The schema group. + */ + String group() default ""; + + /** + * The type of the schema. + */ + String type() default ""; + + /** + * The schema's format + */ + String format() default ""; + + /** + * The name of the schema or property. + **/ + String name() default ""; + + /** + * A title to explain the purpose of the schema. + **/ + String title() default ""; + + /** + * The schema's description + **/ + String description() default ""; + + /** + * The maximum value or length of this schema + **/ + String max() default ""; + + /** + * The minimum value or length of this schema + **/ + String min() default ""; + + /** + * The pattern of this schema. + **/ + String pattern() default ""; + + /** + * An example of this schema. + **/ + String example() default ""; + + /** + * A class that implements this schema. + **/ + Class implementation() default Void.class; + + /** + * A list of allowed schema values + **/ + String[] enumeration() default {}; + + /** + * Whether this schema is required + **/ + boolean required() default false; + + /** + * The default value of this schema + **/ + String defaultValue() default ""; + + /** + * Whether this schema is read only + **/ + boolean readOnly() default false; + + /** + * Whether this schema is written only + */ + boolean writeOnly() default false; + + /** + * Whether this schema is nullable + */ + boolean nullable() default false; + + /** + * Whether this operation is deprecated + */ + boolean deprecated() default false; + + /** + * Whether this schema is hidden. + */ + boolean hidden() default false; + + /** + * The extensions of the OpenAPI. + */ + String[] extensions() default {}; +} diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java index 59f0235de85..4ef8731af80 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java @@ -112,6 +112,7 @@ public interface Constants { String H2_SETTINGS_JSON_FRAMEWORK_NAME = "dubbo.protocol.triple.rest.json-framework"; String H2_SETTINGS_DISALLOWED_CONTENT_TYPES = "dubbo.protocol.triple.rest.disallowed-content-types"; + String H2_SETTINGS_OPENAPI_PREFIX = "dubbo.protocol.triple.rest.openapi"; String H2_SETTINGS_VERBOSE_ENABLED = "dubbo.protocol.triple.verbose"; String H2_SETTINGS_SERVLET_ENABLED = "dubbo.protocol.triple.servlet.enabled"; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java index 4c69c499338..1aec29ef1ef 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java @@ -501,6 +501,10 @@ public void setInvoker(Invoker invoker) { this.invoker = invoker; } + public Object remove(Object key) { + return attributes.remove(key); + } + @Override public Object put(Object key, Object value) { return attributes.put(key, value); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java index 4158649a11d..0a8f1afe8ae 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerCallListener.java @@ -25,6 +25,8 @@ import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcInvocation; +import org.apache.dubbo.rpc.RpcServiceContext; +import org.apache.dubbo.rpc.protocol.tri.TripleConstants; import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum; import java.net.InetSocketAddress; @@ -56,14 +58,19 @@ public void invoke() { RpcContext.restoreCancellationContext( ((Http2CancelableStreamObserver) responseObserver).getCancellationContext()); } - InetSocketAddress remoteAddress = - (InetSocketAddress) invocation.getAttributes().remove(REMOTE_ADDRESS_KEY); - RpcContext.getServiceContext().setRemoteAddress(remoteAddress); - String remoteApp = (String) invocation.getAttributes().remove(TripleHeaderEnum.CONSUMER_APP_NAME_KEY); + + RpcServiceContext serviceContext = RpcContext.getServiceContext(); + serviceContext.setRemoteAddress((InetSocketAddress) invocation.remove(REMOTE_ADDRESS_KEY)); + String remoteApp = (String) invocation.remove(TripleHeaderEnum.CONSUMER_APP_NAME_KEY); if (remoteApp != null) { - RpcContext.getServiceContext().setRemoteApplicationName(remoteApp); + serviceContext.setRemoteApplicationName(remoteApp); invocation.setAttachmentIfAbsent(REMOTE_APPLICATION_KEY, remoteApp); } + if (serviceContext.getRequest() == null) { + serviceContext.setRequest(invocation.get(TripleConstants.HTTP_REQUEST_KEY)); + serviceContext.setResponse(invocation.get(TripleConstants.HTTP_RESPONSE_KEY)); + } + try { long stInMillis = System.currentTimeMillis(); Result response = invoker.invoke(invocation); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java index 10b622d9a7a..9d0e3437797 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h3/grpc/GrpcHttp3ServerTransportListenerFactory.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.h3.grpc; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.h2.H2StreamChannel; import org.apache.dubbo.remoting.http3.Http3ServerTransportListenerFactory; @@ -24,7 +25,7 @@ import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcUtils; -@Activate(order = -100, onClass = "com.google.protobuf.Message") +@Activate(order = -100, onClass = CommonConstants.PROTOBUF_MESSAGE_CLASS_NAME) public class GrpcHttp3ServerTransportListenerFactory implements Http3ServerTransportListenerFactory { @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java index c7cbec42b20..ce00cb1a278 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java @@ -33,13 +33,11 @@ public class ContentNegotiator { - private final FrameworkModel frameworkModel; private final CodecUtils codecUtils; private Map extensionMapping; private String parameterName; public ContentNegotiator(FrameworkModel frameworkModel) { - this.frameworkModel = frameworkModel; codecUtils = frameworkModel.getOrRegisterBean(CodecUtils.class); } @@ -169,7 +167,8 @@ private String getMediaTypeByExtension(String extension) { extensionMapping.put("xhtml", MediaType.TEXT_HTML); extensionMapping.put("html", MediaType.TEXT_HTML); extensionMapping.put("htm", MediaType.TEXT_HTML); - for (String ext : new String[] {"txt", "md", "csv", "log", "properties", "proto"}) { + extensionMapping.put("proto", new MediaType(MediaType.TEXT, "proto")); + for (String ext : new String[] {"txt", "md", "csv", "log", "properties"}) { extensionMapping.put(ext, MediaType.TEXT_PLAIN); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java index 13040756bfe..30b3ca199e1 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java @@ -40,6 +40,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ConfigFactory; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPIService; import org.apache.dubbo.rpc.protocol.tri.rest.util.KeyString; import org.apache.dubbo.rpc.protocol.tri.rest.util.MethodWalker; @@ -77,8 +78,10 @@ public DefaultRequestMappingRegistry(FrameworkModel frameworkModel) { private void init(Invoker invoker) { contentNegotiator = frameworkModel.getOrRegisterBean(ContentNegotiator.class); - openAPIService = frameworkModel.getOrRegisterBean(DefaultOpenAPIService.class); - openAPIService.setRequestMappingRegistry(this); + if (ConfigFactory.isOpenAPIEnabled(frameworkModel)) { + openAPIService = frameworkModel.getOrRegisterBean(DefaultOpenAPIService.class); + openAPIService.setRequestMappingRegistry(this); + } resolvers = frameworkModel.getActivateExtensions(RequestMappingResolver.class); restConfig = ConfigManager.getProtocolOrDefault(invoker.getUrl()) .getTripleOrDefault() @@ -225,10 +228,9 @@ public HandlerMeta lookup(HttpRequest request) { if (candidates.isEmpty()) { int end = path.length(); - if (restConfig.getTrailingSlashMatchOrDefault()) { + if (end > 1 && restConfig.getTrailingSlashMatchOrDefault()) { if (path.charAt(end - 1) == '/') { - end--; - tryMatch(request, path.subSequence(0, end), candidates, partialMatches); + tryMatch(request, path.subSequence(0, --end), candidates, partialMatches); } } @@ -446,7 +448,9 @@ private boolean tryExists(KeyString path, String method) { } private void onMappingChanged() { - openAPIService.refresh(); + if (openAPIService != null) { + openAPIService.refresh(); + } } private static final class Candidate { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java index d6242e6117a..7690dd110c6 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java @@ -43,14 +43,24 @@ public final class RadixTree { private final Map>> directPathMap = new HashMap<>(); private final Node root = new Node<>(); + private final char separator; private final boolean caseSensitive; - public RadixTree(boolean caseSensitive) { + public RadixTree(boolean caseSensitive, char separator) { this.caseSensitive = caseSensitive; + this.separator = separator; + } + + public RadixTree(boolean caseSensitive) { + this(caseSensitive, '/'); + } + + public RadixTree(char separator) { + this(true, separator); } public RadixTree() { - caseSensitive = true; + this(true, '/'); } public T addPath(PathExpression path, T value) { @@ -89,6 +99,12 @@ public T addPath(String path, T value) { return addPath(PathExpression.parse(PathUtils.normalize(path)), value); } + public void addPath(T value, String... paths) { + for (String path : paths) { + addPath(path, value); + } + } + private Node getChild(Node current, PathSegment segment) { Node child; if (segment.getType() == Type.LITERAL) { @@ -203,11 +219,43 @@ public List> match(String path) { return match(new KeyString(path, caseSensitive)); } + public List> matchRelaxed(String path) { + KeyString keyPath = new KeyString(path, caseSensitive); + List> matches = new ArrayList<>(); + match(keyPath, matches); + if (!matches.isEmpty()) { + return matches; + } + + int end = path.length(); + if (end > 1 && path.charAt(end - 1) == '/') { + match(keyPath.subSequence(0, --end), matches); + if (!matches.isEmpty()) { + return matches; + } + } + + for (int i = end - 1; i >= 0; i--) { + char ch = path.charAt(i); + if (ch == '/') { + break; + } + if (ch == '.') { + match(keyPath.subSequence(0, i), matches); + if (!matches.isEmpty()) { + return matches; + } + } + } + + return matches; + } + private void matchRecursive( Node current, KeyString path, int start, Map variableMap, List> matches) { int end = -2; if (!current.children.isEmpty()) { - end = path.indexOf('/', start); + end = path.indexOf(separator, start); Node child = current.children.get(path.subSequence(start, end)); if (child != null) { if (end == -1) { @@ -222,7 +270,7 @@ private void matchRecursive( return; } if (end == -2) { - end = path.indexOf('/', start); + end = path.indexOf(separator, start); } Map workVariableMap = new LinkedHashMap<>(); for (Map.Entry> entry : current.fuzzyChildren.entrySet()) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java index 5428d1c8c8b..2057d8e3988 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RestRequestHandlerMapping.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.mapping; import org.apache.dubbo.common.URL; +import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; @@ -57,11 +58,12 @@ public final class RestRequestHandlerMapping implements RequestHandlerMapping { private final CodecUtils codecUtils; public RestRequestHandlerMapping(FrameworkModel frameworkModel) { - requestMappingRegistry = frameworkModel.getOrRegisterBean(DefaultRequestMappingRegistry.class); - argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); - typeConverter = frameworkModel.getOrRegisterBean(GeneralTypeConverter.class); - contentNegotiator = frameworkModel.getOrRegisterBean(ContentNegotiator.class); - codecUtils = frameworkModel.getOrRegisterBean(CodecUtils.class); + ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); + requestMappingRegistry = beanFactory.getOrRegisterBean(DefaultRequestMappingRegistry.class); + argumentResolver = beanFactory.getOrRegisterBean(CompositeArgumentResolver.class); + typeConverter = beanFactory.getOrRegisterBean(GeneralTypeConverter.class); + contentNegotiator = beanFactory.getOrRegisterBean(ContentNegotiator.class); + codecUtils = beanFactory.getOrRegisterBean(CodecUtils.class); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java index e769a6c4413..c3fa4360f5b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; public final class PathExpression implements Comparable { @@ -128,17 +129,37 @@ public String toString() { return path; } StringBuilder sb = new StringBuilder(path.length()); + int varIndex = 1; for (PathSegment segment : segments) { sb.append('/'); - String value = segment.getValue(); - if (segment.getType() == Type.VARIABLE) { - if (value.isEmpty()) { - sb.append('*'); - } else { - sb.append('{').append(value).append('}'); - } - } else { - sb.append(value); + switch (segment.getType()) { + case LITERAL: + sb.append(segment.getValue()); + break; + case WILDCARD_TAIL: + List variables = segment.getVariables(); + if (variables == null) { + sb.append("{path}"); + } else { + sb.append('{').append(variables.get(0)).append('}'); + } + break; + case VARIABLE: + sb.append('{'); + String value = segment.getValue(); + if (value.isEmpty()) { + sb.append("var").append(varIndex++); + } else { + sb.append(value); + } + sb.append('}'); + break; + case PATTERN: + case PATTERN_MULTI: + sb.append('{').append("var").append(varIndex++).append('}'); + break; + default: + break; } } return sb.toString(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java index 15b213b8552..54a4aaaeb70 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta; +import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.remoting.http12.rest.Param; import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; @@ -36,9 +37,16 @@ import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Message; public final class BeanMeta { + private static final boolean HAS_PB = ClassUtils.hasProtobuf(); + private final Class type; private final ConstructorMeta constructor; private final Map properties = new LinkedHashMap<>(); @@ -99,22 +107,39 @@ public static ConstructorMeta resolveConstructor(RestToolKit toolKit, String pre } private void resolveProperties(RestToolKit toolKit, String prefix, Class type) { - if (type == null || type == Object.class) { + if (type == null || type == Object.class || TypeUtils.isSystemType(type)) { return; } + Set pbFields = null; + if (HAS_PB && Message.class.isAssignableFrom(type)) { + try { + Descriptor descriptor = + (Descriptor) type.getMethod("getDescriptor").invoke(null); + pbFields = descriptor.getFields().stream() + .map(FieldDescriptor::getName) + .collect(Collectors.toSet()); + } catch (Exception ignored) { + } + } + Set allNames = new LinkedHashSet<>(); Map fieldMap = new LinkedHashMap<>(); - for (Field field : type.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())) { - continue; - } - if (!field.isAccessible()) { - field.setAccessible(true); + if (pbFields == null) { + for (Field field : type.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers()) + || Modifier.isTransient(field.getModifiers()) + || field.isSynthetic()) { + continue; + } + if (!field.isAccessible()) { + field.setAccessible(true); + } + fieldMap.put(field.getName(), field); + allNames.add(field.getName()); } - fieldMap.put(field.getName(), field); - allNames.add(field.getName()); } + Map getMethodMap = new LinkedHashMap<>(); Map setMethodMap = new LinkedHashMap<>(); for (Method method : type.getDeclaredMethods()) { @@ -127,17 +152,21 @@ private void resolveProperties(RestToolKit toolKit, String prefix, Class type if (returnType == Void.TYPE) { continue; } - if (name.startsWith("get")) { + if (name.length() > 3 && name.startsWith("get")) { name = toName(name, 3); - getMethodMap.put(name, method); - allNames.add(name); - } else if (name.startsWith("is") && returnType == Boolean.TYPE) { - name = toName(name, 2); - getMethodMap.put(name, method); - allNames.add(name); + if (pbFields == null || pbFields.contains(name)) { + getMethodMap.put(name, method); + allNames.add(name); + } + } else if (name.length() > 2 && name.startsWith("is") && returnType == Boolean.TYPE) { + if (pbFields == null || pbFields.contains(name)) { + name = toName(name, 2); + getMethodMap.put(name, method); + allNames.add(name); + } } } else if (count == 1) { - if (name.startsWith("set")) { + if (name.length() > 3 && name.startsWith("set")) { name = toName(name, 3); setMethodMap.put(name, method); allNames.add(name); @@ -149,7 +178,10 @@ private void resolveProperties(RestToolKit toolKit, String prefix, Class type Field field = fieldMap.get(name); Method getMethod = getMethodMap.get(name); Method setMethod = setMethodMap.get(name); - PropertyMeta meta = new PropertyMeta(toolKit, field, getMethod, setMethod, prefix, name); + int visibility = pbFields == null + ? (setMethod == null ? 0 : 1) << 2 | (getMethod == null ? 0 : 1) << 1 | (field == null ? 0 : 1) + : 0b011; + PropertyMeta meta = new PropertyMeta(toolKit, field, getMethod, setMethod, prefix, name, visibility); properties.put(meta.getName(), meta); } @@ -284,9 +316,11 @@ public static final class PropertyMeta extends NestableParameterMeta { private final Method getMethod; private final Method setMethod; private final Parameter parameter; + private final int visibility; - PropertyMeta(RestToolKit toolKit, Field f, Method gm, Method sm, String prefix, String name) { + PropertyMeta(RestToolKit toolKit, Field f, Method gm, Method sm, String prefix, String name, int visibility) { super(toolKit, prefix, name); + this.visibility = visibility; field = f; getMethod = gm; setMethod = sm; @@ -294,6 +328,10 @@ public static final class PropertyMeta extends NestableParameterMeta { initNestedMeta(); } + public int getVisibility() { + return visibility; + } + @Override public Class getType() { if (field != null) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java index 5698024a1c9..e00d6cd2294 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java @@ -26,10 +26,8 @@ import javax.annotation.Nullable; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Collection; -import java.util.Optional; public abstract class ParameterMeta extends AnnotationSupport { @@ -84,7 +82,7 @@ public final Class getActualType() { Class type = actualType; if (type == null) { type = getType(); - if (type == Optional.class) { + if (TypeUtils.isWrapperType(type)) { type = TypeUtils.getNestedActualType(getGenericType(), 0); if (type == null) { type = Object.class; @@ -99,8 +97,8 @@ public final Type getActualGenericType() { Type type = actualGenericType; if (type == null) { type = getGenericType(); - if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType() == Optional.class) { - type = TypeUtils.getNestedGenericType(getGenericType(), 0); + if (TypeUtils.isWrapperType(TypeUtils.getActualType(type))) { + type = TypeUtils.getNestedGenericType(type, 0); if (type == null) { type = Object.class; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ProtoBean.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ProtoBean.java new file mode 100644 index 00000000000..3f9a9d3327d --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ProtoBean.java @@ -0,0 +1,45 @@ +/* + * 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.protocol.tri.rest.mapping.meta; + +import org.apache.dubbo.common.utils.ClassUtils; + +import java.util.Set; +import java.util.stream.Collectors; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Message; + +final class ProtoBean { + + public static final boolean HAS_PB = ClassUtils.hasProtobuf(); + + public static Set getFields(Class clazz) { + if (HAS_PB && Message.class.isAssignableFrom(clazz)) { + try { + Descriptor descriptor = + (Descriptor) clazz.getMethod("getDescriptor").invoke(null); + return descriptor.getFields().stream() + .map(FieldDescriptor::getName) + .collect(Collectors.toSet()); + } catch (Exception ignored) { + } + } + return null; + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java index 450e63c49bd..2486f5a45f8 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java @@ -18,7 +18,6 @@ import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; import java.util.HashMap; import java.util.Map; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java index ae5f66913a5..d6b8ea8b2ce 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java @@ -29,6 +29,8 @@ import java.util.Map; import java.util.Set; +import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_OPENAPI_PREFIX; + public final class ConfigFactory { private static Map CONFIG_METHODS; @@ -40,6 +42,15 @@ public ConfigFactory(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; } + public static boolean isOpenAPIEnabled(FrameworkModel frameworkModel) { + Environment environment = getEnvironment(frameworkModel); + return environment.getConfiguration().getBoolean(H2_SETTINGS_OPENAPI_PREFIX + ".enabled", true); + } + + private static Environment getEnvironment(FrameworkModel frameworkModel) { + return frameworkModel.defaultApplication().modelEnvironment(); + } + public OpenAPIConfig getConfig(String group) { return getConfigMap().get(group); } @@ -62,20 +73,20 @@ private Map getConfigMap() { private Map readConfigMap() { Map map = new HashMap<>(); - Environment environment = frameworkModel.defaultApplication().modelEnvironment(); + Environment environment = getEnvironment(frameworkModel); Configuration configuration = environment.getConfiguration(); List> configMaps = environment.getConfigurationMaps(); Set allKeys = new HashSet<>(); for (Map configMap : configMaps) { for (String key : configMap.keySet()) { - if (key.startsWith(Constants.CONFIG_PREFIX)) { + if (key.startsWith(H2_SETTINGS_OPENAPI_PREFIX)) { allKeys.add(key); } } } - int len = Constants.CONFIG_PREFIX.length(); + int len = H2_SETTINGS_OPENAPI_PREFIX.length(); for (String fullKey : allKeys) { if (fullKey.length() > len) { char c = fullKey.charAt(len); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java index c7262593300..2b4c2c2a5af 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java @@ -24,7 +24,5 @@ public final class Constants { public static final String DEFAULT_GROUP = "default"; public static final String GLOBAL_GROUP = ""; - public static final String CONFIG_PREFIX = "dubbo.protocol.triple.rest.openapi"; - private Constants() {} } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java index 6ff8a875e3e..76f956a1ac6 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java @@ -19,8 +19,8 @@ import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; public interface Context { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java index 083a657e498..6cd7299d954 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java @@ -16,18 +16,19 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +import org.apache.dubbo.common.utils.Holder; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; final class ContextImpl extends AbstractContext implements Context { private final OpenAPIRequest request; - private HttpRequest httpRequest; - private HttpResponse httpResponse; + private Holder httpRequest; + private Holder httpResponse; ContextImpl(OpenAPI openAPI, SchemaFactory schemaFactory, ExtensionFactory extFactory, OpenAPIRequest request) { super(openAPI, schemaFactory, extFactory); @@ -41,17 +42,23 @@ public OpenAPIRequest getRequest() { @Override public HttpRequest getHttpRequest() { - if (httpRequest == null) { - httpRequest = RpcContext.getServiceContext().getRequest(HttpRequest.class); + Holder holder = httpRequest; + if (holder == null) { + holder = new Holder<>(); + holder.set(RpcContext.getServiceContext().getRequest(HttpRequest.class)); + httpRequest = holder; } - return httpRequest; + return holder.get(); } @Override public HttpResponse getHttpResponse() { - if (httpResponse == null) { - httpResponse = RpcContext.getServiceContext().getResponse(HttpResponse.class); + Holder holder = httpResponse; + if (holder == null) { + holder = new Holder<>(); + holder.set(RpcContext.getServiceContext().getResponse(HttpResponse.class)); + httpResponse = holder; } - return httpResponse; + return holder.get(); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index 9c9656eddd3..906f2d98b09 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -20,16 +20,30 @@ import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; import org.apache.dubbo.common.utils.LRUCache; import org.apache.dubbo.common.utils.Pair; +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.HttpResult; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; +import org.apache.dubbo.remoting.http12.message.MediaType; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree.Match; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.Registration; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingRegistry; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; import java.lang.ref.SoftReference; import java.lang.reflect.Method; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.IdentityHashMap; @@ -38,9 +52,10 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -public class DefaultOpenAPIService implements OpenAPIService { +public class DefaultOpenAPIService implements OpenAPIRequestHandler, OpenAPIService { private static final FluentLogger LOG = FluentLogger.of(DefaultOpenAPIService.class); + private static final String API_DOCS = "/api-docs"; private final LRUCache> cache = new LRUCache<>(64); private final FrameworkModel frameworkModel; @@ -49,6 +64,7 @@ public class DefaultOpenAPIService implements OpenAPIService { private final DefinitionMerger definitionMerger; private final DefinitionFilter definitionFilter; private final DefinitionEncoder definitionEncoder; + private final RadixTree tree; private RequestMappingRegistry requestMappingRegistry; private volatile List openAPIs; @@ -62,12 +78,34 @@ public DefaultOpenAPIService(FrameworkModel frameworkModel) { definitionMerger = new DefinitionMerger(frameworkModel); definitionFilter = new DefinitionFilter(frameworkModel); definitionEncoder = new DefinitionEncoder(frameworkModel); + tree = initRequestHandlers(); } public void setRequestMappingRegistry(RequestMappingRegistry requestMappingRegistry) { this.requestMappingRegistry = requestMappingRegistry; } + private RadixTree initRequestHandlers() { + RadixTree tree = new RadixTree<>(false); + for (OpenAPIRequestHandler handler : extensionFactory.getExtensions(OpenAPIRequestHandler.class)) { + for (String path : handler.getPaths()) { + tree.addPath(path, handler); + } + } + tree.addPath(this, API_DOCS, API_DOCS + "/{group}"); + return tree; + } + + @Override + public HttpResult handle(String path, HttpRequest httpRequest, HttpResponse httpResponse) { + OpenAPIRequest request = httpRequest.attribute(OpenAPIRequest.class.getName()); + request.setGroup(RequestUtils.getPathVariable(httpRequest, "group")); + return HttpResult.builder() + .contentType(MediaType.APPLICATION + '/' + request.getFormat()) + .body(handleDocument(request).getBytes(StandardCharsets.UTF_8)) + .build(); + } + @Override public OpenAPI getOpenAPI(OpenAPIRequest request) { if (openAPIs == null) { @@ -105,6 +143,31 @@ private List resolveOpenAPIs() { @Override public String getDocument(OpenAPIRequest request) { + request = Helper.formatRequest(request); + HttpRequest httpRequest = RpcContext.getServiceContext().getRequest(HttpRequest.class); + if (!RequestUtils.isRestRequest(httpRequest)) { + return handleDocument(request); + } + + String path = RequestUtils.getPathVariable(httpRequest, "path"); + path = path == null ? API_DOCS : '/' + path; + List> matches = tree.matchRelaxed(path); + if (matches.isEmpty()) { + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); + } + + Collections.sort(matches); + Match match = matches.get(0); + HttpResponse httpResponse = RpcContext.getServiceContext().getResponse(HttpResponse.class); + if (request.getFormat() == null) { + request.setFormat(Helper.parseFormat(httpResponse.contentType())); + } + httpRequest.setAttribute(OpenAPIRequest.class.getName(), request); + httpRequest.setAttribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE, match.getVariableMap()); + throw match.getValue().handle(path, httpRequest, httpResponse).toPayload(); + } + + private String handleDocument(OpenAPIRequest request) { String cacheKey = request.toString(); SoftReference ref = cache.get(cacheKey); if (ref != null) { @@ -126,15 +189,11 @@ public void refresh() { if (exported) { export(); } - OpenAPIRequest request = new OpenAPIRequest(); - request.setPretty(true); - String openAPI = getDocument(request); - LOG.info("Refreshed OpenAPI documents: {}", openAPI); } @Override public void export() { - if (extensionFactory.getExtensions(DocumentPublisher.class).length == 0) { + if (extensionFactory.getExtensions(OpenAPIDocumentPublisher.class).length == 0) { return; } @@ -149,7 +208,7 @@ public void export() { } private void doExport() { - for (DocumentPublisher publisher : extensionFactory.getExtensions(DocumentPublisher.class)) { + for (OpenAPIDocumentPublisher publisher : extensionFactory.getExtensions(OpenAPIDocumentPublisher.class)) { try { publisher.publish(request -> { OpenAPI openAPI = getOpenAPI(request); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java index 962d9c10eba..8555054e98b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java @@ -18,11 +18,11 @@ import org.apache.dubbo.common.utils.JsonUtils; import org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException; +import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.remoting.http12.message.codec.YamlCodec; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.proto.ProtoEncoder; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; @@ -50,9 +50,9 @@ public String encode(OpenAPI openAPI, OpenAPIRequest request) { openAPI.writeTo(root, context); String format = request.getFormat(); - format = format == null ? "json" : format.toLowerCase(); + format = format == null ? MediaType.JSON : format.toLowerCase(); switch (format) { - case "json": + case MediaType.JSON: if (Boolean.TRUE.equals(request.getPretty())) { return JsonUtils.toPrettyJson(root); } @@ -68,7 +68,7 @@ public String encode(OpenAPI openAPI, OpenAPIRequest request) { } return protoEncoder.encode(openAPI); default: - throw new UnsupportedMediaTypeException("application/" + format); + throw new UnsupportedMediaTypeException("text/" + format); } } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java index 9234cfcad75..3f194c68468 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Components; @@ -30,7 +31,6 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; import java.util.Iterator; import java.util.List; @@ -235,13 +235,13 @@ private void filterHeader(ApiResponse response, Operation operation, OpenAPIFilt filterSchema(header::getSchema, header::setSchema, header, filters, context); - Map contents = header.getContent(); + Map contents = header.getContents(); if (contents == null) { continue; } - for (MediaType mediaType : contents.values()) { - filterSchema(mediaType::getSchema, mediaType::setSchema, mediaType, filters, context); + for (MediaType content : contents.values()) { + filterSchema(content::getSchema, content::setSchema, content, filters, context); } } } @@ -251,8 +251,8 @@ private boolean filterContext(Map contents, OpenAPIFilter[] f return true; } - for (MediaType mediaType : contents.values()) { - filterSchema(mediaType::getSchema, mediaType::setSchema, mediaType, filters, context); + for (MediaType content : contents.values()) { + filterSchema(content::getSchema, content::setSchema, content, filters, context); } return false; } @@ -283,7 +283,7 @@ private void filterSchemas(Components components, OpenAPIFilter[] filters, Conte } private void filterSchema( - Supplier getter, Consumer setter, Node node, OpenAPIFilter[] filters, Context context) { + Supplier getter, Consumer setter, Node owner, OpenAPIFilter[] filters, Context context) { Schema schema = getter.get(); if (schema == null) { return; @@ -291,7 +291,7 @@ private void filterSchema( Schema initialSchema = schema; for (OpenAPIFilter filter : filters) { - schema = filter.filterSchema(schema, node, context); + schema = filter.filterSchema(schema, owner, context); if (schema == null) { setter.accept(null); return; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index 99f2853fd61..4a66457993b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.utils.JsonUtils; import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Components; @@ -61,11 +62,11 @@ final class DefinitionMerger { } public OpenAPI merge(List openAPIs, OpenAPIRequest request) { - OpenAPI result = new OpenAPI(); + OpenAPI model = new OpenAPI().setInfo(new Info()); if (openAPIs.isEmpty()) { - applyConfig(result, configFactory.getGlobalConfig()); - return result; + applyConfig(model, configFactory.getGlobalConfig()); + return model; } String group = trim(request.getGroup()); @@ -74,39 +75,48 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { } String version = trim(request.getVersion()); if (version != null) { - result.setOpenapi(formatVersion(version)); + model.setOpenapi(formatVersion(version)); } - applyConfig(result, configFactory.getConfig(group)); + applyConfig(model, configFactory.getConfig(group)); - String[] tags = trim(request.getTags()); - String service = trim(request.getService()); + String[] tags = request.getTag(); + String[] services = request.getService(); for (OpenAPI api : openAPIs) { - if (service != null) { - String apiService = api.getService().getServiceInterface(); - if (apiService != null && !apiService.regionMatches(true, 0, service, 0, service.length())) { - continue; - } + if (isServiceNotMatch(api.getService().getServiceInterface(), services)) { + continue; } if (group.equals(api.getGroup())) { - mergeBasic(result, api); + mergeBasic(model, api); } - mergePaths(result, api, group, tags); + mergePaths(model, api, group, tags); - mergeSecuritySchemes(result, api); + mergeSecuritySchemes(model, api); - mergeTags(result, api); + mergeTags(model, api); } - applyConfig(result, configFactory.getGlobalConfig()); + applyConfig(model, configFactory.getGlobalConfig()); - addSchemas(result); + addSchemas(model); - cleanup(result); + completeModel(model); - return result; + return model; + } + + private static boolean isServiceNotMatch(String apiService, String[] services) { + if (apiService == null || services == null) { + return false; + } + for (String service : services) { + if (apiService.regionMatches(true, 0, service, 0, service.length())) { + return false; + } + } + return true; } private void applyConfig(OpenAPI api, OpenAPIConfig config) { @@ -119,9 +129,6 @@ private void applyConfig(OpenAPI api, OpenAPIConfig config) { } Info info = api.getInfo(); - if (info == null) { - api.setInfo(info = new Info()); - } if (info.getTitle() == null) { info.setTitle(config.getInfoTitle()); } @@ -330,22 +337,8 @@ private void mergePathItem(String path, PathItem pathItem, PathItem from, String continue; } - if (tags != null) { - Set operationTags = fromOperation.getTags(); - if (operationTags == null) { - continue; - } - boolean exclude = false; - for (String tag : tags) { - if (operationTags.contains(tag)) { - continue; - } - exclude = true; - break; - } - if (exclude) { - continue; - } + if (isTagNotMatch(tags, fromOperation.getTags())) { + continue; } Operation operation = operations.get(httpMethod); @@ -383,6 +376,18 @@ private void mergePathItem(String path, PathItem pathItem, PathItem from, String pathItem.addExtensions(from.getExtensions()); } + private static boolean isTagNotMatch(String[] tags, Set operationTags) { + if (tags == null || operationTags == null) { + return false; + } + for (String tag : tags) { + if (operationTags.contains(tag)) { + return false; + } + } + return true; + } + private void mergeSecuritySchemes(OpenAPI api, OpenAPI from) { Components fromComponents = from.getComponents(); if (fromComponents == null) { @@ -435,7 +440,11 @@ private void addSchemas(OpenAPI api) { } for (PathItem pathItem : api.getPaths().values()) { - for (Operation operation : pathItem.getOperations().values()) { + Map operations = pathItem.getOperations(); + if (operations == null) { + continue; + } + for (Operation operation : operations.values()) { List parameters = operation.getParameters(); if (parameters != null) { for (Parameter parameter : parameters) { @@ -444,8 +453,8 @@ private void addSchemas(OpenAPI api) { if (contents == null) { continue; } - for (MediaType mediaType : contents.values()) { - addSchema(mediaType.getSchema(), schemas); + for (MediaType content : contents.values()) { + addSchema(content.getSchema(), schemas); } } } @@ -455,8 +464,8 @@ private void addSchemas(OpenAPI api) { if (contents == null) { continue; } - for (MediaType mediaType : contents.values()) { - addSchema(mediaType.getSchema(), schemas); + for (MediaType content : contents.values()) { + addSchema(content.getSchema(), schemas); } } Map responses = operation.getResponses(); @@ -468,13 +477,13 @@ private void addSchemas(OpenAPI api) { addSchema(header.getSchema(), schemas); } } - + Map contents = response.getContents(); if (contents == null) { continue; } - for (MediaType mediaType : contents.values()) { - addSchema(mediaType.getSchema(), schemas); + for (MediaType content : contents.values()) { + addSchema(content.getSchema(), schemas); } } } @@ -486,28 +495,37 @@ private void addSchema(Schema schema, Map schemas) { if (schema == null) { return; } - Schema targetSchema = schema.getTargetSchema(); - if (targetSchema == null) { - return; - } - String name = targetSchema.getJavaType().getName(); - schema.setRef(name); - if (schemas.putIfAbsent(name, targetSchema) != null) { - return; - } - - addSchema(targetSchema.getItems(), schemas); + addSchema(schema.getItems(), schemas); - Map properties = targetSchema.getProperties(); + Map properties = schema.getProperties(); if (properties != null) { for (Schema property : properties.values()) { addSchema(property, schemas); } } - addSchema(targetSchema.getAdditionalPropertiesSchema(), schemas); + addSchema(schema.getAdditionalPropertiesSchema(), schemas); + + Schema targetSchema = schema.getTargetSchema(); + if (targetSchema == null) { + return; + } + + String name = targetSchema.getJavaType().getSimpleName(); + schema.setRef("#/components/schemas/" + name); + if (schemas.putIfAbsent(name, targetSchema) == null) { + addSchema(targetSchema, schemas); + } } - private void cleanup(OpenAPI api) {} + private void completeModel(OpenAPI api) { + Info info = api.getInfo(); + if (info.getTitle() == null) { + info.setTitle("Dubbo OpenAPI"); + } + if (info.getVersion() == null) { + info.setVersion("v1"); + } + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index 89554400349..a6e9ce312b8 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -39,7 +39,6 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; import java.util.Arrays; import java.util.Collection; @@ -96,7 +95,7 @@ public OpenAPI resolve(ServiceMeta serviceMeta, Collection> r continue; } for (PathExpression expression : pathCondition.getExpressions()) { - String path = Helper.toPathValue(expression); + String path = expression.toString(); PathItem pathItem = openAPI.getOrAddPath(path); String ref = pathItem.getRef(); if (ref != null) { @@ -237,7 +236,8 @@ private String generateOperationId(MethodMeta meta, OpenAPI openAPI) { if (name == null) { return null; } - NamingStrategy strategy = extensionFactory.getExtension(NamingStrategy.class, NamingStrategy.PREFIX + name); + OpenAPINamingStrategy strategy = + extensionFactory.getExtension(OpenAPINamingStrategy.class, OpenAPINamingStrategy.PREFIX + name); if (strategy == null) { return null; } @@ -275,8 +275,10 @@ private void resolveRequestBody(RequestBody body, OpenAPI openAPI, MethodMeta me private void resolveResponse( String httpStatusCode, ApiResponse response, OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) { int httpStatus = Integer.parseInt(httpStatusCode); - if (httpStatus > 201 && httpStatus < 400) { + if (response.getDescription() == null) { response.setDescription(HttpUtils.getStatusMessage(httpStatus)); + } + if (httpStatus > 201 && httpStatus < 400) { return; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java index b88cb3bf05a..0823ba1c8e2 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java @@ -57,6 +57,9 @@ public T[] getExtensions(Class type) { } public T[] getExtensions(Class type, String group) { + if (group == null) { + return getExtensions(type); + } return (T[]) cache.computeIfAbsent(Pair.of(type, group), k -> { List list = new ArrayList<>(); for (OpenAPIExtension extension : extensions) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index 32796bd8b5d..ab488d05a1e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathSegment; @@ -38,7 +39,32 @@ public final class Helper { private static final String[][] VERBS_TABLE = { - {GET.name(), "get", "load", "fetch", "read", "retrieve", "list", "find", "query", "search", "is"}, + { + GET.name(), + "get", + "load", + "fetch", + "read", + "retrieve", + "obtain", + "list", + "find", + "query", + "search", + "is", + "are", + "was", + "has", + "check", + "verify", + "test", + "can", + "should", + "need", + "allow", + "support", + "accept" + }, {PUT.name(), "put", "replace"}, {PATCH.name(), "patch", "update", "modify", "edit", "change", "set"}, {DELETE.name(), "delete", "remove", "erase", "destroy", "drop"} @@ -124,6 +150,39 @@ public static String formatVersion(String version) { return Constants.VERSION_30; } + public static OpenAPIRequest formatRequest(OpenAPIRequest request) { + if (request == null) { + return new OpenAPIRequest(); + } + request.setGroup(trim(request.getGroup())); + + String[] tag = trim(request.getTag()); + if (tag != null) { + Arrays.sort(tag); + } + request.setTag(tag); + + String[] service = trim(request.getService()); + if (service != null) { + Arrays.sort(service); + } + request.setService(service); + + request.setVersion(trim(request.getVersion())); + request.setFormat(trim(request.getFormat())); + return request; + } + + public static String parseFormat(String contentType) { + if (contentType != null) { + int index = contentType.indexOf('/'); + if (index > 0 && contentType.indexOf("htm", index) == -1) { + return contentType.substring(index + 1); + } + } + return "json"; + } + public static String trim(String str) { if (str == null || str.isEmpty()) { return null; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DocumentPublisher.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.java similarity index 89% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DocumentPublisher.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.java index 25a216df91c..c92502bb971 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DocumentPublisher.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.java @@ -17,11 +17,12 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.common.utils.Pair; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import java.util.function.Function; -public interface DocumentPublisher extends OpenAPIExtension { +public interface OpenAPIDocumentPublisher extends OpenAPIExtension { void publish(Function> fn); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/NamingStrategy.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java similarity index 94% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/NamingStrategy.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java index 1c2d0c04a76..f65600c2e65 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/NamingStrategy.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java @@ -19,7 +19,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -public interface NamingStrategy extends OpenAPIExtension { +public interface OpenAPINamingStrategy extends OpenAPIExtension { String PREFIX = "naming-strategy-"; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java new file mode 100644 index 00000000000..47c5619f6e7 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java @@ -0,0 +1,30 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.HttpResult; + +public interface OpenAPIRequestHandler extends OpenAPIExtension { + + default String[] getPaths() { + return null; + } + + HttpResult handle(String path, HttpRequest request, HttpResponse response); +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java new file mode 100644 index 00000000000..c3662bba8db --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java @@ -0,0 +1,28 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; + +public interface OpenAPISchemaPredicate extends OpenAPIExtension { + + boolean testClass(Class clazz, ParameterMeta parameter); + + boolean testProperty(ParameterMeta parameter, BeanMeta bean, PropertyMeta property); +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java similarity index 87% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaResolver.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java index d59005da621..3d5d3d693c9 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java @@ -14,15 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema; +package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import java.lang.reflect.Type; -public interface SchemaResolver extends OpenAPIExtension { +public interface OpenAPISchemaResolver extends OpenAPIExtension { Schema resolve(ParameterMeta parameter, Context context, Chain chain); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java index 6e12b9cda96..aa5e01b5e57 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; public interface OpenAPIService { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/PrimitiveSchema.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java similarity index 96% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/PrimitiveSchema.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java index 9fe18392b17..e9305cf48ae 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/PrimitiveSchema.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java @@ -14,15 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema; +package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type; -import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; /** * Primitive Schema @@ -56,7 +54,6 @@ public enum PrimitiveSchema { ARRAY(Object[].class, Type.ARRAY); private static final Map TYPE_MAPPING = new ConcurrentHashMap<>(); - private static final List SYSTEM_PREFIXES = new CopyOnWriteArrayList<>(); static { for (PrimitiveSchema schema : values()) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/proto/ProtoEncoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java similarity index 94% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/proto/ProtoEncoder.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java index 43215707984..bffde4a8653 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/proto/ProtoEncoder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.protocol.tri.rest.openapi.proto; +package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java index c68aa8c91ab..0b0f53f9b2b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java @@ -18,7 +18,6 @@ import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaFactory; public interface ResolveContext { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java similarity index 79% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaFactory.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java index d7d828d2882..ad51e5210af 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/schema/SchemaFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java @@ -14,17 +14,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema; +package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.TypeParameterMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ExtensionFactory; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.Chain; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.Context; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaResolver.Chain; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.SchemaResolver.Context; import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; import java.lang.reflect.GenericArrayType; @@ -32,22 +32,24 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; -import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.PrimitiveSchema.ARRAY; -import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.schema.PrimitiveSchema.OBJECT; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.PrimitiveSchema.ARRAY; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.PrimitiveSchema.OBJECT; public final class SchemaFactory { - private final SchemaResolver[] resolvers; + private final OpenAPISchemaResolver[] resolvers; + private final OpenAPISchemaPredicate[] predicates; private final Map, Optional> schemaMap = CollectionUtils.newConcurrentHashMap(); private final Map, String> nameMap = CollectionUtils.newConcurrentHashMap(); public SchemaFactory(FrameworkModel frameworkModel) { - resolvers = frameworkModel.getOrRegisterBean(ExtensionFactory.class).getExtensions(SchemaResolver.class); + ExtensionFactory extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); + resolvers = extensionFactory.getExtensions(OpenAPISchemaResolver.class); + predicates = extensionFactory.getExtensions(OpenAPISchemaPredicate.class); } public Map, Optional> getSchemaMap() { @@ -151,13 +153,17 @@ private Schema resolveClassSchema(Class clazz, ParameterMeta parameter) { return existingSchema.map(s -> new Schema().setTargetSchema(s)).orElseGet(OBJECT::newSchema); } - String name = clazz.getName(); - List systemPrefixes = TypeUtils.getSystemPrefixes(); - for (int i = 0, size = systemPrefixes.size(); i < size; i++) { - if (name.startsWith(systemPrefixes.get(i))) { - schemaMap.put(clazz, Optional.empty()); - return OBJECT.newSchema(); + if (TypeUtils.isSystemType(clazz)) { + schemaMap.put(clazz, Optional.empty()); + return OBJECT.newSchema(); + } + + for (OpenAPISchemaPredicate predicate : predicates) { + if (predicate.testClass(clazz, parameter)) { + continue; } + schemaMap.put(clazz, Optional.empty()); + return OBJECT.newSchema(); } if (clazz.isEnum()) { @@ -172,8 +178,19 @@ private Schema resolveClassSchema(Class clazz, ParameterMeta parameter) { Schema beanSchema = OBJECT.newSchema().setJavaType(clazz); schemaMap.put(clazz, Optional.of(beanSchema)); BeanMeta beanMeta = new BeanMeta(parameter.getToolKit(), clazz, true); - for (ParameterMeta param : beanMeta.getProperties()) { - beanSchema.addProperty(param.getName(), getSchema(param)); + out: + for (PropertyMeta property : beanMeta.getProperties()) { + for (OpenAPISchemaPredicate predicate : predicates) { + if (predicate.testProperty(parameter, beanMeta, property)) { + continue; + } + continue out; + } + + int visibility = property.getVisibility(); + if (visibility > 1 && (visibility & 1) == 1) { + beanSchema.addProperty(property.getName(), getSchema(property)); + } } return new Schema().setTargetSchema(beanSchema); } @@ -182,19 +199,14 @@ private Schema resolveNestedSchema(Type nestedType, ParameterMeta parameter) { return resolveSchema(nestedType, new TypeParameterMeta(parameter.getToolKit(), nestedType)); } - private Schema cacheSchema(Class clazz, Schema schema) { - schemaMap.put(clazz, Optional.ofNullable(schema)); - return schema; - } - static final class ChainImpl implements Chain { - private final SchemaResolver[] resolvers; + private final OpenAPISchemaResolver[] resolvers; private final Function fallback; private int cursor; - ChainImpl(SchemaResolver[] resolvers, Function fallback) { + ChainImpl(OpenAPISchemaResolver[] resolvers, Function fallback) { this.resolvers = resolvers; this.fallback = fallback; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java index 38d9fe835dd..525e25b66e7 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java @@ -94,11 +94,11 @@ public ApiResponse setContents(Map contents) { return this; } - public ApiResponse addContent(String name, MediaType mediaType) { + public ApiResponse addContent(String name, MediaType content) { if (contents == null) { contents = new LinkedHashMap<>(); } - contents.put(name, mediaType); + contents.put(name, content); return this; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java index 15eaff62433..90a0c764d46 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java @@ -47,7 +47,7 @@ public String toString() { private Schema schema; private Object example; private Map examples; - private Map content; + private Map contents; public String getDescription() { return description; @@ -140,30 +140,30 @@ public Header removeExample(String name) { return this; } - public Map getContent() { - return content; + public Map getContents() { + return contents; } public MediaType getContent(String name) { - return content == null ? null : content.get(name); + return contents == null ? null : contents.get(name); } - public Header setContent(Map content) { - this.content = content; + public Header setContents(Map contents) { + this.contents = contents; return this; } - public Header addContent(String name, MediaType mediaType) { - if (content == null) { - content = new LinkedHashMap<>(); + public Header addContent(String name, MediaType content) { + if (contents == null) { + contents = new LinkedHashMap<>(); } - content.put(name, mediaType); + contents.put(name, content); return this; } public Header removeContent(String name) { - if (content != null) { - content.remove(name); + if (contents != null) { + contents.remove(name); } return this; } @@ -173,7 +173,7 @@ public Header clone() { Header clone = super.clone(); clone.schema = clone(schema); clone.examples = clone(examples); - clone.content = clone(content); + clone.contents = clone(contents); return clone; } @@ -188,7 +188,7 @@ public Map writeTo(Map node, Context context) { write(node, "schema", schema, context); write(node, "example", example); write(node, "examples", examples, context); - write(node, "content", content, context); + write(node, "content", contents, context); writeExtensions(node); return node; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java index 77bec3c5ee8..0179dc54381 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java @@ -207,11 +207,11 @@ public Parameter setContents(Map contents) { return this; } - public Parameter addContent(String name, MediaType mediaType) { + public Parameter addContent(String name, MediaType content) { if (contents == null) { contents = new LinkedHashMap<>(); } - contents.put(name, mediaType); + contents.put(name, content); return this; } @@ -260,7 +260,7 @@ public Parameter clone() { @Override public Map writeTo(Map node, Context context) { write(node, "name", name); - write(node, "in", in); + write(node, "in", in.toString()); write(node, "description", description); write(node, "required", required); write(node, "deprecated", deprecated); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java index ee375dd7955..4e8ce6f5e2a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java @@ -155,14 +155,17 @@ public PathItem clone() { @Override public Map writeTo(Map node, Context context) { - write(node, "$ref", ref); - write(node, "summary", summary); - write(node, "description", description); - for (Map.Entry entry : operations.entrySet()) { - write(node, entry.getKey().name().toLowerCase(), entry.getValue(), context); + if (ref != null) { + write(node, "$ref", ref); + } else if (operations != null) { + write(node, "summary", summary); + write(node, "description", description); + for (Map.Entry entry : operations.entrySet()) { + write(node, entry.getKey().name().toLowerCase(), entry.getValue(), context); + } + write(node, "servers", servers, context); + write(node, "parameters", parameters, context); } - write(node, "servers", servers, context); - write(node, "parameters", parameters, context); writeExtensions(node); return node; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java index d0bf06dc172..eb3e21165ad 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java @@ -40,15 +40,15 @@ public Map getContents() { return contents; } - public MediaType getContent(String mediaType) { - return contents == null ? null : contents.get(mediaType); + public MediaType getContent(String content) { + return contents == null ? null : contents.get(content); } - public MediaType getOrAddContent(String mediaType) { + public MediaType getOrAddContent(String content) { if (contents == null) { contents = new LinkedHashMap<>(); } - return contents.computeIfAbsent(mediaType, k -> new MediaType()); + return contents.computeIfAbsent(content, k -> new MediaType()); } public RequestBody setContents(Map contents) { @@ -56,11 +56,11 @@ public RequestBody setContents(Map contents) { return this; } - public RequestBody addContent(String name, MediaType mediaType) { + public RequestBody addContent(String name, MediaType content) { if (contents == null) { contents = new LinkedHashMap<>(); } - contents.put(name, mediaType); + contents.put(name, content); return this; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java index 708f2c1ce6f..a444cfd5831 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java @@ -20,14 +20,17 @@ import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ResolveContext; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; import java.util.Arrays; @@ -37,17 +40,17 @@ import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim; @Activate(order = 100) -public final class BasicOpenAPIDefinitionResolver implements OpenAPIDefinitionResolver { +public final class BasicOpenAPIDefinitionResolver implements OpenAPIDefinitionResolver, OpenAPISchemaResolver { @Override public boolean hidden(ServiceMeta serviceMeta) { - AnnotationMeta openAPI = serviceMeta.getAnnotation(Annotations.OpenAPI); + AnnotationMeta openAPI = serviceMeta.findAnnotation(Annotations.OpenAPI); return openAPI != null && openAPI.getBoolean("hidden"); } @Override public OpenAPI resolve(ServiceMeta serviceMeta) { - AnnotationMeta openAPI = serviceMeta.getAnnotation(Annotations.OpenAPI); + AnnotationMeta openAPI = serviceMeta.findAnnotation(Annotations.OpenAPI); if (openAPI == null) { return null; } @@ -60,9 +63,9 @@ public OpenAPI resolve(ServiceMeta serviceMeta) { } model.setGroup(trim(openAPI.getString("group"))); - String title = trim(openAPI.getString("title")); - String description = trim(openAPI.getString("description")); - String version = trim(openAPI.getString("version")); + String title = trim(openAPI.getString("infoTitle")); + String description = trim(openAPI.getString("infoDescription")); + String version = trim(openAPI.getString("infoVersion")); if (title != null || description != null || version != null) { model.setInfo(new Info().setTitle(title).setDescription(description).setVersion(version)); } @@ -81,13 +84,13 @@ public OpenAPI resolve(ServiceMeta serviceMeta) { @Override public boolean hidden(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { - AnnotationMeta operation = methodMeta.getAnnotation(Annotations.Operation); + AnnotationMeta operation = methodMeta.findAnnotation(Annotations.Operation); return operation != null && operation.getBoolean("hidden"); } @Override public Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { - AnnotationMeta operation = methodMeta.getAnnotation(Annotations.Operation); + AnnotationMeta operation = methodMeta.findAnnotation(Annotations.Operation); if (operation == null) { return null; } @@ -98,7 +101,7 @@ public Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext model.setHttpMethod(HttpMethods.of(method.toUpperCase())); } - String[] tags = Helper.trim(operation.getStringArray("tags")); + String[] tags = trim(operation.getStringArray("tags")); if (tags != null) { model.setTags(new LinkedHashSet<>(Arrays.asList(tags))); } @@ -111,4 +114,9 @@ public Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext model.setExtensions(Helper.toProperties(operation.getStringArray("extensions"))); return model; } + + @Override + public Schema resolve(ParameterMeta parameter, Context context, Chain chain) { + return chain.resolve(parameter, context); + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RequestUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RequestUtils.java index bb152cc7a6b..a471ef5be66 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RequestUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RequestUtils.java @@ -46,6 +46,10 @@ public final class RequestUtils { private RequestUtils() {} + public static boolean isRestRequest(HttpRequest request) { + return request != null && request.hasAttribute(RestConstants.PATH_ATTRIBUTE); + } + public static boolean isMultiPart(HttpRequest request) { String contentType = request.contentType(); return contentType != null && contentType.startsWith(MediaType.MULTIPART_FORM_DATA.getName()); @@ -122,6 +126,19 @@ public static Map getParametersMapStartingWith(HttpRequest reque return params; } + public static String getPathVariable(HttpRequest request, String name) { + Map variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + if (variableMap == null) { + return null; + } + String value = variableMap.get(name); + if (value == null) { + return null; + } + int index = value.indexOf(';'); + return decodeURL(index == -1 ? value : value.substring(0, index)); + } + public static Map> parseMatrixVariables(String matrixVariables) { Map> result = null; StringTokenizer pairs = new StringTokenizer(matrixVariables, ";"); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java index a5f3210b46d..ae089ff964d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.util; +import org.apache.dubbo.common.stream.StreamObserver; import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.common.utils.ConcurrentHashSet; @@ -60,6 +61,7 @@ import java.util.TimeZone; import java.util.TreeMap; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -129,6 +131,21 @@ public static void addSystemPrefixes(String... prefixes) { SYSTEM_PREFIXES.addAll(Arrays.asList(prefixes)); } + public static boolean isSystemType(Class type) { + String name = type.getName(); + List systemPrefixes = TypeUtils.getSystemPrefixes(); + for (int i = 0, size = systemPrefixes.size(); i < size; i++) { + if (name.startsWith(systemPrefixes.get(i))) { + return true; + } + } + return false; + } + + public static boolean isWrapperType(Class type) { + return type == Optional.class || type == CompletableFuture.class || type == StreamObserver.class; + } + public static Class getMapValueType(Class targetClass) { for (Type gi : targetClass.getGenericInterfaces()) { if (gi instanceof ParameterizedType) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractStream.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractStream.java index f2f69bb344d..b73c5623e8a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractStream.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractStream.java @@ -30,7 +30,7 @@ public abstract class AbstractStream implements Stream { protected Executor executor; protected final FrameworkModel frameworkModel; - private static final boolean HAS_PROTOBUF = hasProtobuf(); + private static final boolean HAS_PROTOBUF = ClassUtils.hasProtobuf(); public AbstractStream(Executor executor, FrameworkModel frameworkModel) { this.executor = new SerializingExecutor(executor); @@ -44,13 +44,4 @@ public void setExecutor(Executor executor) { public static boolean getGrpcStatusDetailEnabled() { return HAS_PROTOBUF; } - - private static boolean hasProtobuf() { - try { - ClassUtils.forName("com.google.protobuf.Message"); - return true; - } catch (ClassNotFoundException ignore) { - return false; - } - } } From 3a02bd171188a58ec04c964d89b313b8df8d4b93 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Wed, 20 Nov 2024 00:07:27 +0800 Subject: [PATCH 06/23] Basic definition resolve impl --- .../dubbo/config/nested/OpenAPIConfig.java | 45 ++++--- .../support/jaxrs/BeanArgumentBinder.java | 2 +- .../rest/support/jaxrs/JaxrsRestToolKit.java | 6 + .../dubbo/remoting/http12/rest/OpenAPI.java | 13 -- .../remoting/http12/rest/OpenAPIRequest.java | 34 ++++-- .../dubbo/remoting/http12/rest/Operation.java | 16 +++ .../dubbo/remoting/http12/rest/Schema.java | 29 ++++- .../rest/mapping/meta/AnnotationSupport.java | 42 +++++-- .../tri/rest/mapping/meta/BeanMeta.java | 31 +++-- .../tri/rest/mapping/meta/MethodMeta.java | 8 ++ .../tri/rest/mapping/meta/ParameterMeta.java | 8 +- .../tri/rest/openapi/ConfigFactory.java | 1 + .../protocol/tri/rest/openapi/Constants.java | 5 + .../rest/openapi/DefaultOpenAPIService.java | 1 + .../tri/rest/openapi/DefinitionMerger.java | 114 +++++++++--------- .../tri/rest/openapi/DefinitionResolver.java | 37 +++++- .../rpc/protocol/tri/rest/openapi/Helper.java | 97 ++++++++------- .../rest/openapi/OpenAPISchemaPredicate.java | 4 +- .../tri/rest/openapi/SchemaFactory.java | 31 +++-- .../tri/rest/openapi/model/OpenAPI.java | 14 ++- .../tri/rest/openapi/model/Operation.java | 23 +++- .../tri/rest/openapi/model/PathItem.java | 3 +- .../tri/rest/openapi/model/Schema.java | 55 +++++---- .../tri/rest/support/basic/Annotations.java | 1 + .../basic/BasicOpenAPIDefinitionResolver.java | 74 ++++++++++-- .../rest/support/basic/BasicRestToolKit.java | 9 ++ .../support/basic/BeanArgumentBinder.java | 2 +- .../protocol/tri/rest/util/RestToolKit.java | 3 + 28 files changed, 479 insertions(+), 229 deletions(-) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java index 6668e2238ab..9796772cf7e 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -35,13 +35,6 @@ public class OpenAPIConfig implements Serializable { */ private String path; - /** - * The version of OpenAPI being used. - * e.g. 3.0.1, 3.1.0 - *

The default value is '3.0.1'. - */ - private String version; - /** * The title of the OpenAPI information. */ @@ -122,19 +115,17 @@ public class OpenAPIConfig implements Serializable { */ private String[] defaultHttpStatusCodes; + /** + * Whether to flatten the inherited fields from the parent class into the schema. + *

The default value is {@code false}. + */ + private Boolean schemaFlatten; + /** * The custom settings. */ private Map settings; - public String getExternalDocsUrl() { - return externalDocsUrl; - } - - public void setExternalDocsUrl(String externalDocsUrl) { - this.externalDocsUrl = externalDocsUrl; - } - public Boolean getEnabled() { return enabled; } @@ -151,14 +142,6 @@ public void setPath(String path) { this.path = path; } - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - public String getInfoTitle() { return infoTitle; } @@ -215,6 +198,14 @@ public void setExternalDocsDescription(String externalDocsDescription) { this.externalDocsDescription = externalDocsDescription; } + public String getExternalDocsUrl() { + return externalDocsUrl; + } + + public void setExternalDocsUrl(String externalDocsUrl) { + this.externalDocsUrl = externalDocsUrl; + } + public String[] getServers() { return servers; } @@ -279,6 +270,14 @@ public void setDefaultHttpStatusCodes(String[] defaultHttpStatusCodes) { this.defaultHttpStatusCodes = defaultHttpStatusCodes; } + public Boolean getSchemaFlatten() { + return schemaFlatten; + } + + public void setSchemaFlatten(Boolean schemaFlatten) { + this.schemaFlatten = schemaFlatten; + } + public Map getSettings() { return settings; } diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java index 3c2f77d0de7..7ff3ccd7d10 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java @@ -77,7 +77,7 @@ private Object resolveArgument(ParameterMeta paramMeta, HttpRequest request, Htt Pair.of(paramMeta.getActualType(), prefix), k -> new BeanMeta(paramMeta.getToolKit(), k.getValue(), k.getKey())); - ConstructorMeta constructor = beanMeta.getConstructor(); + ConstructorMeta constructor = beanMeta.getConstructorRequired(); ParameterMeta[] parameters = constructor.getParameters(); Object bean; int len = parameters.length; diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java index 00c38a10096..270a4fde908 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java @@ -18,6 +18,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; @@ -56,4 +57,9 @@ public Object convert(Object value, ParameterMeta parameter) { public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response) { return binder.bind(parameter, request, response); } + + @Override + public ParamType getParamType(ParameterMeta parameter) { + return null; + } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java index a40d411a47d..c149203edc4 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java @@ -24,7 +24,6 @@ /** * Annotation for defining OpenAPI on Dubbo service interface. - * Provide metadata such as tags, groups, title, description, version, hidden, and order. * *

Example usage:

*
@@ -39,23 +38,11 @@
 @Documented
 public @interface OpenAPI {
 
-    /**
-     * Alias for {@link #infoTitle()}.
-     */
-    String value() default "";
-
     /**
      * The openAPI groups.
      */
     String group() default "";
 
-    /**
-     * The version of OpenAPI being used.
-     * e.g. 3.0.1, 3.1.0
-     * 

The default value is '3.0.1'. - */ - String version() default ""; - /** * The openAPI tags. *

Supported Syntax
diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java index 22805c2a04d..4e127a68e0b 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java @@ -32,6 +32,12 @@ public class OpenAPIRequest implements Serializable { */ private String group; + /** + * The openAPI version, using a major.minor.patch versioning scheme + * e.g. 1.0.1 + */ + private String version; + /** * The openAPI tags. Each tag is an or condition. */ @@ -43,20 +49,21 @@ public class OpenAPIRequest implements Serializable { private String[] service; /** - * The openAPI version. + * The openAPI specification version, using a major.minor.patch versioning scheme * e.g. 3.0.1, 3.1.0 - *

The default value is '3.0.1' if not set. + *

The default value is '3.0.1'. */ - private String version; + private String openapi; /** * The format of the response. - *

The default value is '3.0.1' if not set. + *

The default value is 'json'. */ private String format; /** * Whether to pretty print for json. + *

The default value is {@code false}. */ private Boolean pretty; @@ -68,6 +75,14 @@ public void setGroup(String group) { this.group = group; } + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + public String[] getTag() { return tag; } @@ -84,12 +99,12 @@ public void setService(String[] service) { this.service = service; } - public String getVersion() { - return version; + public String getOpenapi() { + return openapi; } - public void setVersion(String version) { - this.version = version; + public void setOpenapi(String openapi) { + this.openapi = openapi; } public String getFormat() { @@ -104,9 +119,8 @@ public Boolean getPretty() { return pretty; } - public OpenAPIRequest setPretty(Boolean pretty) { + public void setPretty(Boolean pretty) { this.pretty = pretty; - return this; } @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java index 9343130cfe1..204b34e010a 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java @@ -22,6 +22,17 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Annotation for defining an operation in the OpenAPI specification for Dubbo services. + * + *

Example usage:

+ *
+ * @Operation(method = "GET", summary = "Retrieve user", tags = {"user", "retrieve"})
+ * public User getUser(String id) {
+ *     ...
+ * }
+ * 
+ */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented @@ -37,6 +48,11 @@ */ String group() default ""; + /** + * The operation version. + */ + String version() default ""; + /** * The HTTP method for this operation. */ diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Schema.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Schema.java index 8f83764d0bb..8c5d35c134f 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Schema.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Schema.java @@ -18,12 +18,27 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -@Target(ElementType.TYPE) +/** + * Annotation for defining a schema in the OpenAPI specification for Dubbo services. + * + *

Example usage:

+ *
+ * @Schema(title = "User Schema", required = true)
+ * public class User {
+ *     @Schema(title = "User name", example = "Tom")
+ *     private String name;
+ *     ...
+ * }
+ * 
+ */ +@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) +@Inherited @Documented public @interface Schema { @@ -37,6 +52,11 @@ */ String group() default ""; + /** + * The schema version. + */ + String version() default ""; + /** * The type of the schema. */ @@ -112,6 +132,13 @@ */ boolean writeOnly() default false; + /** + * Whether to flatten the inherited fields from the parent class into the schema. + * If set to {@code true}, the fields from the parent class will be included directly in the schema, + * instead of being treated as a separate schema. + */ + boolean flatten() default false; + /** * Whether this schema is nullable */ diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java index 776b8ec93d7..8ade26b632b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java @@ -17,7 +17,6 @@ package org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta; import org.apache.dubbo.common.utils.CollectionUtils; -import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; import java.lang.annotation.Annotation; @@ -32,12 +31,12 @@ public abstract class AnnotationSupport { private static final AnnotationMeta[] EMPTY = new AnnotationMeta[0]; - private static final Integer GET_KEY = 1; - private static final Integer GET_MERGED_KEY = 2; - private static final Integer FIND_KEY = 3; - private static final Integer FIND_MERGED_KEY = 4; + private static final int GET_KEY = 1; + private static final int GET_MERGED_KEY = 2; + private static final int FIND_KEY = 3; + private static final int FIND_MERGED_KEY = 4; - private final Map, Optional> cache = CollectionUtils.newConcurrentHashMap(); + private final Map> cache = CollectionUtils.newConcurrentHashMap(); private final Map arrayCache = CollectionUtils.newConcurrentHashMap(); private final RestToolKit toolKit; @@ -72,7 +71,7 @@ public final Annotation[] getRawAnnotations() { } public final AnnotationMeta getAnnotation(Class annotationType) { - return cache.computeIfAbsent(Pair.of(annotationType, GET_KEY), k -> { + return cache.computeIfAbsent(new Key(annotationType, GET_KEY), k -> { AnnotatedElement element = getAnnotatedElement(); Annotation annotation = element.getAnnotation(annotationType); if (annotation != null) { @@ -96,7 +95,7 @@ public final boolean isAnnotated(AnnotationEnum annotationEnum) { } public final AnnotationMeta getMergedAnnotation(Class annotationType) { - return cache.computeIfAbsent(Pair.of(annotationType, GET_MERGED_KEY), k -> { + return cache.computeIfAbsent(new Key(annotationType, GET_MERGED_KEY), k -> { AnnotatedElement element = getAnnotatedElement(); Annotation[] annotations = element.getAnnotations(); for (Annotation annotation : annotations) { @@ -144,7 +143,7 @@ public final AnnotationMeta[] findAnnotations() { } public final AnnotationMeta findAnnotation(Class annotationType) { - return cache.computeIfAbsent(Pair.of(annotationType, FIND_KEY), k -> { + return cache.computeIfAbsent(new Key(annotationType, FIND_KEY), k -> { List elements = getAnnotatedElements(); for (int i = 0, size = elements.size(); i < size; i++) { AnnotatedElement element = elements.get(i); @@ -171,7 +170,7 @@ public final boolean isHierarchyAnnotated(AnnotationEnum annotationEnum) { } public final AnnotationMeta findMergedAnnotation(Class annotationType) { - return cache.computeIfAbsent(Pair.of(annotationType, FIND_MERGED_KEY), k -> { + return cache.computeIfAbsent(new Key(annotationType, FIND_MERGED_KEY), k -> { List elements = getAnnotatedElements(); for (int i = 0, size = elements.size(); i < size; i++) { AnnotatedElement element = elements.get(i); @@ -212,5 +211,28 @@ protected List getAnnotatedElements() { return Collections.singletonList(getAnnotatedElement()); } + private static final class Key { + + private final Class annotationType; + private final int type; + + Key(Class annotationType, int type) { + this.annotationType = annotationType; + this.type = type; + } + + @Override + public int hashCode() { + return (annotationType.hashCode() << 2) + type; + } + + @SuppressWarnings({"EqualsWhichDoesntCheckParameterClass", "EqualsDoesntCheckParameterClass"}) + @Override + public boolean equals(Object obj) { + Key other = (Key) obj; + return annotationType == other.annotationType && type == other.type; + } + } + protected abstract AnnotatedElement getAnnotatedElement(); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java index 54a4aaaeb70..3ce72403e3f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java @@ -51,22 +51,22 @@ public final class BeanMeta { private final ConstructorMeta constructor; private final Map properties = new LinkedHashMap<>(); - public BeanMeta(RestToolKit toolKit, String prefix, Class type, boolean skipConstructor) { + public BeanMeta(RestToolKit toolKit, String prefix, Class type, boolean flatten) { this.type = type; - constructor = skipConstructor ? null : resolveConstructor(toolKit, null, type); - resolveProperties(toolKit, prefix, type); + constructor = resolveConstructor(toolKit, null, type); + resolveProperties(toolKit, prefix, type, flatten); } - public BeanMeta(RestToolKit toolKit, Class type, boolean skipConstructor) { - this(toolKit, null, type, skipConstructor); + public BeanMeta(RestToolKit toolKit, Class type, boolean flatten) { + this(toolKit, null, type, flatten); } public BeanMeta(RestToolKit toolKit, String prefix, Class type) { - this(toolKit, prefix, type, false); + this(toolKit, prefix, type, true); } public BeanMeta(RestToolKit toolKit, Class type) { - this(toolKit, null, type, false); + this(toolKit, null, type, true); } public Class getType() { @@ -77,6 +77,13 @@ public ConstructorMeta getConstructor() { return constructor; } + public ConstructorMeta getConstructorRequired() { + if (constructor == null) { + throw new IllegalArgumentException("No available default constructor found in " + type); + } + return constructor; + } + public Collection getProperties() { return properties.values(); } @@ -86,7 +93,7 @@ public PropertyMeta getProperty(String name) { } public Object newInstance() { - return constructor.newInstance(); + return getConstructorRequired().newInstance(); } public static ConstructorMeta resolveConstructor(RestToolKit toolKit, String prefix, Class type) { @@ -101,12 +108,12 @@ public static ConstructorMeta resolveConstructor(RestToolKit toolKit, String pre } } if (ct == null) { - throw new IllegalArgumentException("No available default constructor found in " + type); + return null; } return new ConstructorMeta(toolKit, prefix, ct); } - private void resolveProperties(RestToolKit toolKit, String prefix, Class type) { + private void resolveProperties(RestToolKit toolKit, String prefix, Class type, boolean flatten) { if (type == null || type == Object.class || TypeUtils.isSystemType(type)) { return; } @@ -185,7 +192,9 @@ private void resolveProperties(RestToolKit toolKit, String prefix, Class type properties.put(meta.getName(), meta); } - resolveProperties(toolKit, prefix, type.getSuperclass()); + if (flatten) { + resolveProperties(toolKit, prefix, type.getSuperclass(), flatten); + } } private static String toName(String name, int index) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java index 9e7fce0cae5..d61363d8ade 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java @@ -123,10 +123,18 @@ public Class getReturnType() { return method.getReturnType(); } + public Class getActualReturnType() { + return getReturnParameter().getActualType(); + } + public Type getGenericReturnType() { return method.getGenericReturnType(); } + public Type getActualGenericReturnType() { + return getReturnParameter().getActualGenericType(); + } + @Override protected List getAnnotatedElements() { return hierarchy; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java index e00d6cd2294..ddba602f93a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java @@ -112,6 +112,10 @@ public final Object bind(HttpRequest request, HttpResponse response) { return getToolKit().bind(this, request, response); } + public final ParamType getParamType() { + return getToolKit().getParamType(this); + } + public int getIndex() { return -1; } @@ -120,10 +124,6 @@ public String getDescription() { return name; } - public ParamType getParamType() { - return ParamType.Param; - } - public abstract Class getType(); public abstract Type getGenericType(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java index d6b8ea8b2ce..456a214ac92 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java @@ -104,6 +104,7 @@ private Map readConfigMap() { applyConfigValue(map, group, key, configuration.getString(fullKey)); } } + map.computeIfAbsent(Constants.GLOBAL_GROUP, k -> new OpenAPIConfig()); return map; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java index 2b4c2c2a5af..f7b0fe1cbb6 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java @@ -21,8 +21,13 @@ public final class Constants { public static final String VERSION_30 = "3.0.1"; public static final String VERSION_31 = "3.1.0"; + public static final String ALL_GROUP = "all"; public static final String DEFAULT_GROUP = "default"; public static final String GLOBAL_GROUP = ""; + public static final String X_JAVA_TYPE = "x-java-type"; + public static final String X_JAVA_METHOD = "x-java-method"; + public static final String X_JAVA_PARAM = "x-java-param"; + private Constants() {} } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index 906f2d98b09..2beaa34204b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -144,6 +144,7 @@ private List resolveOpenAPIs() { @Override public String getDocument(OpenAPIRequest request) { request = Helper.formatRequest(request); + HttpRequest httpRequest = RpcContext.getServiceContext().getRequest(HttpRequest.class); if (!RequestUtils.isRestRequest(httpRequest)) { return handleDocument(request); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index 4a66457993b..a2e4ea39a1c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -48,9 +48,6 @@ import java.util.Set; import java.util.TreeMap; -import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.formatVersion; -import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim; - final class DefinitionMerger { private static final FluentLogger LOG = FluentLogger.of(DefinitionMerger.class); @@ -62,28 +59,31 @@ final class DefinitionMerger { } public OpenAPI merge(List openAPIs, OpenAPIRequest request) { - OpenAPI model = new OpenAPI().setInfo(new Info()); + Info info = new Info(); + OpenAPI model = new OpenAPI().setInfo(info); if (openAPIs.isEmpty()) { applyConfig(model, configFactory.getGlobalConfig()); return model; } - String group = trim(request.getGroup()); + String group = request.getGroup(); + String version = request.getVersion(); + String[] tags = request.getTag(); + String[] services = request.getService(); + if (group == null) { group = Constants.DEFAULT_GROUP; } - String version = trim(request.getVersion()); if (version != null) { - model.setOpenapi(formatVersion(version)); + info.setVersion(version); } + model.setOpenapi(Helper.formatSpecVersion(request.getOpenapi())); applyConfig(model, configFactory.getConfig(group)); - String[] tags = request.getTag(); - String[] services = request.getService(); for (OpenAPI api : openAPIs) { - if (isServiceNotMatch(api.getService().getServiceInterface(), services)) { + if (isServiceNotMatch(api.getMeta().getServiceInterface(), services)) { continue; } @@ -91,7 +91,7 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { mergeBasic(model, api); } - mergePaths(model, api, group, tags); + mergePaths(model, api, group, version, tags); mergeSecuritySchemes(model, api); @@ -100,34 +100,18 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { applyConfig(model, configFactory.getGlobalConfig()); - addSchemas(model); + addSchemas(model, version, group); completeModel(model); return model; } - private static boolean isServiceNotMatch(String apiService, String[] services) { - if (apiService == null || services == null) { - return false; - } - for (String service : services) { - if (apiService.regionMatches(true, 0, service, 0, service.length())) { - return false; - } - } - return true; - } - private void applyConfig(OpenAPI api, OpenAPIConfig config) { if (config == null) { return; } - if (api.getOpenapi() == null) { - api.setOpenapi(formatVersion(config.getVersion())); - } - Info info = api.getInfo(); if (info.getTitle() == null) { info.setTitle(config.getInfoTitle()); @@ -135,6 +119,9 @@ private void applyConfig(OpenAPI api, OpenAPIConfig config) { if (info.getDescription() == null) { info.setDescription(config.getInfoDescription()); } + if (info.getVersion() == null) { + info.setVersion(config.getInfoVersion()); + } Contact contact = info.getContact(); if (contact == null) { @@ -192,10 +179,6 @@ private void applyConfig(OpenAPI api, OpenAPIConfig config) { } private void mergeBasic(OpenAPI api, OpenAPI from) { - if (api.getOpenapi() == null) { - api.setOpenapi(formatVersion(from.getOpenapi())); - } - mergeInfo(api, from); List fromServers = from.getServers(); @@ -287,7 +270,7 @@ private void mergeInfo(OpenAPI api, OpenAPI from) { info.addExtensions(fromInfo.getExtensions()); } - private void mergePaths(OpenAPI api, OpenAPI from, String group, String[] tags) { + private void mergePaths(OpenAPI api, OpenAPI from, String group, String version, String[] tags) { Map fromPaths = from.getPaths(); if (fromPaths == null) { return; @@ -311,11 +294,14 @@ private void mergePaths(OpenAPI api, OpenAPI from, String group, String[] tags) if (pathItem == null) { paths.put(path, pathItem = new PathItem()); } - mergePathItem(path, pathItem, fromPathItem, group, tags); + mergePath(path, pathItem, fromPathItem, group, version, tags); } } - private void mergePathItem(String path, PathItem pathItem, PathItem from, String group, String[] tags) { + private void mergePath(String path, PathItem pathItem, PathItem from, String group, String version, String[] tags) { + if (pathItem.getRef() == null) { + pathItem.setRef(from.getRef()); + } if (pathItem.getSummary() == null) { pathItem.setSummary(from.getSummary()); } @@ -333,23 +319,20 @@ private void mergePathItem(String path, PathItem pathItem, PathItem from, String HttpMethods httpMethod = entry.getKey(); Operation fromOperation = entry.getValue(); - if (!group.equals(fromOperation.getGroup())) { - continue; - } - - if (isTagNotMatch(tags, fromOperation.getTags())) { + if (isGroupNotMatch(group, fromOperation.getGroup()) + || isVersionNotMatch(version, fromOperation.getVersion()) + || isTagNotMatch(tags, fromOperation.getTags())) { continue; } Operation operation = operations.get(httpMethod); if (operation == null) { operations.put(httpMethod, fromOperation.clone()); - } else if (operation.getMethod() != null) { + } else if (operation.getMeta() != null) { LOG.internalWarn( "Operation already exists, path='{}', httpMethod='{}', method={}", path, - httpMethod, - fromOperation.getMethod()); + httpMethod, fromOperation.getMeta()); } } } @@ -376,6 +359,26 @@ private void mergePathItem(String path, PathItem pathItem, PathItem from, String pathItem.addExtensions(from.getExtensions()); } + private static boolean isServiceNotMatch(String apiService, String[] services) { + if (apiService == null || services == null) { + return false; + } + for (String service : services) { + if (apiService.regionMatches(true, 0, service, 0, service.length())) { + return false; + } + } + return true; + } + + private static boolean isGroupNotMatch(String group, String fromGroup) { + return !group.equals(Constants.ALL_GROUP) && !group.equals(fromGroup); + } + + private static boolean isVersionNotMatch(String version, String fromVersion) { + return version != null && fromVersion != null && !Helper.isVersionGreaterOrEqual(fromVersion, version); + } + private static boolean isTagNotMatch(String[] tags, Set operationTags) { if (tags == null || operationTags == null) { return false; @@ -429,7 +432,7 @@ private void mergeTags(OpenAPI api, OpenAPI from) { } } - private void addSchemas(OpenAPI api) { + private void addSchemas(OpenAPI api, String version, String group) { Components components = api.getComponents(); if (components == null) { api.setComponents(components = new Components()); @@ -448,13 +451,13 @@ private void addSchemas(OpenAPI api) { List parameters = operation.getParameters(); if (parameters != null) { for (Parameter parameter : parameters) { - addSchema(parameter.getSchema(), schemas); + addSchema(parameter.getSchema(), schemas, group, version); Map contents = parameter.getContents(); if (contents == null) { continue; } for (MediaType content : contents.values()) { - addSchema(content.getSchema(), schemas); + addSchema(content.getSchema(), schemas, group, version); } } } @@ -465,7 +468,7 @@ private void addSchemas(OpenAPI api) { continue; } for (MediaType content : contents.values()) { - addSchema(content.getSchema(), schemas); + addSchema(content.getSchema(), schemas, group, version); } } Map responses = operation.getResponses(); @@ -474,7 +477,7 @@ private void addSchemas(OpenAPI api) { Map headers = response.getHeaders(); if (headers != null) { for (Header header : headers.values()) { - addSchema(header.getSchema(), schemas); + addSchema(header.getSchema(), schemas, group, version); } } @@ -483,7 +486,7 @@ private void addSchemas(OpenAPI api) { continue; } for (MediaType content : contents.values()) { - addSchema(content.getSchema(), schemas); + addSchema(content.getSchema(), schemas, group, version); } } } @@ -491,21 +494,24 @@ private void addSchemas(OpenAPI api) { } } - private void addSchema(Schema schema, Map schemas) { + private void addSchema(Schema schema, Map schemas, String group, String version) { if (schema == null) { return; } - addSchema(schema.getItems(), schemas); + addSchema(schema.getItems(), schemas, group, version); Map properties = schema.getProperties(); if (properties != null) { for (Schema property : properties.values()) { - addSchema(property, schemas); + if (isGroupNotMatch(group, property.getGroup()) || isVersionNotMatch(version, property.getVersion())) { + continue; + } + addSchema(property, schemas, group, version); } } - addSchema(schema.getAdditionalPropertiesSchema(), schemas); + addSchema(schema.getAdditionalPropertiesSchema(), schemas, group, version); Schema targetSchema = schema.getTargetSchema(); if (targetSchema == null) { @@ -515,7 +521,7 @@ private void addSchema(Schema schema, Map schemas) { String name = targetSchema.getJavaType().getSimpleName(); schema.setRef("#/components/schemas/" + name); if (schemas.putIfAbsent(name, targetSchema) == null) { - addSchema(targetSchema, schemas); + addSchema(targetSchema, schemas, group, version); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index a6e9ce312b8..a342b01a348 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -83,7 +83,7 @@ public OpenAPI resolve(ServiceMeta serviceMeta, Collection> r } openAPI.setGlobalConfig(configFactory.getGlobalConfig()); openAPI.setConfig(configFactory.getConfig(openAPI.getGroup())); - openAPI.setService(serviceMeta); + openAPI.setMeta(serviceMeta); ResolveContext context = new ResolveContextImpl(openAPI, schemaFactory, extensionFactory); for (List registrations : registrationsByMethod) { @@ -102,7 +102,7 @@ public OpenAPI resolve(ServiceMeta serviceMeta, Collection> r path = ref; pathItem = openAPI.getOrAddPath(path); } - if (mainPath != null) { + if (mainPath != null && expression.isDirect()) { pathItem.setRef(mainPath); continue; } @@ -164,20 +164,25 @@ private boolean resolvePath( } pathItem.addOperation(httpMethod, operation); } else { - if (existingOperation.getMethod() != null) { + if (existingOperation.getMeta() != null) { LOG.internalWarn("Operation already exists, path='{}', httpMethod='{}', method={}", path, hm, meta); } continue; } - operation.setMethod(meta); - resolveOperation(httpMethod, operation, openAPI, meta, mapping); + operation.setMeta(meta); + resolveOperation(path, httpMethod, operation, openAPI, meta, mapping); } return true; } private void resolveOperation( - HttpMethods httpMethod, Operation operation, OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) { + String path, + HttpMethods httpMethod, + Operation operation, + OpenAPI openAPI, + MethodMeta meta, + RequestMapping mapping) { if (operation.getOperationId() == null) { String operationId = generateOperationId(meta, openAPI); operation.setOperationId(operationId == null ? meta.getMethod().getName() : operationId); @@ -189,6 +194,25 @@ private void resolveOperation( operation.setGroup(openAPI.getGroup()); } + for (int i = 0, len = path.length(), start = 0; i < len; i++) { + char c = path.charAt(i); + if (c == '{') { + start = i + 1; + } else if (start > 0 && c == '}') { + String name = path.substring(start, i); + Parameter parameter = operation.getParameter(name, In.PATH); + if (parameter == null) { + parameter = new Parameter(name, In.PATH); + operation.addParameter(parameter); + } + parameter.setRequired(true); + if (parameter.getSchema() == null) { + parameter.setSchema(PrimitiveSchema.STRING.newSchema()); + } + start = 0; + } + } + if (CollectionUtils.isEmpty(operation.getParameters())) { for (ParameterMeta paramMeta : meta.getParameters()) { String name = paramMeta.getName(); @@ -204,6 +228,7 @@ private void resolveOperation( parameter = new Parameter(name, in); operation.addParameter(parameter); } + parameter.setMeta(paramMeta); resolveParameter(parameter, paramMeta); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index ab488d05a1e..566a9ab3b78 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -19,15 +19,12 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.remoting.http12.rest.ParamType; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathSegment; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.List; import java.util.Map; import static org.apache.dubbo.remoting.http12.HttpMethods.DELETE; @@ -72,47 +69,6 @@ public final class Helper { private Helper() {} - public static String toPathValue(PathExpression expr) { - if (expr.isDirect()) { - return expr.getPath(); - } - StringBuilder sb = new StringBuilder(expr.getPath().length()); - int varIndex = 1; - for (PathSegment segment : expr.getSegments()) { - sb.append('/'); - switch (segment.getType()) { - case LITERAL: - sb.append(segment.getValue()); - break; - case WILDCARD_TAIL: - List variables = segment.getVariables(); - if (variables == null) { - sb.append("{path}"); - } else { - sb.append('{').append(variables.get(0)).append('}'); - } - break; - case VARIABLE: - sb.append('{'); - String value = segment.getValue(); - if (value.isEmpty()) { - sb.append("var").append(varIndex++); - } else { - sb.append(value); - } - sb.append('}'); - break; - case PATTERN: - case PATTERN_MULTI: - sb.append('{').append("var").append(varIndex++).append('}'); - break; - default: - break; - } - } - return sb.toString(); - } - public static Collection guessHttpMethod(MethodMeta method) { String name = method.getMethod().getName(); for (String[] verbs : VERBS_TABLE) { @@ -140,7 +96,7 @@ public static In toIn(ParamType paramType) { } } - public static String formatVersion(String version) { + public static String formatSpecVersion(String version) { if (version == null) { return null; } @@ -155,6 +111,7 @@ public static OpenAPIRequest formatRequest(OpenAPIRequest request) { return new OpenAPIRequest(); } request.setGroup(trim(request.getGroup())); + request.setVersion(trim(request.getVersion())); String[] tag = trim(request.getTag()); if (tag != null) { @@ -229,4 +186,54 @@ public static Map toProperties(String[] array) { } return properties; } + + public static String pathToRef(String path) { + StringBuilder sb = new StringBuilder(path.length() + 16); + sb.append("#/paths/"); + for (int i = 0, len = path.length(); i < len; i++) { + char c = path.charAt(i); + if (c == '/') { + sb.append('~').append('1'); + } else if (c == '~') { + sb.append('~').append('0'); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + public static boolean isVersionGreaterOrEqual(String version1, String version2) { + int i = 0, j = 0, len1 = version1.length(), len2 = version2.length(); + while (i < len1 || j < len2) { + int num1 = 0; + while (i < len1) { + char c = version1.charAt(i); + if (Character.isDigit(c)) { + num1 = num1 * 10 + (c - '0'); + } else if (c == '.' || c == '-' || c == '_') { + i++; + break; + } + i++; + } + + int num2 = 0; + while (j < len2) { + char c = version2.charAt(j); + if (Character.isDigit(c)) { + num2 = num2 * 10 + (c - '0'); + } else if (c == '.' || c == '-' || c == '_') { + j++; + break; + } + j++; + } + + if (num1 < num2) { + return false; + } + } + return true; + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java index c3662bba8db..c24fb05819f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java @@ -22,7 +22,7 @@ public interface OpenAPISchemaPredicate extends OpenAPIExtension { - boolean testClass(Class clazz, ParameterMeta parameter); + Boolean acceptClass(Class clazz, ParameterMeta parameter); - boolean testProperty(ParameterMeta parameter, BeanMeta bean, PropertyMeta property); + Boolean acceptProperty(ParameterMeta parameter, BeanMeta bean, PropertyMeta property); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java index ad51e5210af..371ee90c6a0 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java @@ -159,11 +159,16 @@ private Schema resolveClassSchema(Class clazz, ParameterMeta parameter) { } for (OpenAPISchemaPredicate predicate : predicates) { - if (predicate.testClass(clazz, parameter)) { + Boolean accepted = predicate.acceptClass(clazz, parameter); + if (accepted == null) { continue; } - schemaMap.put(clazz, Optional.empty()); - return OBJECT.newSchema(); + if (accepted) { + break; + } else { + schemaMap.put(clazz, Optional.empty()); + return OBJECT.newSchema(); + } } if (clazz.isEnum()) { @@ -180,17 +185,27 @@ private Schema resolveClassSchema(Class clazz, ParameterMeta parameter) { BeanMeta beanMeta = new BeanMeta(parameter.getToolKit(), clazz, true); out: for (PropertyMeta property : beanMeta.getProperties()) { + boolean fallback = true; for (OpenAPISchemaPredicate predicate : predicates) { - if (predicate.testProperty(parameter, beanMeta, property)) { + Boolean accepted = predicate.acceptProperty(parameter, beanMeta, property); + if (accepted == null) { continue; } - continue out; + if (accepted) { + fallback = false; + break; + } else { + continue out; + } } - int visibility = property.getVisibility(); - if (visibility > 1 && (visibility & 1) == 1) { - beanSchema.addProperty(property.getName(), getSchema(property)); + if (fallback) { + int visibility = property.getVisibility(); + if ((visibility & 0b001) == 0 || (visibility & 0b110) == 0) { + continue; + } } + beanSchema.addProperty(property.getName(), getSchema(property)); } return new Schema().setTargetSchema(beanSchema); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java index 584cee0212d..82126a44709 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java @@ -43,7 +43,7 @@ public final class OpenAPI extends Node { private transient OpenAPIConfig globalConfig; private transient OpenAPIConfig config; - private transient ServiceMeta service; + private transient ServiceMeta meta; public String getOpenapi() { return openapi; @@ -234,12 +234,16 @@ public T getConfigValue(Function fn) { return globalConfig == null ? null : fn.apply(globalConfig); } - public ServiceMeta getService() { - return service; + public String getConfigSetting(String key) { + return getConfigValue(config -> config == null ? null : config.getSetting(key)); } - public OpenAPI setService(ServiceMeta service) { - this.service = service; + public ServiceMeta getMeta() { + return meta; + } + + public OpenAPI setMeta(ServiceMeta meta) { + this.meta = meta; return this; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java index 25e3d64e6a7..ef5b1298ba5 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java @@ -18,6 +18,7 @@ import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; @@ -43,8 +44,9 @@ public final class Operation extends Node { private List servers; private String group; + private String version; private HttpMethods httpMethod; - private transient MethodMeta method; + private transient MethodMeta meta; public Set getTags() { return tags; @@ -253,6 +255,15 @@ public Operation setGroup(String group) { return this; } + public String getVersion() { + return version; + } + + public Operation setVersion(String version) { + this.version = version; + return this; + } + public HttpMethods getHttpMethod() { return httpMethod; } @@ -262,12 +273,12 @@ public Operation setHttpMethod(HttpMethods httpMethod) { return this; } - public MethodMeta getMethod() { - return method; + public MethodMeta getMeta() { + return meta; } - public Operation setMethod(MethodMeta method) { - this.method = method; + public Operation setMeta(MethodMeta meta) { + this.meta = meta; return this; } @@ -300,6 +311,8 @@ public Map writeTo(Map node, Context context) { write(node, "security", security, context); write(node, "servers", servers, context); writeExtensions(node); + write(node, Constants.X_JAVA_TYPE, meta.getServiceMeta().getServiceInterface()); + write(node, Constants.X_JAVA_METHOD, meta.getMethod().getName()); return node; } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java index 4e8ce6f5e2a..eaff4f0ca93 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java @@ -18,6 +18,7 @@ import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -156,7 +157,7 @@ public PathItem clone() { @Override public Map writeTo(Map node, Context context) { if (ref != null) { - write(node, "$ref", ref); + write(node, "$ref", Helper.pathToRef(ref)); } else if (operations != null) { write(node, "summary", summary); write(node, "description", description); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java index 25bbf010c78..0716c2b441e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java @@ -27,10 +27,10 @@ public final class Schema extends Node { public enum Type { + STRING("string"), INTEGER("integer"), NUMBER("number"), BOOLEAN("boolean"), - STRING("string"), OBJECT("object"), ARRAY("array"); @@ -44,6 +44,15 @@ public enum Type { public String toString() { return value; } + + public Type of(String value) { + for (Type type : values()) { + if (type.value.equals(value)) { + return type; + } + } + return STRING; + } } private String ref; @@ -65,7 +74,7 @@ public String toString() { private Boolean uniqueItems; private Integer maxProperties; private Integer minProperties; - private List required; + private Boolean required; private List enumeration; private Type type; private Schema items; @@ -85,6 +94,8 @@ public String toString() { private Boolean writeOnly; private Boolean deprecated; + private String group; + private String version; private transient Schema targetSchema; private transient Class javaType; @@ -259,30 +270,15 @@ public Schema setMinProperties(Integer minProperties) { return this; } - public List getRequired() { + public Boolean getRequired() { return required; } - public Schema setRequired(List required) { + public Schema setRequired(Boolean required) { this.required = required; return this; } - public Schema addRequired(String required) { - if (this.required == null) { - this.required = new ArrayList<>(); - } - this.required.add(required); - return this; - } - - public Schema removeRequired(String required) { - if (this.required != null) { - this.required.remove(required); - } - return this; - } - public List getEnumeration() { return enumeration; } @@ -506,6 +502,24 @@ public Schema setDeprecated(Boolean deprecated) { return this; } + public String getGroup() { + return group; + } + + public Schema setGroup(String group) { + this.group = group; + return this; + } + + public String getVersion() { + return version; + } + + public Schema setVersion(String version) { + this.version = version; + return this; + } + public Schema getTargetSchema() { return targetSchema; } @@ -527,9 +541,6 @@ public Schema setJavaType(Class javaType) { @Override public Schema clone() { Schema clone = super.clone(); - if (required != null) { - clone.required = new ArrayList<>(required); - } if (enumeration != null) { clone.enumeration = new ArrayList<>(enumeration); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java index 8942f6984a9..3dc74da8f3c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/Annotations.java @@ -25,6 +25,7 @@ public enum Annotations implements AnnotationEnum { Param, OpenAPI, Operation, + Schema, Nonnull("javax.annotation.Nonnull"); private final String className; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java index a444cfd5831..e78f18cac7a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java @@ -19,11 +19,14 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaPredicate; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ResolveContext; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs; @@ -31,21 +34,26 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Map; +import java.util.function.Consumer; import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim; @Activate(order = 100) -public final class BasicOpenAPIDefinitionResolver implements OpenAPIDefinitionResolver, OpenAPISchemaResolver { +public final class BasicOpenAPIDefinitionResolver + implements OpenAPIDefinitionResolver, OpenAPISchemaResolver, OpenAPISchemaPredicate { + + private static final String HIDDEN = "hidden"; @Override public boolean hidden(ServiceMeta serviceMeta) { AnnotationMeta openAPI = serviceMeta.findAnnotation(Annotations.OpenAPI); - return openAPI != null && openAPI.getBoolean("hidden"); + return openAPI != null && openAPI.getBoolean(HIDDEN); } @Override @@ -56,7 +64,6 @@ public OpenAPI resolve(ServiceMeta serviceMeta) { } OpenAPI model = new OpenAPI(); - model.setOpenapi(trim(openAPI.getString("version"))); Map tags = Helper.toProperties(openAPI.getStringArray("tags")); for (Map.Entry entry : tags.entrySet()) { model.addTag(new Tag().setName(entry.getKey()).setDescription(entry.getValue())); @@ -85,7 +92,7 @@ public OpenAPI resolve(ServiceMeta serviceMeta) { @Override public boolean hidden(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { AnnotationMeta operation = methodMeta.findAnnotation(Annotations.Operation); - return operation != null && operation.getBoolean("hidden"); + return operation != null && operation.getBoolean(HIDDEN); } @Override @@ -107,8 +114,10 @@ public Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext } model.setGroup(trim(operation.getString("group"))); - model.setOperationId(trim(operation.getString("operationId"))); - model.setSummary(trim(operation.getString("summary"))); + model.setVersion(trim(operation.getString("version"))); + model.setOperationId(trim(operation.getString("id"))); + String summary = trim(operation.getValue()); + model.setSummary(summary == null ? trim(operation.getString("summary")) : summary); model.setDescription(trim(operation.getString("description"))); model.setDeprecated(operation.getBoolean("deprecated")); model.setExtensions(Helper.toProperties(operation.getStringArray("extensions"))); @@ -117,6 +126,57 @@ public Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext @Override public Schema resolve(ParameterMeta parameter, Context context, Chain chain) { - return chain.resolve(parameter, context); + AnnotationMeta schema = parameter.getAnnotation(Annotations.Schema); + if (schema == null) { + return chain.resolve(parameter, context); + } + + Class impl = schema.getClass("implementation"); + Schema model = impl == null ? chain.resolve(parameter, context) : context.getSchema(impl); + + setValue(schema, "group", model::setGroup); + setValue(schema, "version", model::setVersion); + setValue(schema, "type", v -> model.setType(Type.valueOf(v))); + setValue(schema, "format", model::setFormat); + setValue(schema, "name", model::setName); + String title = trim(schema.getValue()); + model.setTitle(title == null ? trim(schema.getString("title")) : title); + setValue(schema, "title", model::setTitle); + setValue(schema, "description", model::setDescription); + setValue(schema, "max", v -> model.setMaxLength(Integer.parseInt(v))); + setValue(schema, "min", v -> model.setMinLength(Integer.parseInt(v))); + setValue(schema, "pattern", model::setPattern); + setValue(schema, "example", model::setExample); + String[] enumItems = trim(schema.getStringArray("enumeration")); + if (enumItems != null) { + model.setEnumeration(Arrays.asList(enumItems)); + } + model.setRequired(schema.getBoolean("required")); + setValue(schema, "defaultValue", model::setDefaultValue); + model.setReadOnly(schema.getBoolean("readOnly")); + model.setWriteOnly(schema.getBoolean("writeOnly")); + model.setNullable(schema.getBoolean("nullable")); + model.setDeprecated(schema.getBoolean("deprecated")); + model.setExtensions(Helper.toProperties(schema.getStringArray("extensions"))); + return model; + } + + private static void setValue(AnnotationMeta schema, String key, Consumer setter) { + String value = trim(schema.getString(key)); + if (value != null) { + setter.accept(value); + } + } + + @Override + public Boolean acceptClass(Class clazz, ParameterMeta parameter) { + AnnotationMeta schema = parameter.getAnnotation(Annotations.Schema); + return schema == null ? null : schema.getBoolean(HIDDEN); + } + + @Override + public Boolean acceptProperty(ParameterMeta parameter, BeanMeta bean, PropertyMeta property) { + AnnotationMeta schema = parameter.getAnnotation(Annotations.Schema); + return schema == null ? null : schema.getBoolean(HIDDEN); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java index 8aac208d8bf..9b8b9f8073f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java @@ -18,8 +18,11 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.Param; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.AbstractRestToolKit; @@ -41,4 +44,10 @@ public int getDialect() { public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response) { return binder.bind(parameter, request, response); } + + @Override + public ParamType getParamType(ParameterMeta parameter) { + AnnotationMeta mapping = parameter.findAnnotation(Param.class); + return mapping == null ? null : mapping.getAnnotation().type(); + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java index 332b214c85e..3642fcefbf9 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java @@ -60,7 +60,7 @@ public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse re return null; } - ConstructorMeta constructor = beanMeta.getConstructor(); + ConstructorMeta constructor = beanMeta.getConstructorRequired(); ParameterMeta[] parameters = constructor.getParameters(); Object bean; int len = parameters.length; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java index 2ed7c511fbd..892af79076e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java @@ -18,6 +18,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import javax.annotation.Nullable; @@ -37,6 +38,8 @@ public interface RestToolKit { Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response); + ParamType getParamType(ParameterMeta parameter); + @Nullable String[] getParameterNames(Method method); From 737c4224c2acbd49e90ff3f5847fb6b9cb761e59 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Thu, 21 Nov 2024 15:28:33 +0800 Subject: [PATCH 07/23] Schema inherit support --- .../dubbo/common/utils/StringUtils.java | 50 ++++++++++++++++ .../dubbo/config/nested/OpenAPIConfig.java | 14 +++++ .../dubbo/springboot/demo/servlet/Animal.java | 24 ++++++++ .../dubbo/springboot/demo/servlet/Cat.java | 14 +++++ .../dubbo/springboot/demo/servlet/Dog.java | 14 +++++ .../demo/servlet/GreeterService.java | 2 + .../demo/servlet/GreeterServiceImpl.java | 5 ++ .../dubbo/springboot/demo/servlet/Live.java | 23 ++++++++ .../src/main/resources/application.yml | 6 +- .../dubbo/metadata/MetadataService.java | 4 +- .../dubbo/metadata/MetadataServiceV2.java | 2 +- .../support/spring/SpringRestToolKit.java | 15 +++++ .../dubbo/remoting/http12/rest/OpenAPI.java | 2 +- .../dubbo/remoting/http12/rest/Operation.java | 2 +- .../tri/rest/mapping/meta/AnnotationMeta.java | 9 +++ .../tri/rest/mapping/meta/BeanMeta.java | 40 +++++++++++-- .../tri/rest/openapi/ConfigFactory.java | 4 +- .../rest/openapi/DefaultOpenAPIService.java | 6 ++ .../tri/rest/openapi/DefinitionMerger.java | 32 +++++++++- .../tri/rest/openapi/DefinitionResolver.java | 6 +- .../rpc/protocol/tri/rest/openapi/Helper.java | 3 + .../rest/openapi/OpenAPISchemaPredicate.java | 2 +- .../tri/rest/openapi/SchemaFactory.java | 41 +++++++++++-- .../tri/rest/openapi/model/Schema.java | 4 ++ .../basic/BasicOpenAPIDefinitionResolver.java | 4 +- .../tri/rest/util/AbstractRestToolKit.java | 9 +++ .../protocol/tri/rest/util/RestToolKit.java | 4 ++ .../rpc/protocol/tri/rest/util/TypeUtils.java | 58 +++++++++++++++++++ 28 files changed, 371 insertions(+), 28 deletions(-) create mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java create mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java create mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java create mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java index 74786e8a2e1..1c3f156873c 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java @@ -1362,4 +1362,54 @@ public static List tokenizeToList(String str, char... separators) { } return tokens; } + + public static Boolean toBoolean(String value) { + if (isEmpty(value)) { + return null; + } + switch (value.length()) { + case 1: + char c = value.charAt(0); + if (c == '0' || c == 'n' || c == 'N') { + return Boolean.FALSE; + } + if (c == '1' || c == 'y' || c == 'Y') { + return Boolean.TRUE; + } + break; + case 2: + if ("on".equalsIgnoreCase(value)) { + return Boolean.TRUE; + } + if ("no".equalsIgnoreCase(value)) { + return Boolean.FALSE; + } + break; + case 3: + if ("yes".equalsIgnoreCase(value)) { + return Boolean.TRUE; + } + if ("off".equalsIgnoreCase(value)) { + return Boolean.TRUE; + } + break; + case 4: + if ("true".equalsIgnoreCase(value)) { + return Boolean.TRUE; + } + break; + case 5: + if ("false".equalsIgnoreCase(value)) { + return Boolean.FALSE; + } + break; + default: + } + return null; + } + + public static boolean toBoolean(String value, boolean defaultValue) { + Boolean result = toBoolean(value); + return result == null ? defaultValue : result; + } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java index 9796772cf7e..875c2e72f03 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -29,6 +29,12 @@ public class OpenAPIConfig implements Serializable { */ private Boolean enabled; + /** + * Whether to cache the OpenAPI document. + *

The default value is 'true'. + */ + private Boolean cache; + /** * The HTTP path where OpenAPI will be registered. *

The default value is '/dubbo/openapi'. @@ -134,6 +140,14 @@ public void setEnabled(Boolean enabled) { this.enabled = enabled; } + public Boolean getCache() { + return cache; + } + + public void setCache(Boolean cache) { + this.cache = cache; + } + public String getPath() { return path; } diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java new file mode 100644 index 00000000000..09c6b963787 --- /dev/null +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java @@ -0,0 +1,24 @@ +package org.apache.dubbo.springboot.demo.servlet; + +public class Animal extends Live { + + private String name; + + private int age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } +} diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java new file mode 100644 index 00000000000..fab53ae9347 --- /dev/null +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java @@ -0,0 +1,14 @@ +package org.apache.dubbo.springboot.demo.servlet; + +public class Cat extends Animal { + + private int length; + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } +} diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java new file mode 100644 index 00000000000..d1711e0fa38 --- /dev/null +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java @@ -0,0 +1,14 @@ +package org.apache.dubbo.springboot.demo.servlet; + +public class Dog extends Animal { + + private String color; + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } +} diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java index e777429e71d..1e26ff7e62d 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java @@ -41,4 +41,6 @@ public interface GreeterService { * Sends greetings with bi streaming */ StreamObserver sayHelloBiStream(StreamObserver responseObserver); + + Animal createAnimal(Cat cat, Dog dog); } diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterServiceImpl.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterServiceImpl.java index ef699dd69d7..8340b7a9a3d 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterServiceImpl.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterServiceImpl.java @@ -74,6 +74,11 @@ public void onCompleted() { }; } + @Override + public Animal createAnimal(Cat cat, Dog dog) { + return cat; + } + private static HelloReply toReply(String message) { HelloReply reply = new HelloReply(); reply.setMessage(message); diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java new file mode 100644 index 00000000000..06736a55f6a --- /dev/null +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java @@ -0,0 +1,23 @@ +package org.apache.dubbo.springboot.demo.servlet; + +public class Live { + + private boolean alive; + private byte[] raw; + + public boolean isAlive() { + return alive; + } + + public void setAlive(boolean alive) { + this.alive = alive; + } + + public byte[] getRaw() { + return raw; + } + + public void setRaw(byte[] raw) { + this.raw = raw; + } +} diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml index f9628d83414..99c61ebab17 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml @@ -24,8 +24,12 @@ dubbo: qos-enable: false protocol: name: tri - port: ${server.port} + port: 8082 triple: + rest: + openapi: + cache: false + schema-flatten: true servlet: enabled: true registry: diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java index 859523c7e6e..f50ce92e2ff 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java @@ -40,7 +40,7 @@ * 1. The Consumer queries the metadata information of the Provider to list the interfaces and each interface's configuration * 2. The Console (dubbo-admin) queries for the metadata of a specific process, or aggregate data of all processes. */ -@OpenAPI(hidden = false) +@OpenAPI(hidden = "false") public interface MetadataService { /** @@ -235,6 +235,6 @@ static boolean isMetadataService(String interfaceName) { /** * 1. Get the openAPI definition */ - @Mapping({"getOpenAPI", "//${" + H2_SETTINGS_OPENAPI_PREFIX + ".path:dubbo/openapi}/{*path}"}) + @Mapping(path = {"getOpenAPI", "//${" + H2_SETTINGS_OPENAPI_PREFIX + ".path:dubbo/openapi}/{*path}"}) String getOpenAPI(OpenAPIRequest request); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java index 79ad7e1cc4b..fd3f69479a0 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java @@ -20,7 +20,7 @@ import java.util.concurrent.CompletableFuture; -@OpenAPI(hidden = true) +@OpenAPI(hidden = "true") public interface MetadataServiceV2 extends org.apache.dubbo.rpc.model.DubboStub { String JAVA_SERVICE_NAME = "org.apache.dubbo.metadata.MetadataServiceV2"; diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java index 79254589a1a..da43b925069 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java @@ -24,6 +24,7 @@ import org.apache.dubbo.config.spring.extension.SpringExtensionInjector; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; @@ -36,8 +37,11 @@ import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestUtils; +import javax.annotation.Nullable; + import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Collection; import java.util.Map; @@ -149,11 +153,22 @@ public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse re return argumentBinder.bind(parameter, request, response); } + @Override + public ParamType getParamType(ParameterMeta parameter) { + return null; + } + @Override public String[] getParameterNames(Method method) { return parameterNameReader.readParameterNames(method); } + @Nullable + @Override + public String[] getParameterNames(Constructor ctor) { + return parameterNameReader.readParameterNames(ctor); + } + @Override public Map getAttributes(AnnotatedElement element, Annotation annotation) { return AnnotatedElementUtils.getMergedAnnotationAttributes(element, annotation.annotationType()); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java index c149203edc4..364684bbd49 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPI.java @@ -82,7 +82,7 @@ /** * Indicates whether the mapping is hidden in OpenAPI. */ - boolean hidden() default false; + String hidden() default ""; /** * Ordering info. diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java index 204b34e010a..d1cd645ceb8 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Operation.java @@ -86,7 +86,7 @@ /** * Indicates whether the operation is hidden in OpenAPI. */ - boolean hidden() default false; + String hidden() default ""; /** * The extensions of the OpenAPI. diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationMeta.java index 8919222c911..e1505ec5631 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationMeta.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta; import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; import java.lang.annotation.Annotation; @@ -174,6 +175,14 @@ attributeName, getAnnotationType().getName(), value), if (expectedType == String.class) { return (T) value.toString(); } + if (expectedType == Boolean.class) { + Boolean b = StringUtils.toBoolean(value.toString()); + return (T) (b == null ? Boolean.FALSE : b); + } + if (expectedType == Number.class) { + String str = value.toString(); + return str.indexOf('.') > -1 ? (T) Double.valueOf(str) : (T) Long.valueOf(str); + } if (expectedType.isArray()) { Class expectedComponentType = expectedType.getComponentType(); if (expectedComponentType.isInstance(value)) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java index 3ce72403e3f..4f287e82bf7 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java @@ -43,7 +43,7 @@ import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Message; -public final class BeanMeta { +public final class BeanMeta extends ParameterMeta { private static final boolean HAS_PB = ClassUtils.hasProtobuf(); @@ -52,6 +52,7 @@ public final class BeanMeta { private final Map properties = new LinkedHashMap<>(); public BeanMeta(RestToolKit toolKit, String prefix, Class type, boolean flatten) { + super(toolKit, prefix, null); this.type = type; constructor = resolveConstructor(toolKit, null, type); resolveProperties(toolKit, prefix, type, flatten); @@ -69,10 +70,21 @@ public BeanMeta(RestToolKit toolKit, Class type) { this(toolKit, null, type, true); } + @Override public Class getType() { return type; } + @Override + public Type getGenericType() { + return type; + } + + @Override + protected AnnotatedElement getAnnotatedElement() { + return type; + } + public ConstructorMeta getConstructor() { return constructor; } @@ -193,7 +205,7 @@ private void resolveProperties(RestToolKit toolKit, String prefix, Class type } if (flatten) { - resolveProperties(toolKit, prefix, type.getSuperclass(), flatten); + resolveProperties(toolKit, prefix, type.getSuperclass(), true); } } @@ -218,9 +230,11 @@ public ConstructorParameterMeta[] getParameters() { private ConstructorParameterMeta[] initParameters(RestToolKit toolKit, String prefix, Constructor ct) { Parameter[] cps = ct.getParameters(); int len = cps.length; + String[] parameterNames = toolKit == null ? null : toolKit.getParameterNames(ct); ConstructorParameterMeta[] parameters = new ConstructorParameterMeta[len]; for (int i = 0; i < len; i++) { - parameters[i] = new ConstructorParameterMeta(toolKit, cps[i], prefix); + String parameterName = parameterNames == null ? null : parameterNames[i]; + parameters[i] = new ConstructorParameterMeta(toolKit, cps[i], prefix, parameterName); } return parameters; } @@ -238,8 +252,8 @@ public static final class ConstructorParameterMeta extends ParameterMeta { private final Parameter parameter; - ConstructorParameterMeta(RestToolKit toolKit, Parameter parameter, String prefix) { - super(toolKit, prefix, parameter.isNamePresent() ? parameter.getName() : null); + ConstructorParameterMeta(RestToolKit toolKit, Parameter parameter, String prefix, String name) { + super(toolKit, prefix, name == null && parameter.isNamePresent() ? parameter.getName() : name); this.parameter = parameter; } @@ -341,6 +355,22 @@ public int getVisibility() { return visibility; } + public Field getField() { + return field; + } + + public Method getGetMethod() { + return getMethod; + } + + public Method getSetMethod() { + return setMethod; + } + + public Parameter getParameter() { + return parameter; + } + @Override public Class getType() { if (field != null) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java index 456a214ac92..c864bc3f003 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java @@ -56,7 +56,7 @@ public OpenAPIConfig getConfig(String group) { } public OpenAPIConfig getGlobalConfig() { - return getConfig(Constants.GLOBAL_GROUP); + return getConfigMap().get(Constants.GLOBAL_GROUP); } private Map getConfigMap() { @@ -93,7 +93,7 @@ private Map readConfigMap() { String group, key; if (c == '.') { group = StringUtils.EMPTY_STRING; - key = fullKey.substring(len + 2); + key = fullKey.substring(len + 1); } else if (c == 's') { int end = fullKey.indexOf('.', len + 1); group = fullKey.substring(len + 1, end); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index 2beaa34204b..5e43339c75b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -59,6 +59,7 @@ public class DefaultOpenAPIService implements OpenAPIRequestHandler, OpenAPIServ private final LRUCache> cache = new LRUCache<>(64); private final FrameworkModel frameworkModel; + private final ConfigFactory configFactory; private final ExtensionFactory extensionFactory; private final DefinitionResolver definitionResolver; private final DefinitionMerger definitionMerger; @@ -73,6 +74,7 @@ public class DefaultOpenAPIService implements OpenAPIRequestHandler, OpenAPIServ public DefaultOpenAPIService(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); definitionResolver = new DefinitionResolver(frameworkModel); definitionMerger = new DefinitionMerger(frameworkModel); @@ -169,6 +171,10 @@ public String getDocument(OpenAPIRequest request) { } private String handleDocument(OpenAPIRequest request) { + if (Boolean.FALSE.equals(configFactory.getGlobalConfig().getCache())) { + return definitionEncoder.encode(getOpenAPI(request), request); + } + String cacheKey = request.toString(); SoftReference ref = cache.get(cacheKey); if (ref != null) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index a2e4ea39a1c..2cfadccc7d7 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -332,7 +332,8 @@ private void mergePath(String path, PathItem pathItem, PathItem from, String gro LOG.internalWarn( "Operation already exists, path='{}', httpMethod='{}', method={}", path, - httpMethod, fromOperation.getMeta()); + httpMethod, + fromOperation.getMeta()); } } } @@ -372,11 +373,13 @@ private static boolean isServiceNotMatch(String apiService, String[] services) { } private static boolean isGroupNotMatch(String group, String fromGroup) { - return !group.equals(Constants.ALL_GROUP) && !group.equals(fromGroup); + return !(fromGroup == null && Constants.DEFAULT_GROUP.equals(group) + || Constants.ALL_GROUP.equals(group) + || group.equals(fromGroup)); } private static boolean isVersionNotMatch(String version, String fromVersion) { - return version != null && fromVersion != null && !Helper.isVersionGreaterOrEqual(fromVersion, version); + return !(version == null || fromVersion == null || Helper.isVersionGreaterOrEqual(fromVersion, version)); } private static boolean isTagNotMatch(String[] tags, Set operationTags) { @@ -513,6 +516,29 @@ private void addSchema(Schema schema, Map schemas, String group, addSchema(schema.getAdditionalPropertiesSchema(), schemas, group, version); + List allOf = schema.getAllOf(); + if (allOf != null) { + for (Schema item : allOf) { + addSchema(item, schemas, group, version); + } + } + + List oneOf = schema.getOneOf(); + if (oneOf != null) { + for (Schema item : oneOf) { + addSchema(item, schemas, group, version); + } + } + + List anyOf = schema.getAnyOf(); + if (anyOf != null) { + for (Schema item : anyOf) { + addSchema(item, schemas, group, version); + } + } + + addSchema(schema.getNot(), schemas, group, version); + Schema targetSchema = schema.getTargetSchema(); if (targetSchema == null) { return; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index a342b01a348..cf365406373 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -190,9 +190,6 @@ private void resolveOperation( if (operation.getDeprecated() == null && meta.isHierarchyAnnotated(Deprecated.class)) { operation.setDeprecated(true); } - if (operation.getGroup() == null) { - operation.setGroup(openAPI.getGroup()); - } for (int i = 0, len = path.length(), start = 0; i < len; i++) { char c = path.charAt(i); @@ -306,6 +303,9 @@ private void resolveResponse( if (httpStatus > 201 && httpStatus < 400) { return; } + if (meta.getActualReturnType() == void.class) { + return; + } Collection mediaTypes = null; if (mapping.getProducesCondition() != null) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index 566a9ab3b78..59ad4708552 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -82,6 +82,9 @@ public static Collection guessHttpMethod(MethodMeta method) { } public static In toIn(ParamType paramType) { + if (paramType == null) { + return In.QUERY; + } switch (paramType) { case PathVariable: return In.PATH; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java index c24fb05819f..d9130b15b39 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java @@ -24,5 +24,5 @@ public interface OpenAPISchemaPredicate extends OpenAPIExtension { Boolean acceptClass(Class clazz, ParameterMeta parameter); - Boolean acceptProperty(ParameterMeta parameter, BeanMeta bean, PropertyMeta property); + Boolean acceptProperty(BeanMeta bean, PropertyMeta property); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java index 371ee90c6a0..0f5424e913d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; @@ -25,6 +26,8 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.Chain; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.Context; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.support.basic.Annotations; +import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; import java.lang.reflect.GenericArrayType; @@ -41,12 +44,14 @@ public final class SchemaFactory { + private final ConfigFactory configFactory; private final OpenAPISchemaResolver[] resolvers; private final OpenAPISchemaPredicate[] predicates; private final Map, Optional> schemaMap = CollectionUtils.newConcurrentHashMap(); private final Map, String> nameMap = CollectionUtils.newConcurrentHashMap(); public SchemaFactory(FrameworkModel frameworkModel) { + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); ExtensionFactory extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); resolvers = extensionFactory.getExtensions(OpenAPISchemaResolver.class); predicates = extensionFactory.getExtensions(OpenAPISchemaPredicate.class); @@ -118,8 +123,12 @@ private Schema resolveSchema(Type type, ParameterMeta parameter) { } if (Map.class.isAssignableFrom(clazz)) { - Schema nestedSchema = resolveNestedSchema(argTypes[1], parameter); - return OBJECT.newSchema().setAdditionalPropertiesSchema(nestedSchema); + Schema schema = OBJECT.newSchema(); + Type keyType = argTypes[0]; + if (String.class != keyType) { + schema.addExtension(Constants.X_JAVA_TYPE, TypeUtils.toTypeString(keyType)); + } + return schema.setAdditionalPropertiesSchema(resolveNestedSchema(argTypes[1], parameter)); } return resolveClassSchema(clazz, parameter); @@ -158,8 +167,9 @@ private Schema resolveClassSchema(Class clazz, ParameterMeta parameter) { return OBJECT.newSchema(); } + TypeParameterMeta typeParameter = new TypeParameterMeta(clazz); for (OpenAPISchemaPredicate predicate : predicates) { - Boolean accepted = predicate.acceptClass(clazz, parameter); + Boolean accepted = predicate.acceptClass(clazz, typeParameter); if (accepted == null) { continue; } @@ -180,14 +190,24 @@ private Schema resolveClassSchema(Class clazz, ParameterMeta parameter) { return schema.clone(); } + Boolean flatten = configFactory.getGlobalConfig().getSchemaFlatten(); + if (flatten == null) { + AnnotationMeta anno = typeParameter.getAnnotation(Annotations.Schema); + flatten = anno != null && anno.getBoolean("flatten"); + } + + return new Schema().setTargetSchema(resolveBeanSchema(parameter.getToolKit(), clazz, flatten)); + } + + private Schema resolveBeanSchema(RestToolKit toolKit, Class clazz, boolean flatten) { Schema beanSchema = OBJECT.newSchema().setJavaType(clazz); schemaMap.put(clazz, Optional.of(beanSchema)); - BeanMeta beanMeta = new BeanMeta(parameter.getToolKit(), clazz, true); + BeanMeta beanMeta = new BeanMeta(toolKit, clazz, flatten); out: for (PropertyMeta property : beanMeta.getProperties()) { boolean fallback = true; for (OpenAPISchemaPredicate predicate : predicates) { - Boolean accepted = predicate.acceptProperty(parameter, beanMeta, property); + Boolean accepted = predicate.acceptProperty(beanMeta, property); if (accepted == null) { continue; } @@ -207,7 +227,16 @@ private Schema resolveClassSchema(Class clazz, ParameterMeta parameter) { } beanSchema.addProperty(property.getName(), getSchema(property)); } - return new Schema().setTargetSchema(beanSchema); + + if (flatten) { + return beanSchema; + } + Class superClass = clazz.getSuperclass(); + if (superClass == null || superClass == Object.class || TypeUtils.isSystemType(superClass)) { + return beanSchema; + } + + return beanSchema.addAllOf(getSchema(superClass)); } private Schema resolveNestedSchema(Type nestedType, ParameterMeta parameter) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java index 0716c2b441e..165aaa9b5b4 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import java.math.BigDecimal; @@ -606,6 +607,9 @@ public Map writeTo(Map schema, Context context) write(schema, "writeOnly", writeOnly); write(schema, "deprecated", deprecated); writeExtensions(schema); + if (javaType != null) { + schema.put(Constants.X_JAVA_TYPE, javaType.getName()); + } return schema; } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java index e78f18cac7a..63c34ff287a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java @@ -175,8 +175,8 @@ public Boolean acceptClass(Class clazz, ParameterMeta parameter) { } @Override - public Boolean acceptProperty(ParameterMeta parameter, BeanMeta bean, PropertyMeta property) { - AnnotationMeta schema = parameter.getAnnotation(Annotations.Schema); + public Boolean acceptProperty(BeanMeta bean, PropertyMeta property) { + AnnotationMeta schema = property.getAnnotation(Annotations.Schema); return schema == null ? null : schema.getBoolean(HIDDEN); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java index d92c27aa30a..92e84ec5c8a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java @@ -26,8 +26,11 @@ import org.apache.dubbo.rpc.protocol.tri.rest.argument.TypeConverter; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import javax.annotation.Nullable; + import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Map; @@ -71,6 +74,12 @@ public String[] getParameterNames(Method method) { return parameterNameReader.readParameterNames(method); } + @Nullable + @Override + public String[] getParameterNames(Constructor ctor) { + return parameterNameReader.readParameterNames(ctor); + } + @Override public Map getAttributes(AnnotatedElement element, Annotation annotation) { return AnnotationUtils.getAttributes(annotation, false); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java index 892af79076e..9cc09c17a8b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java @@ -25,6 +25,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Map; @@ -43,5 +44,8 @@ public interface RestToolKit { @Nullable String[] getParameterNames(Method method); + @Nullable + String[] getParameterNames(Constructor ctor); + Map getAttributes(AnnotatedElement element, Annotation annotation); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java index ae089ff964d..203ee7e4ec1 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java @@ -396,4 +396,62 @@ public static String buildSig(Method method) { } return sb.toString(); } + + public static String toTypeString(Type type) { + if (type instanceof Class) { + return ((Class) type).getName(); + } + StringBuilder result = new StringBuilder(32); + buildGenericTypeString(type, result); + return result.toString(); + } + + private static void buildGenericTypeString(Type type, StringBuilder sb) { + if (type instanceof Class) { + sb.append(((Class) type).getName()); + } else if (type instanceof ParameterizedType) { + ParameterizedType pzType = (ParameterizedType) type; + Type[] typeArgs = pzType.getActualTypeArguments(); + buildGenericTypeString(pzType.getRawType(), sb); + sb.append('<'); + for (int i = 0, len = typeArgs.length; i < len; i++) { + if (i > 0) { + sb.append(", "); + } + buildGenericTypeString(typeArgs[i], sb); + } + sb.append('>'); + } else if (type instanceof WildcardType) { + WildcardType wildcardType = (WildcardType) type; + Type[] upperBounds = wildcardType.getUpperBounds(); + Type[] lowerBounds = wildcardType.getLowerBounds(); + if (lowerBounds.length > 0) { + sb.append("? super "); + buildGenericTypeString(lowerBounds[0], sb); + } else if (upperBounds.length > 0 && upperBounds[0] != Object.class) { + sb.append("? extends "); + buildGenericTypeString(upperBounds[0], sb); + } else { + sb.append('?'); + } + } else if (type instanceof GenericArrayType) { + GenericArrayType genericArrayType = (GenericArrayType) type; + buildGenericTypeString(genericArrayType.getGenericComponentType(), sb); + sb.append("[]"); + } else if (type instanceof TypeVariable) { + TypeVariable typeVariable = (TypeVariable) type; + sb.append(typeVariable.getName()); + Type[] bounds = typeVariable.getBounds(); + int len = bounds.length; + if (len > 0 && !(len == 1 && bounds[0] == Object.class)) { + sb.append(" extends "); + for (int i = 0; i < len; i++) { + if (i > 0) {sb.append(" & ");} + buildGenericTypeString(bounds[i], sb); + } + } + } else { + sb.append(type.toString()); + } + } } From d774cabe52e74485b7fdf3824d33a1f5b4f5f1d4 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Thu, 21 Nov 2024 18:04:54 +0800 Subject: [PATCH 08/23] Operation parameter impl --- .../support/jaxrs/BeanArgumentBinder.java | 7 +- .../jaxrs/BeanParamArgumentResolver.java | 6 + .../support/jaxrs/BodyArgumentResolver.java | 7 ++ .../jaxrs/CookieParamArgumentResolver.java | 6 + .../jaxrs/FallbackArgumentResolver.java | 7 +- .../support/jaxrs/FormArgumentResolver.java | 8 ++ .../jaxrs/FormParamArgumentResolver.java | 8 +- .../jaxrs/HeaderParamArgumentResolver.java | 6 + .../rest/support/jaxrs/JaxrsRestToolKit.java | 8 +- .../jaxrs/MatrixParamArgumentResolver.java | 6 + .../jaxrs/PathParamArgumentResolver.java | 9 ++ .../jaxrs/QueryParamArgumentResolver.java | 6 + .../support/spring/BeanArgumentBinder.java | 14 ++- .../spring/BindParamArgumentResolver.java | 6 + .../spring/CookieValueArgumentResolver.java | 6 + .../spring/FallbackArgumentResolver.java | 2 +- .../MatrixVariableArgumentResolver.java | 6 + .../ModelAttributeArgumentResolver.java | 16 ++- .../spring/PathVariableArgumentResolver.java | 7 ++ .../RequestAttributeArgumentResolver.java | 6 + .../spring/RequestBodyArgumentResolver.java | 10 +- .../spring/RequestHeaderArgumentResolver.java | 6 + .../spring/RequestParamArgumentResolver.java | 6 + .../spring/RequestPartArgumentResolver.java | 6 + .../spring/SpringResponseRestFilter.java | 6 +- .../support/spring/SpringRestToolKit.java | 11 +- .../remoting/http12/rest/OpenAPIRequest.java | 2 + .../dubbo/remoting/http12/rest/ParamType.java | 1 + ...bstractAnnotationBaseArgumentResolver.java | 9 +- .../argument/AbstractArgumentResolver.java | 8 +- .../AnnotationBaseArgumentResolver.java | 3 + .../argument/CompositeArgumentResolver.java | 26 +++- .../NamedValueArgumentResolverSupport.java | 19 ++- .../tri/rest/mapping/meta/BeanMeta.java | 42 ++++--- .../tri/rest/mapping/meta/NamedValueMeta.java | 29 ++++- .../tri/rest/mapping/meta/ParameterMeta.java | 23 +++- .../tri/rest/openapi/DefinitionResolver.java | 113 +++++++++++++----- .../rpc/protocol/tri/rest/openapi/Helper.java | 2 +- .../tri/rest/openapi/SchemaFactory.java | 7 +- .../basic/BasicOpenAPIDefinitionResolver.java | 19 ++- .../rest/support/basic/BasicRestToolKit.java | 11 +- .../support/basic/BeanArgumentBinder.java | 9 +- .../basic/FallbackArgumentResolver.java | 10 +- .../support/basic/ParamArgumentResolver.java | 28 ++--- .../tri/rest/util/AbstractRestToolKit.java | 9 ++ .../protocol/tri/rest/util/RestToolKit.java | 4 +- .../rpc/protocol/tri/rest/util/TypeUtils.java | 4 +- 47 files changed, 415 insertions(+), 155 deletions(-) diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java index 7ff3ccd7d10..25e97ce620a 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java @@ -20,7 +20,6 @@ import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; -import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver; @@ -43,8 +42,8 @@ final class BeanArgumentBinder { private final Map, String>, BeanMeta> cache = CollectionUtils.newConcurrentHashMap(); private final ArgumentResolver argumentResolver; - BeanArgumentBinder(FrameworkModel frameworkModel) { - argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); + BeanArgumentBinder(CompositeArgumentResolver argumentResolver) { + this.argumentResolver = argumentResolver; } public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) { @@ -77,7 +76,7 @@ private Object resolveArgument(ParameterMeta paramMeta, HttpRequest request, Htt Pair.of(paramMeta.getActualType(), prefix), k -> new BeanMeta(paramMeta.getToolKit(), k.getValue(), k.getKey())); - ConstructorMeta constructor = beanMeta.getConstructorRequired(); + ConstructorMeta constructor = beanMeta.getConstructor(); ParameterMeta[] parameters = constructor.getParameters(); Object bean; int len = parameters.length; diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanParamArgumentResolver.java index 7c59ec6d592..a47a023222e 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanParamArgumentResolver.java @@ -21,6 +21,7 @@ import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import java.lang.annotation.Annotation; @@ -33,6 +34,11 @@ public Class accept() { return Annotations.BeanParam.type(); } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return null; + } + @Override public Object resolve( ParameterMeta parameter, diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java index fc3640aa10d..31bccf43f19 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java @@ -20,9 +20,11 @@ import org.apache.dubbo.common.io.StreamUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -37,6 +39,11 @@ public Class accept() { return Annotations.Body.type(); } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return new NamedValueMeta(null, false, ParamType.Body); + } + @Override public Object resolve( ParameterMeta parameter, diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/CookieParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/CookieParamArgumentResolver.java index 7f1b37b25a1..43fea3a89a9 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/CookieParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/CookieParamArgumentResolver.java @@ -21,6 +21,7 @@ import org.apache.dubbo.remoting.http12.HttpCookie; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -38,6 +39,11 @@ public Class accept() { return Annotations.CookieParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Cookie; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.cookie(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java index 07076ba08fa..e508510d483 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.io.StreamUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractArgumentResolver; @@ -40,7 +41,9 @@ public boolean accept(ParameterMeta param) { @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param) { - return new NamedValueMeta(param.isAnnotated(Annotations.Nonnull), Helper.defaultValue(param)); + NamedValueMeta meta = new NamedValueMeta(param.isAnnotated(Annotations.Nonnull), Helper.defaultValue(param)); + meta.setParamType(param.isSimple() ? null : ParamType.Body); + return meta; } @Override @@ -49,7 +52,7 @@ protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResp if (value != null) { return value; } - if (meta.parameterMeta().isSimple()) { + if (meta.parameter().isSimple()) { return request.parameter(meta.name()); } return null; diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java index 4f3678be5fa..7c698243073 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java @@ -19,19 +19,27 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import java.lang.annotation.Annotation; @Activate(onClass = "org.jboss.resteasy.annotations.Form") public class FormArgumentResolver implements AnnotationBaseArgumentResolver { + @Override public Class accept() { return Annotations.Form.type(); } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return new NamedValueMeta(null, false, ParamType.Form); + } + @Override public Object resolve( ParameterMeta parameter, diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormParamArgumentResolver.java index 7ac1b2fcda0..88e972aa3d7 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormParamArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -35,6 +36,11 @@ public Class accept() { return Annotations.FormParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Form; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return CollectionUtils.first(request.formParameterValues(getFullName(meta))); @@ -46,7 +52,7 @@ protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request } private String getFullName(NamedValueMeta meta) { - String prefix = meta.parameterMeta().getPrefix(); + String prefix = meta.parameter().getPrefix(); return prefix == null ? meta.name() : prefix + '.' + meta.name(); } } diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/HeaderParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/HeaderParamArgumentResolver.java index 63a71b94353..7b406705a0f 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/HeaderParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/HeaderParamArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -31,6 +32,11 @@ public Class accept() { return Annotations.HeaderParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Header; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.header(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java index 270a4fde908..65e82cfdcb6 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java @@ -18,7 +18,6 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; -import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; @@ -33,7 +32,7 @@ final class JaxrsRestToolKit extends AbstractRestToolKit { public JaxrsRestToolKit(FrameworkModel frameworkModel) { super(frameworkModel); - binder = new BeanArgumentBinder(frameworkModel); + binder = new BeanArgumentBinder(argumentResolver); paramConverterFactory = new ParamConverterFactory(); } @@ -57,9 +56,4 @@ public Object convert(Object value, ParameterMeta parameter) { public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response) { return binder.bind(parameter, request, response); } - - @Override - public ParamType getParamType(ParameterMeta parameter) { - return null; - } } diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/MatrixParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/MatrixParamArgumentResolver.java index a3f6b99bea2..e6517f6bda0 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/MatrixParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/MatrixParamArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -36,6 +37,11 @@ public Class accept() { return Annotations.MatrixParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.MatrixVariable; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return CollectionUtils.first(doResolveCollectionValue(meta, request)); diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java index 8e1fe007208..f87df32f8ff 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java @@ -20,11 +20,13 @@ import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestParameterException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -34,11 +36,18 @@ @Activate(onClass = "javax.ws.rs.PathParam") public class PathParamArgumentResolver implements AnnotationBaseArgumentResolver { + private NamedValueMeta namedValueMeta; + @Override public Class accept() { return Annotations.PathParam.type(); } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return new NamedValueMeta(annotation.getValue(), true, ParamType.PathVariable); + } + @Override public Object resolve( ParameterMeta parameter, diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/QueryParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/QueryParamArgumentResolver.java index 9b156c7da0a..67be793aadb 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/QueryParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/QueryParamArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -32,6 +33,11 @@ public Class accept() { return Annotations.QueryParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Param; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.parameter(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java index 7d340980755..c918e568436 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java @@ -20,7 +20,6 @@ import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; -import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver; @@ -48,8 +47,8 @@ final class BeanArgumentBinder { private final ArgumentResolver argumentResolver; private final ConversionService conversionService; - BeanArgumentBinder(FrameworkModel frameworkModel, ConversionService conversionService) { - argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); + BeanArgumentBinder(CompositeArgumentResolver argumentResolver, ConversionService conversionService) { + this.argumentResolver = argumentResolver; this.conversionService = conversionService; } @@ -75,7 +74,14 @@ private Object createBean(ParameterMeta paramMeta, HttpRequest request, HttpResp if (Modifier.isAbstract(type.getModifiers())) { throw new IllegalStateException(Messages.ARGUMENT_COULD_NOT_RESOLVED.format(paramMeta.getDescription())); } - ConstructorMeta ct = CACHE.computeIfAbsent(type, k -> resolveConstructor(paramMeta.getToolKit(), null, type)); + ConstructorMeta ct = CACHE.computeIfAbsent(type, k -> { + ConstructorMeta meta = resolveConstructor(paramMeta.getToolKit(), null, type); + if (meta == null) { + throw new IllegalStateException( + Messages.ARGUMENT_COULD_NOT_RESOLVED.format(paramMeta.getDescription())); + } + return meta; + }); ParameterMeta[] parameters = ct.getParameters(); int len = parameters.length; if (len == 0) { diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java index a4906b7aec4..f14b83637b6 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AbstractAnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; @@ -35,6 +36,11 @@ public Class accept() { return Annotations.BindParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Param; + } + @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { return new NamedValueMeta(ann.getValue(), param.isAnnotated(Annotations.Nonnull), null); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/CookieValueArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/CookieValueArgumentResolver.java index 0e3767efff4..83bb983ac07 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/CookieValueArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/CookieValueArgumentResolver.java @@ -21,6 +21,7 @@ import org.apache.dubbo.remoting.http12.HttpCookie; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -38,6 +39,11 @@ public Class accept() { return Annotations.CookieValue.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Cookie; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.cookie(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java index 79e1121650b..e43adcf7bc2 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java @@ -41,7 +41,7 @@ protected NamedValueMeta createNamedValueMeta(ParameterMeta param) { @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - ParameterMeta parameter = meta.parameterMeta(); + ParameterMeta parameter = meta.parameter(); if (parameter.isSimple()) { return request.parameter(meta.name()); } diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java index f68ff9cacf1..3e4541504fe 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; @@ -41,6 +42,11 @@ public Class accept() { return Annotations.MatrixVariable.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.MatrixVariable; + } + @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { return new MatrixNamedValueMeta( diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/ModelAttributeArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/ModelAttributeArgumentResolver.java index 89b2581dd3e..56ce0f798f0 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/ModelAttributeArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/ModelAttributeArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; @@ -33,20 +34,25 @@ public Class accept() { return Annotations.ModelAttribute.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Param; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - if (meta.parameterMeta().isSimple()) { + if (meta.parameter().isSimple()) { return request.parameter(meta.name()); } - return meta.parameterMeta().bind(request, response); + return meta.parameter().bind(request, response); } @Override protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - if (meta.parameterMeta().isSimple()) { + if (meta.parameter().isSimple()) { return request.parameterValues(meta.name()); } - return meta.parameterMeta().bind(request, response); + return meta.parameter().bind(request, response); } @Override @@ -54,6 +60,6 @@ protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpR if (TypeUtils.isSimpleProperty(meta.nestedType(1))) { return RequestUtils.getParametersMap(request); } - return meta.parameterMeta().bind(request, response); + return meta.parameter().bind(request, response); } } diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java index a1c389f54f4..eb5cac678af 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java @@ -20,11 +20,13 @@ import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestParameterException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -39,6 +41,11 @@ public Class accept() { return Annotations.PathVariable.type(); } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return new NamedValueMeta(annotation.getValue(), true, ParamType.PathVariable); + } + @Override public Object resolve( ParameterMeta parameter, diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestAttributeArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestAttributeArgumentResolver.java index 7e61abcf442..d0523aa865f 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestAttributeArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestAttributeArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -31,6 +32,11 @@ public Class accept() { return Annotations.RequestAttribute.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Attribute; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.attribute(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java index dcf3173f358..3fda32b1862 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.io.StreamUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; @@ -37,6 +38,11 @@ public Class accept() { return Annotations.RequestBody.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Body; + } + @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { return new NamedValueMeta(Helper.isRequired(ann), null); @@ -45,10 +51,10 @@ protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMet @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { if (RequestUtils.isFormOrMultiPart(request)) { - if (meta.parameterMeta().isSimple()) { + if (meta.parameter().isSimple()) { return request.formParameter(meta.name()); } - return meta.parameterMeta().bind(request, response); + return meta.parameter().bind(request, response); } return RequestUtils.decodeBody(request, meta.genericType()); } diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestHeaderArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestHeaderArgumentResolver.java index acf7e40723e..c93ae084c9a 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestHeaderArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestHeaderArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import java.lang.annotation.Annotation; @@ -31,6 +32,11 @@ public Class accept() { return Annotations.RequestHeader.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Header; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.header(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestParamArgumentResolver.java index 56a1b1577f4..21889890e8b 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestParamArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -32,6 +33,11 @@ public Class accept() { return Annotations.RequestParam.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Param; + } + @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { return request.parameter(meta.name()); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java index 7d17d3bb472..4d9eefbcfe6 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java @@ -20,6 +20,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpRequest.FileUpload; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; @@ -38,6 +39,11 @@ public Class accept() { return Annotations.RequestPart.type(); } + @Override + protected ParamType getParamType(NamedValueMeta meta) { + return ParamType.Part; + } + @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { return new NamedValueMeta(ann.getValue(), Helper.isRequired(ann), null); diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java index a354093f3f1..2d71997ad15 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java @@ -114,11 +114,11 @@ private Optional findSuitableExceptionHandler(ServiceMeta serviceMet } List, MethodMeta>> candidates = new ArrayList<>(); for (MethodMeta methodMeta : serviceMeta.getExceptionHandlers()) { - ExceptionHandler anno = methodMeta.getMethod().getAnnotation(ExceptionHandler.class); - if (anno == null) { + ExceptionHandler ann = methodMeta.getMethod().getAnnotation(ExceptionHandler.class); + if (ann == null) { continue; } - for (Class type : anno.value()) { + for (Class type : ann.value()) { if (type.isAssignableFrom(exType)) { candidates.add(Pair.of(type, methodMeta)); } diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java index da43b925069..e544ba083f4 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java @@ -24,15 +24,16 @@ import org.apache.dubbo.config.spring.extension.SpringExtensionInjector; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; -import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; +import org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.argument.GeneralTypeConverter; import org.apache.dubbo.rpc.protocol.tri.rest.argument.TypeConverter; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestUtils; @@ -68,6 +69,7 @@ final class SpringRestToolKit implements RestToolKit { private final TypeConverter typeConverter; private final BeanArgumentBinder argumentBinder; private final ParameterNameReader parameterNameReader; + private final CompositeArgumentResolver argumentResolver; public SpringRestToolKit(FrameworkModel frameworkModel) { ApplicationModel applicationModel = frameworkModel.defaultApplication(); @@ -89,7 +91,8 @@ public SpringRestToolKit(FrameworkModel frameworkModel) { } typeConverter = frameworkModel.getOrRegisterBean(GeneralTypeConverter.class); parameterNameReader = frameworkModel.getOrRegisterBean(DefaultParameterNameReader.class); - argumentBinder = new BeanArgumentBinder(frameworkModel, conversionService); + argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); + argumentBinder = new BeanArgumentBinder(argumentResolver, conversionService); } @Override @@ -154,8 +157,8 @@ public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse re } @Override - public ParamType getParamType(ParameterMeta parameter) { - return null; + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter) { + return argumentResolver.getNamedValueMeta(parameter); } @Override diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java index 4e127a68e0b..5a3b2d8bd67 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIRequest.java @@ -53,12 +53,14 @@ public class OpenAPIRequest implements Serializable { * e.g. 3.0.1, 3.1.0 *

The default value is '3.0.1'. */ + @Schema(enumeration = {"3.0.1", "3.1.0"}) private String openapi; /** * The format of the response. *

The default value is 'json'. */ + @Schema(enumeration = {"json", "yaml", "proto"}) private String format; /** diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/ParamType.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/ParamType.java index fac5b864c45..4c1fa73533a 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/ParamType.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/ParamType.java @@ -20,6 +20,7 @@ public enum ParamType { PathVariable, MatrixVariable, Param, + Form, Header, Cookie, Attribute, diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java index 9b9143e0a70..74564d22e57 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java @@ -33,9 +33,12 @@ public Object resolve( AnnotationMeta annotation, HttpRequest request, HttpResponse response) { - NamedValueMeta namedValue = - cache.computeIfAbsent(parameter, k -> updateNamedValueMeta(k, createNamedValueMeta(k, annotation))); - return resolve(namedValue, request, response); + return resolve(getNamedValueMeta(parameter, annotation), request, response); + } + + @Override + public final NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return cache.computeIfAbsent(parameter, k -> updateNamedValueMeta(k, createNamedValueMeta(k, annotation))); } protected abstract NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractArgumentResolver.java index 6675f1e5809..7064d5df4b5 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractArgumentResolver.java @@ -25,9 +25,11 @@ public abstract class AbstractArgumentResolver extends NamedValueArgumentResolve @Override public Object resolve(ParameterMeta parameter, HttpRequest request, HttpResponse response) { - NamedValueMeta namedValue = - cache.computeIfAbsent(parameter, k -> updateNamedValueMeta(k, createNamedValueMeta(k))); - return resolve(namedValue, request, response); + return resolve(getNamedValueMeta(parameter), request, response); + } + + public final NamedValueMeta getNamedValueMeta(ParameterMeta parameter) { + return cache.computeIfAbsent(parameter, k -> updateNamedValueMeta(k, createNamedValueMeta(k))); } protected abstract NamedValueMeta createNamedValueMeta(ParameterMeta parameter); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AnnotationBaseArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AnnotationBaseArgumentResolver.java index 30b7a12205d..060b97c7cd7 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AnnotationBaseArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AnnotationBaseArgumentResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import java.lang.annotation.Annotation; @@ -27,6 +28,8 @@ public interface AnnotationBaseArgumentResolver extends Ar Class accept(); + NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation); + Object resolve(ParameterMeta parameter, AnnotationMeta annotation, HttpRequest request, HttpResponse response); default boolean accept(ParameterMeta parameter) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java index 69c50585bc6..ffc859b4e30 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java @@ -21,6 +21,7 @@ import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import java.util.ArrayList; @@ -50,6 +51,10 @@ public CompositeArgumentResolver(FrameworkModel frameworkModel) { argumentConverter = new CompositeArgumentConverter(frameworkModel); } + public ArgumentConverter getArgumentConverter() { + return argumentConverter; + } + @Override public boolean accept(ParameterMeta parameter) { return true; @@ -57,14 +62,14 @@ public boolean accept(ParameterMeta parameter) { @Override public Object resolve(ParameterMeta parameter, HttpRequest request, HttpResponse response) { - AnnotationMeta[] annotations = parameter.findAnnotations(); - for (AnnotationMeta annotation : annotations) { + for (AnnotationMeta annotation : parameter.findAnnotations()) { AnnotationBaseArgumentResolver resolver = resolverMap.get(annotation.getAnnotationType()); if (resolver != null) { Object value = resolver.resolve(parameter, annotation, request, response); return argumentConverter.convert(value, parameter); } } + for (ArgumentResolver resolver : resolvers) { if (resolver.accept(parameter)) { Object value = resolver.resolve(parameter, request, response); @@ -75,7 +80,20 @@ public Object resolve(ParameterMeta parameter, HttpRequest request, HttpResponse throw new IllegalStateException(Messages.ARGUMENT_COULD_NOT_RESOLVED.format(parameter.getDescription())); } - public ArgumentConverter getArgumentConverter() { - return argumentConverter; + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter) { + for (AnnotationMeta annotation : parameter.findAnnotations()) { + AnnotationBaseArgumentResolver resolver = resolverMap.get(annotation.getAnnotationType()); + if (resolver != null) { + return resolver.getNamedValueMeta(parameter, annotation); + } + } + + for (ArgumentResolver resolver : resolvers) { + if (resolver.accept(parameter) && resolver instanceof AbstractArgumentResolver) { + return ((AbstractArgumentResolver) resolver).getNamedValueMeta(parameter); + } + } + + return null; } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java index f69402fd9e8..2b914708d69 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestParameterException; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; @@ -56,23 +57,29 @@ protected final Object resolve(NamedValueMeta meta, HttpRequest request, HttpRes return null; } - protected final NamedValueMeta updateNamedValueMeta(ParameterMeta parameterMeta, NamedValueMeta meta) { + protected final NamedValueMeta updateNamedValueMeta(ParameterMeta parameter, NamedValueMeta meta) { if (meta.isNameEmpty()) { - meta.setName(parameterMeta.getName()); + meta.setName(parameter.getName()); } - - Class type = parameterMeta.getActualType(); + if (meta.paramType() == null) { + meta.setParamType(getParamType(meta)); + } + Class type = parameter.getActualType(); meta.setType(type); - meta.setGenericType(parameterMeta.getActualGenericType()); + meta.setGenericType(parameter.getActualGenericType()); if (type.isArray()) { meta.setNestedTypes(new Class[] {type}); } else { meta.setNestedTypes(TypeUtils.getNestedActualTypes(meta.genericType())); } - meta.setParameterMeta(parameterMeta); + meta.setParameterMeta(parameter); return meta; } + protected ParamType getParamType(NamedValueMeta meta) { + return null; + } + protected String emptyDefaultValue(NamedValueMeta meta) { return meta.defaultValue(); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java index 4f287e82bf7..fb308562ff9 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta; import org.apache.dubbo.common.utils.ClassUtils; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.rest.Param; import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; @@ -33,6 +34,7 @@ import java.lang.reflect.Parameter; import java.lang.reflect.Type; import java.util.Collection; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; @@ -48,14 +50,14 @@ public final class BeanMeta extends ParameterMeta { private static final boolean HAS_PB = ClassUtils.hasProtobuf(); private final Class type; - private final ConstructorMeta constructor; - private final Map properties = new LinkedHashMap<>(); + private final boolean flatten; + private ConstructorMeta constructor; + private Map propertyMap; public BeanMeta(RestToolKit toolKit, String prefix, Class type, boolean flatten) { super(toolKit, prefix, null); this.type = type; - constructor = resolveConstructor(toolKit, null, type); - resolveProperties(toolKit, prefix, type, flatten); + this.flatten = flatten; } public BeanMeta(RestToolKit toolKit, Class type, boolean flatten) { @@ -86,26 +88,29 @@ protected AnnotatedElement getAnnotatedElement() { } public ConstructorMeta getConstructor() { - return constructor; - } - - public ConstructorMeta getConstructorRequired() { if (constructor == null) { - throw new IllegalArgumentException("No available default constructor found in " + type); + constructor = resolveConstructor(getToolKit(), getPrefix(), type); } return constructor; } public Collection getProperties() { - return properties.values(); + return getPropertiesMap().values(); } public PropertyMeta getProperty(String name) { - return properties.get(name); + return getPropertiesMap().get(name); + } + + private Map getPropertiesMap() { + if (propertyMap == null) { + propertyMap = resolvePropertyMap(getToolKit(), getPrefix(), type, flatten); + } + return propertyMap; } public Object newInstance() { - return getConstructorRequired().newInstance(); + return getConstructor().newInstance(); } public static ConstructorMeta resolveConstructor(RestToolKit toolKit, String prefix, Class type) { @@ -120,14 +125,15 @@ public static ConstructorMeta resolveConstructor(RestToolKit toolKit, String pre } } if (ct == null) { - return null; + throw new IllegalArgumentException("No available default constructor found in " + type); } return new ConstructorMeta(toolKit, prefix, ct); } - private void resolveProperties(RestToolKit toolKit, String prefix, Class type, boolean flatten) { + public static Map resolvePropertyMap( + RestToolKit toolKit, String prefix, Class type, boolean flatten) { if (type == null || type == Object.class || TypeUtils.isSystemType(type)) { - return; + return Collections.emptyMap(); } Set pbFields = null; @@ -193,6 +199,8 @@ private void resolveProperties(RestToolKit toolKit, String prefix, Class type } } } + + Map properties = CollectionUtils.newLinkedHashMap(allNames.size()); for (String name : allNames) { Field field = fieldMap.get(name); Method getMethod = getMethodMap.get(name); @@ -205,8 +213,10 @@ private void resolveProperties(RestToolKit toolKit, String prefix, Class type } if (flatten) { - resolveProperties(toolKit, prefix, type.getSuperclass(), true); + resolvePropertyMap(toolKit, prefix, type.getSuperclass(), flatten); } + + return properties; } private static String toName(String name, int index) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java index 69a1af9bb98..1e93684ebdd 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; @@ -25,13 +26,23 @@ public class NamedValueMeta { + public static final NamedValueMeta EMPTY = new NamedValueMeta(false, null); + private String name; private final boolean required; private final String defaultValue; + private ParamType paramType; private Class type; private Type genericType; private Class[] nestedTypes; - private ParameterMeta parameterMeta; + private ParameterMeta parameter; + + public NamedValueMeta(String name, boolean required, ParamType paramType) { + this.name = name; + this.required = required; + this.defaultValue = null; + this.paramType = paramType; + } public NamedValueMeta(String name, boolean required, String defaultValue) { this.name = name; @@ -68,6 +79,14 @@ public String defaultValue() { return defaultValue; } + public ParamType paramType() { + return paramType; + } + + public void setParamType(ParamType paramType) { + this.paramType = paramType; + } + public Class type() { return type; } @@ -100,12 +119,12 @@ public void setNestedTypes(Class[] nestedTypes) { this.nestedTypes = nestedTypes; } - public ParameterMeta parameterMeta() { - return parameterMeta; + public ParameterMeta parameter() { + return parameter; } - public void setParameterMeta(ParameterMeta parameterMeta) { - this.parameterMeta = parameterMeta; + public void setParameterMeta(ParameterMeta parameter) { + this.parameter = parameter; } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java index ddba602f93a..d9a46ef2966 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ParameterMeta.java @@ -18,7 +18,6 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; -import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; @@ -36,6 +35,8 @@ public abstract class ParameterMeta extends AnnotationSupport { private Boolean simple; private Class actualType; private Type actualGenericType; + private BeanMeta beanMeta; + private NamedValueMeta namedValueMeta; protected ParameterMeta(RestToolKit toolKit, String prefix, String name) { super(toolKit); @@ -108,12 +109,28 @@ public final Type getActualGenericType() { return type; } + public final BeanMeta getBeanMeta() { + BeanMeta beanMeta = this.beanMeta; + if (beanMeta == null) { + this.beanMeta = beanMeta = new BeanMeta(getToolKit(), getActualType()); + } + return beanMeta; + } + public final Object bind(HttpRequest request, HttpResponse response) { return getToolKit().bind(this, request, response); } - public final ParamType getParamType() { - return getToolKit().getParamType(this); + public final NamedValueMeta getNamedValueMeta() { + NamedValueMeta namedValueMeta = this.namedValueMeta; + if (namedValueMeta == null) { + namedValueMeta = getToolKit().getNamedValueMeta(this); + if (namedValueMeta == null) { + namedValueMeta = NamedValueMeta.EMPTY; + } + this.namedValueMeta = namedValueMeta; + } + return namedValueMeta; } public int getIndex() { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index cf365406373..ccb2bd8c197 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -24,12 +24,16 @@ import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.remoting.http12.HttpUtils; import org.apache.dubbo.remoting.http12.message.MediaType; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.Registration; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathCondition; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; @@ -39,7 +43,9 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -184,8 +190,7 @@ private void resolveOperation( MethodMeta meta, RequestMapping mapping) { if (operation.getOperationId() == null) { - String operationId = generateOperationId(meta, openAPI); - operation.setOperationId(operationId == null ? meta.getMethod().getName() : operationId); + operation.setOperationId(meta.getMethod().getName()); } if (operation.getDeprecated() == null && meta.isHierarchyAnnotated(Deprecated.class)) { operation.setDeprecated(true); @@ -210,24 +215,8 @@ private void resolveOperation( } } - if (CollectionUtils.isEmpty(operation.getParameters())) { - for (ParameterMeta paramMeta : meta.getParameters()) { - String name = paramMeta.getName(); - if (name == null) { - continue; - } - In in = Helper.toIn(paramMeta.getParamType()); - if (in == null) { - continue; - } - Parameter parameter = operation.getParameter(name, in); - if (parameter == null) { - parameter = new Parameter(name, in); - operation.addParameter(parameter); - } - parameter.setMeta(paramMeta); - resolveParameter(parameter, paramMeta); - } + for (ParameterMeta paramMeta : meta.getParameters()) { + resolveParameter(operation, paramMeta, true); } if (httpMethod.supportBody()) { @@ -253,22 +242,57 @@ private void resolveOperation( } } - private String generateOperationId(MethodMeta meta, OpenAPI openAPI) { - String name = openAPI.getConfigValue(OpenAPIConfig::getOperationIdStrategy); + private void resolveParameter(Operation operation, ParameterMeta paramMeta, boolean traverse) { + String name = paramMeta.getName(); if (name == null) { - return null; + return; } - OpenAPINamingStrategy strategy = - extensionFactory.getExtension(OpenAPINamingStrategy.class, OpenAPINamingStrategy.PREFIX + name); - if (strategy == null) { - return null; + + NamedValueMeta valueMeta = paramMeta.getNamedValueMeta(); + In in = Helper.toIn(valueMeta.paramType()); + if (in == null) { + return; + } + + boolean simple = paramMeta.isSimple(); + if (in != In.QUERY && !simple) { + return; + } + if (simple) { + Parameter parameter = operation.getParameter(name, in); + if (parameter == null) { + parameter = new Parameter(name, in); + operation.addParameter(parameter); + } + if (parameter.getRequired() == null) { + parameter.setRequired(valueMeta.required()); + } + Schema schema = parameter.getSchema(); + if (schema == null) { + parameter.setSchema(schema = schemaFactory.getSchema(paramMeta)); + } + if (schema.getDefaultValue() == null) { + schema.setDefaultValue(valueMeta.defaultValue()); + } + parameter.setMeta(paramMeta); + return; + } + if (!traverse) { + return; } - return strategy.generateOperationId(meta, openAPI); - } - private void resolveParameter(Parameter parameter, ParameterMeta meta) { - if (parameter.getSchema() == null) { - parameter.setSchema(schemaFactory.getSchema(meta)); + BeanMeta beanMeta = paramMeta.getBeanMeta(); + try { + for (ParameterMeta ctorParam : beanMeta.getConstructor().getParameters()) { + resolveParameter(operation, ctorParam, false); + } + } catch (Throwable ignored) { + } + for (PropertyMeta property : beanMeta.getProperties()) { + if ((property.getVisibility() & 0b001) == 0) { + continue; + } + resolveParameter(operation, property, false); } } @@ -285,11 +309,34 @@ private void resolveRequestBody(RequestBody body, OpenAPI openAPI, MethodMeta me mediaTypes = Arrays.stream(defaultMediaTypes).map(MediaType::of).collect(Collectors.toList()); } } + out: for (MediaType mediaType : mediaTypes) { org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.MediaType content = body.getOrAddContent(mediaType.getName()); if (content.getSchema() == null) { - content.setSchema(schemaFactory.getSchema(meta.getParameters())); + for (ParameterMeta paramMeta : meta.getParameters()) { + ParamType paramType = paramMeta.getNamedValueMeta().paramType(); + if (paramType == ParamType.Body) { + content.setSchema(schemaFactory.getSchema(paramMeta)); + continue out; + } + } + + List paramMetas = new ArrayList<>(); + for (ParameterMeta paramMeta : meta.getParameters()) { + if (paramMeta.getNamedValueMeta().paramType() == null) { + paramMetas.add(paramMeta); + } + } + int size = paramMetas.size(); + if (size == 0) { + continue; + } + if (size == 1) { + content.setSchema(schemaFactory.getSchema(paramMetas.get(0))); + } else { + content.setSchema(schemaFactory.getSchema(paramMetas)); + } } } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index 59ad4708552..75d0b4d2db7 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -166,7 +166,7 @@ public static String[] trim(String[] array) { array[p++] = value; } } - int newLen = p + 1; + int newLen = p; return newLen == len ? array : Arrays.copyOf(array, newLen); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java index 0f5424e913d..42fc2db92fc 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java @@ -35,6 +35,7 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; @@ -95,7 +96,7 @@ public Schema getSchema(Type type) { }); } - public Schema getSchema(ParameterMeta[] parameters) { + public Schema getSchema(List parameters) { Schema schema = OBJECT.newSchema(); for (ParameterMeta parameter : parameters) { String name = parameter.getName(); @@ -192,8 +193,8 @@ private Schema resolveClassSchema(Class clazz, ParameterMeta parameter) { Boolean flatten = configFactory.getGlobalConfig().getSchemaFlatten(); if (flatten == null) { - AnnotationMeta anno = typeParameter.getAnnotation(Annotations.Schema); - flatten = anno != null && anno.getBoolean("flatten"); + AnnotationMeta ann = typeParameter.getAnnotation(Annotations.Schema); + flatten = ann != null && ann.getBoolean("flatten"); } return new Schema().setTargetSchema(resolveBeanSchema(parameter.getToolKit(), clazz, flatten)); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java index 63c34ff287a..33d925a6e9d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java @@ -132,7 +132,7 @@ public Schema resolve(ParameterMeta parameter, Context context, Chain chain) { } Class impl = schema.getClass("implementation"); - Schema model = impl == null ? chain.resolve(parameter, context) : context.getSchema(impl); + Schema model = impl == Void.class ? chain.resolve(parameter, context) : context.getSchema(impl); setValue(schema, "group", model::setGroup); setValue(schema, "version", model::setVersion); @@ -151,12 +151,12 @@ public Schema resolve(ParameterMeta parameter, Context context, Chain chain) { if (enumItems != null) { model.setEnumeration(Arrays.asList(enumItems)); } - model.setRequired(schema.getBoolean("required")); + setBoolValue(schema, "required", model::setRequired); setValue(schema, "defaultValue", model::setDefaultValue); - model.setReadOnly(schema.getBoolean("readOnly")); - model.setWriteOnly(schema.getBoolean("writeOnly")); - model.setNullable(schema.getBoolean("nullable")); - model.setDeprecated(schema.getBoolean("deprecated")); + setBoolValue(schema, "readOnly", model::setReadOnly); + setBoolValue(schema, "writeOnly", model::setWriteOnly); + setBoolValue(schema, "nullable", model::setNullable); + setBoolValue(schema, "deprecated", model::setDeprecated); model.setExtensions(Helper.toProperties(schema.getStringArray("extensions"))); return model; } @@ -168,6 +168,13 @@ private static void setValue(AnnotationMeta schema, String key, Consumer schema, String key, Consumer setter) { + Boolean value = schema.getBoolean(key); + if (Boolean.TRUE.equals(value)) { + setter.accept(true); + } + } + @Override public Boolean acceptClass(Class clazz, ParameterMeta parameter) { AnnotationMeta schema = parameter.getAnnotation(Annotations.Schema); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java index 9b8b9f8073f..edaf5cdd983 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRestToolKit.java @@ -18,11 +18,8 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; -import org.apache.dubbo.remoting.http12.rest.Param; -import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; -import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.AbstractRestToolKit; @@ -32,7 +29,7 @@ final class BasicRestToolKit extends AbstractRestToolKit { public BasicRestToolKit(FrameworkModel frameworkModel) { super(frameworkModel); - binder = new BeanArgumentBinder(frameworkModel); + binder = new BeanArgumentBinder(argumentResolver); } @Override @@ -44,10 +41,4 @@ public int getDialect() { public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response) { return binder.bind(parameter, request, response); } - - @Override - public ParamType getParamType(ParameterMeta parameter) { - AnnotationMeta mapping = parameter.findAnnotation(Param.class); - return mapping == null ? null : mapping.getAnnotation().type(); - } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java index 3642fcefbf9..285e93ef218 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BeanArgumentBinder.java @@ -23,7 +23,6 @@ import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.remoting.http12.rest.Param; import org.apache.dubbo.remoting.http12.rest.ParamType; -import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; import org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver; @@ -49,8 +48,8 @@ final class BeanArgumentBinder { private final CompositeArgumentResolver argumentResolver; - public BeanArgumentBinder(FrameworkModel frameworkModel) { - argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); + public BeanArgumentBinder(CompositeArgumentResolver argumentResolver) { + this.argumentResolver = argumentResolver; } public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) { @@ -60,7 +59,7 @@ public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse re return null; } - ConstructorMeta constructor = beanMeta.getConstructorRequired(); + ConstructorMeta constructor = beanMeta.getConstructor(); ParameterMeta[] parameters = constructor.getParameters(); Object bean; int len = parameters.length; @@ -146,7 +145,7 @@ private static BeanMeta getBeanMeta(ParameterMeta paramMeta) { if (paramMeta.isSimple() || Modifier.isAbstract(type.getModifiers())) { return null; } - return CACHE.computeIfAbsent(type, k -> new BeanMeta(paramMeta.getToolKit(), k)); + return CACHE.computeIfAbsent(type, k -> paramMeta.getBeanMeta()); } /** diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java index 92735f485b0..96a5ceaf494 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java @@ -54,8 +54,8 @@ protected NamedValueMeta createNamedValueMeta(ParameterMeta param) { MethodMeta methodMeta = ((MethodParameterMeta) param).getMethodMeta(); ParameterMeta[] paramMetas = methodMeta.getParameters(); for (ParameterMeta paramMeta : paramMetas) { - AnnotationMeta anno = paramMeta.findAnnotation(Param.class); - if (anno != null && anno.getAnnotation().type() == ParamType.Body) { + AnnotationMeta ann = paramMeta.findAnnotation(Param.class); + if (ann != null && ann.getAnnotation().type() == ParamType.Body) { noBodyParam = false; break; } @@ -100,7 +100,7 @@ protected Object doResolveValue(NamedValueMeta meta, boolean single, HttpRequest if (body instanceof List) { List list = (List) body; if (list.size() == fm.paramCount) { - return list.get(meta.parameterMeta().getIndex()); + return list.get(meta.parameter().getIndex()); } } else if (body instanceof Map) { Object value = ((Map) body).get(meta.name()); @@ -116,10 +116,10 @@ protected Object doResolveValue(NamedValueMeta meta, boolean single, HttpRequest return RequestUtils.getParametersMap(request); } String value = request.parameter(meta.name()); - if (meta.parameterMeta().isSimple() || RestUtils.isMaybeJSONObject(value)) { + if (meta.parameter().isSimple() || RestUtils.isMaybeJSONObject(value)) { return value; } - return meta.parameterMeta().bind(request, response); + return meta.parameter().bind(request, response); } return request.parameterValues(meta.name()); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java index cbf906408db..8e5085e3a7b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java @@ -25,7 +25,6 @@ import org.apache.dubbo.remoting.http12.HttpRequest.FileUpload; import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.remoting.http12.rest.Param; -import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; @@ -54,8 +53,9 @@ protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMet if (Param.DEFAULT_NONE.equals(defaultValue)) { defaultValue = null; } - ParamType paramType = ann.getEnum("type"); - return new ParamNamedValueMeta(ann.getValue(), ann.getBoolean("required"), defaultValue, paramType); + NamedValueMeta meta = new NamedValueMeta(ann.getValue(), ann.getBoolean("required"), defaultValue); + meta.setParamType(ann.getEnum("type")); + return meta; } @Override @@ -65,13 +65,15 @@ public Class accept() { @Override protected Object resolveValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - switch (((ParamNamedValueMeta) meta).paramType) { + switch (meta.paramType()) { case PathVariable: return resolvePathVariable(meta, request); case MatrixVariable: return CollectionUtils.first(resolveMatrixVariable(meta, request)); case Param: return request.parameter(meta.name()); + case Form: + return request.formParameter(meta.name()); case Header: return request.header(meta.name()); case Cookie: @@ -96,7 +98,7 @@ protected Object filterValue(Object value, NamedValueMeta meta) { @Override protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - switch (((ParamNamedValueMeta) meta).paramType) { + switch (meta.paramType()) { case PathVariable: String value = resolvePathVariable(meta, request); return value == null ? Collections.emptyList() : Collections.singletonList(value); @@ -104,6 +106,8 @@ protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request return resolveMatrixVariable(meta, request); case Param: return request.parameterValues(meta.name()); + case Form: + return request.formParameterValues(meta.name()); case Header: return request.headerValues(meta.name()); case Cookie: @@ -142,7 +146,7 @@ protected Object resolveCollectionValue(NamedValueMeta meta, HttpRequest request @Override protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpResponse response) { - switch (((ParamNamedValueMeta) meta).paramType) { + switch (meta.paramType()) { case PathVariable: String value = resolvePathVariable(meta, request); return value == null ? Collections.emptyMap() : Collections.singletonMap(meta.name(), value); @@ -150,6 +154,8 @@ protected Object resolveMapValue(NamedValueMeta meta, HttpRequest request, HttpR return CollectionUtils.first(resolveMatrixVariable(meta, request)); case Param: return RequestUtils.getParametersMap(request); + case Form: + return RequestUtils.getFormParametersMap(request); case Header: return request.headers().asMap(); case Cookie: @@ -204,14 +210,4 @@ private static List resolveMatrixVariable(NamedValueMeta meta, HttpReque Map variableMap = request.attribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE); return RequestUtils.parseMatrixVariableValues(variableMap, meta.name()); } - - private static final class ParamNamedValueMeta extends NamedValueMeta { - - private final ParamType paramType; - - ParamNamedValueMeta(String name, boolean required, String defaultValue, ParamType paramType) { - super(name, required, defaultValue); - this.paramType = paramType; - } - } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java index 92e84ec5c8a..772022bb8cc 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/AbstractRestToolKit.java @@ -22,8 +22,10 @@ import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestException; +import org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.argument.GeneralTypeConverter; import org.apache.dubbo.rpc.protocol.tri.rest.argument.TypeConverter; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import javax.annotation.Nullable; @@ -39,11 +41,13 @@ public abstract class AbstractRestToolKit implements RestToolKit { protected final FrameworkModel frameworkModel; protected final TypeConverter typeConverter; protected final ParameterNameReader parameterNameReader; + protected final CompositeArgumentResolver argumentResolver; public AbstractRestToolKit(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; typeConverter = frameworkModel.getOrRegisterBean(GeneralTypeConverter.class); parameterNameReader = frameworkModel.getOrRegisterBean(DefaultParameterNameReader.class); + argumentResolver = frameworkModel.getOrRegisterBean(CompositeArgumentResolver.class); } @Override @@ -69,6 +73,11 @@ public Object convert(Object value, ParameterMeta parameter) { return target; } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter) { + return argumentResolver.getNamedValueMeta(parameter); + } + @Override public String[] getParameterNames(Method method) { return parameterNameReader.readParameterNames(method); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java index 9cc09c17a8b..86deda314c4 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/RestToolKit.java @@ -18,7 +18,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; -import org.apache.dubbo.remoting.http12.rest.ParamType; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import javax.annotation.Nullable; @@ -39,7 +39,7 @@ public interface RestToolKit { Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response); - ParamType getParamType(ParameterMeta parameter); + NamedValueMeta getNamedValueMeta(ParameterMeta parameter); @Nullable String[] getParameterNames(Method method); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java index 203ee7e4ec1..59a5e20bea0 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java @@ -446,7 +446,9 @@ private static void buildGenericTypeString(Type type, StringBuilder sb) { if (len > 0 && !(len == 1 && bounds[0] == Object.class)) { sb.append(" extends "); for (int i = 0; i < len; i++) { - if (i > 0) {sb.append(" & ");} + if (i > 0) { + sb.append(" & "); + } buildGenericTypeString(bounds[i], sb); } } From cce8f565ca494ec079a9cf6a6b2cd9c6ed93ed19 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Thu, 21 Nov 2024 23:43:52 +0800 Subject: [PATCH 09/23] NameStrategy impl --- .../dubbo/config/nested/OpenAPIConfig.java | 25 +-- .../dubbo/springboot/demo/servlet/Animal.java | 16 ++ .../dubbo/springboot/demo/servlet/Cat.java | 16 ++ .../dubbo/springboot/demo/servlet/Dog.java | 16 ++ .../dubbo/springboot/demo/servlet/Live.java | 16 ++ .../springboot/demo/servlet/sub/Dog.java | 32 ++++ .../src/main/resources/application.yml | 2 +- .../dubbo/metadata/MetadataService.java | 2 +- .../AbstractServerHttpChannelObserver.java | 9 +- .../tri/rest/openapi/ConfigFactory.java | 2 +- .../protocol/tri/rest/openapi/Context.java | 2 + .../tri/rest/openapi/ContextImpl.java | 10 ++ .../openapi/DefaultOpenAPINamingStrategy.java | 62 ++++++++ .../rest/openapi/DefaultOpenAPIService.java | 9 +- .../tri/rest/openapi/DefinitionMerger.java | 148 +++++++++++++++--- .../tri/rest/openapi/DefinitionResolver.java | 42 ++++- .../rpc/protocol/tri/rest/openapi/Helper.java | 3 - .../rest/openapi/OpenAPINamingStrategy.java | 12 +- .../rest/openapi/OpenAPISchemaResolver.java | 2 - .../tri/rest/openapi/SchemaFactory.java | 11 -- .../tri/rest/openapi/model/Components.java | 3 +- .../tri/rest/openapi/model/Schema.java | 41 ++++- ...protocol.tri.rest.openapi.OpenAPIExtension | 1 + 23 files changed, 400 insertions(+), 82 deletions(-) create mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/sub/Dog.java create mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java index 875c2e72f03..5db16597d46 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -92,14 +92,9 @@ public class OpenAPIConfig implements Serializable { private String securityScheme; /** - * The strategy used to generate operation id. + * The strategy used to generate operation id and schema name. */ - private String operationIdStrategy; - - /** - * The strategy used to generate schema name. - */ - private String schemaNameStrategy; + private String nameStrategy; /** * The default media types that are consumed. @@ -236,20 +231,12 @@ public void setSecurityScheme(String securityScheme) { this.securityScheme = securityScheme; } - public String getOperationIdStrategy() { - return operationIdStrategy; - } - - public void setOperationIdStrategy(String operationIdStrategy) { - this.operationIdStrategy = operationIdStrategy; - } - - public String getSchemaNameStrategy() { - return schemaNameStrategy; + public String getNameStrategy() { + return nameStrategy; } - public void setSchemaNameStrategy(String schemaNameStrategy) { - this.schemaNameStrategy = schemaNameStrategy; + public void setNameStrategy(String nameStrategy) { + this.nameStrategy = nameStrategy; } public String[] getDefaultConsumesMediaTypes() { diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java index 09c6b963787..435f74a5fb6 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java @@ -1,3 +1,19 @@ +/* + * 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.springboot.demo.servlet; public class Animal extends Live { diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java index fab53ae9347..ca73161871f 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java @@ -1,3 +1,19 @@ +/* + * 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.springboot.demo.servlet; public class Cat extends Animal { diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java index d1711e0fa38..063e886cb77 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java @@ -1,3 +1,19 @@ +/* + * 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.springboot.demo.servlet; public class Dog extends Animal { diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java index 06736a55f6a..c9f2316bbc8 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java @@ -1,3 +1,19 @@ +/* + * 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.springboot.demo.servlet; public class Live { diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/sub/Dog.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/sub/Dog.java new file mode 100644 index 00000000000..89916a98b5d --- /dev/null +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/sub/Dog.java @@ -0,0 +1,32 @@ +/* + * 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.springboot.demo.servlet.sub; + +import org.apache.dubbo.springboot.demo.servlet.Animal; + +public class Dog extends Animal { + + private String color; + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } +} diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml index 99c61ebab17..0f2a5571c7e 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml @@ -29,7 +29,7 @@ dubbo: rest: openapi: cache: false - schema-flatten: true + schema-flatten: false servlet: enabled: true registry: diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java index f50ce92e2ff..719c3691285 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java @@ -40,7 +40,7 @@ * 1. The Consumer queries the metadata information of the Provider to list the interfaces and each interface's configuration * 2. The Console (dubbo-admin) queries for the metadata of a specific process, or aggregate data of all processes. */ -@OpenAPI(hidden = "false") +@OpenAPI(hidden = "true") public interface MetadataService { /** diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java index c7f620644ca..e6c4277bb44 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java @@ -21,6 +21,7 @@ import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; @@ -207,7 +208,13 @@ protected final HttpOutputMessage buildMessage(int statusCode, Object data) thro if (LOGGER.isDebugEnabled()) { try { - LOGGER.debug("Http response body sent: '{}' by [{}]", JsonUtils.toJson(data), httpChannel); + String text; + if (data instanceof byte[]) { + text = new String((byte[]) data, StandardCharsets.UTF_8); + } else { + text = JsonUtils.toJson(data); + } + LOGGER.debug("Http response body sent: '{}' by [{}]", text, httpChannel); } catch (Throwable ignored) { } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java index c864bc3f003..25c5d04fe4a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java @@ -146,7 +146,7 @@ private static void applyConfigValue(Map map, String grou if (valueType == String.class) { method.invoke(config, value); } else if (valueType == Boolean.class) { - method.invoke(config, Boolean.valueOf(value.toLowerCase())); + method.invoke(config, StringUtils.toBoolean(value, false)); } else if (valueType.isArray()) { method.invoke(config, new Object[] {StringUtils.tokenize(value)}); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java index 76f956a1ac6..560b3cbee7d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java @@ -36,6 +36,8 @@ public interface Context { OpenAPIConfig getConfig(); + boolean isOpenAPI31(); + SchemaFactory getSchemaFactory(); ExtensionFactory getExtensionFactory(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java index 6cd7299d954..f9e21d4d87b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java @@ -27,6 +27,7 @@ final class ContextImpl extends AbstractContext implements Context { private final OpenAPIRequest request; + private Boolean openAPI31; private Holder httpRequest; private Holder httpResponse; @@ -35,6 +36,15 @@ final class ContextImpl extends AbstractContext implements Context { this.request = request; } + @Override + public boolean isOpenAPI31() { + if (openAPI31 == null) { + String v = request.getOpenapi(); + openAPI31 = v != null && v.startsWith("3.1."); + } + return openAPI31; + } + @Override public OpenAPIRequest getRequest() { return request; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java new file mode 100644 index 00000000000..a2f5c876ea0 --- /dev/null +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java @@ -0,0 +1,62 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.io.Bytes; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; + +import java.lang.reflect.Method; +import java.util.concurrent.ThreadLocalRandom; + +public class DefaultOpenAPINamingStrategy implements OpenAPINamingStrategy { + + @Override + public String generateOperationId(MethodMeta methodMeta, OpenAPI openAPI) { + return methodMeta.getMethod().getName(); + } + + @Override + public String resolveOperationIdConflict(int attempt, String operationId, MethodMeta methodMeta, OpenAPI openAPI) { + Method method = methodMeta.getMethod(); + if (attempt == 1) { + String sig = TypeUtils.buildSig(method); + if (sig != null) { + return method.getName() + '_' + sig; + } + } + return method.getName() + '_' + buildPostfix(attempt, method.toString()); + } + + @Override + public String generateSchemaName(Class clazz, OpenAPI openAPI) { + return clazz.getSimpleName(); + } + + @Override + public String resolveSchemaNameConflict(int attempt, String schemaName, Class clazz, OpenAPI openAPI) { + return clazz.getSimpleName() + '_' + buildPostfix(attempt, clazz.getName()); + } + + private static String buildPostfix(int attempt, String str) { + if (attempt > 4) { + str += ThreadLocalRandom.current().nextInt(10000); + } + return Bytes.bytes2hex(Bytes.getMD5(str), 0, Math.min(4, attempt)); + } +} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index 5e43339c75b..03cd50c9d13 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -101,7 +101,14 @@ private RadixTree initRequestHandlers() { @Override public HttpResult handle(String path, HttpRequest httpRequest, HttpResponse httpResponse) { OpenAPIRequest request = httpRequest.attribute(OpenAPIRequest.class.getName()); - request.setGroup(RequestUtils.getPathVariable(httpRequest, "group")); + String group = RequestUtils.getPathVariable(httpRequest, "group"); + if (group != null) { + int index = group.lastIndexOf('.'); + if (index > 0) { + group = group.substring(0, index); + } + request.setGroup(group); + } return HttpResult.builder() .contentType(MediaType.APPLICATION + '/' + request.getFormat()) .body(handleDocument(request).getBytes(StandardCharsets.UTF_8)) diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index 2cfadccc7d7..321b4caca7e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.common.logger.FluentLogger; +import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.JsonUtils; import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.remoting.http12.HttpMethods; @@ -42,28 +43,50 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Set; import java.util.TreeMap; +import java.util.function.Consumer; final class DefinitionMerger { private static final FluentLogger LOG = FluentLogger.of(DefinitionMerger.class); + private static final String NAMING_STRATEGY_PREFIX = "naming-strategy-"; + private static final String NAMING_STRATEGY_DEFAULT = "default"; + private final ExtensionFactory extensionFactory; private final ConfigFactory configFactory; + private OpenAPINamingStrategy openAPINamingStrategy; DefinitionMerger(FrameworkModel frameworkModel) { + extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); } + private OpenAPINamingStrategy getNamingStrategy() { + if (openAPINamingStrategy == null) { + String strategy = configFactory.getGlobalConfig().getNameStrategy(); + String name = NAMING_STRATEGY_PREFIX + (strategy == null ? NAMING_STRATEGY_DEFAULT : strategy); + openAPINamingStrategy = extensionFactory.getExtension(OpenAPINamingStrategy.class, name); + Objects.requireNonNull(openAPINamingStrategy, "Can't find OpenAPINamingStrategy with name: " + name); + } + return openAPINamingStrategy; + } + public OpenAPI merge(List openAPIs, OpenAPIRequest request) { Info info = new Info(); OpenAPI model = new OpenAPI().setInfo(info); + OpenAPIConfig globalConfig = configFactory.getGlobalConfig(); + model.setGlobalConfig(globalConfig); if (openAPIs.isEmpty()) { - applyConfig(model, configFactory.getGlobalConfig()); + applyConfig(model, globalConfig); return model; } @@ -80,7 +103,9 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { } model.setOpenapi(Helper.formatSpecVersion(request.getOpenapi())); - applyConfig(model, configFactory.getConfig(group)); + OpenAPIConfig config = configFactory.getConfig(group); + model.setConfig(config); + applyConfig(model, config); for (OpenAPI api : openAPIs) { if (isServiceNotMatch(api.getMeta().getServiceInterface(), services)) { @@ -98,10 +123,12 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { mergeTags(model, api); } - applyConfig(model, configFactory.getGlobalConfig()); + applyConfig(model, globalConfig); addSchemas(model, version, group); + completeOperations(model); + completeModel(model); return model; @@ -436,15 +463,7 @@ private void mergeTags(OpenAPI api, OpenAPI from) { } private void addSchemas(OpenAPI api, String version, String group) { - Components components = api.getComponents(); - if (components == null) { - api.setComponents(components = new Components()); - } - Map schemas = components.getSchemas(); - if (schemas == null) { - components.setSchemas(schemas = new TreeMap<>()); - } - + Map schemas = new IdentityHashMap<>(); for (PathItem pathItem : api.getPaths().values()) { Map operations = pathItem.getOperations(); if (operations == null) { @@ -495,9 +514,47 @@ private void addSchemas(OpenAPI api, String version, String group) { } } } + + Components components = api.getComponents(); + if (components == null) { + api.setComponents(components = new Components()); + } + + Set names = CollectionUtils.newHashSet(schemas.size()); + for (Schema schema : schemas.keySet()) { + String name = schema.getName(); + if (name != null) { + names.add(name); + } + } + + OpenAPINamingStrategy strategy = getNamingStrategy(); + for (Schema schema : schemas.values()) { + String name = schema.getName(); + if (name == null) { + Class clazz = schema.getJavaType(); + name = strategy.generateSchemaName(clazz, api); + for (int i = 1; i < 100; i++) { + if (names.contains(name)) { + name = strategy.resolveSchemaNameConflict(i, name, clazz, api); + } else { + names.add(name); + break; + } + } + schema.setName(name); + } + + for (Schema sourceSchema : schema.getSourceSchemas()) { + sourceSchema.setTargetSchema(schema); + sourceSchema.setRef("#/components/schemas/" + name); + } + schema.setSourceSchemas(null); + components.addSchema(name, schema); + } } - private void addSchema(Schema schema, Map schemas, String group, String version) { + private void addSchema(Schema schema, Map schemas, String group, String version) { if (schema == null) { return; } @@ -506,8 +563,12 @@ private void addSchema(Schema schema, Map schemas, String group, Map properties = schema.getProperties(); if (properties != null) { - for (Schema property : properties.values()) { + Iterator> it = properties.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + Schema property = entry.getValue(); if (isGroupNotMatch(group, property.getGroup()) || isVersionNotMatch(version, property.getVersion())) { + it.remove(); continue; } addSchema(property, schemas, group, version); @@ -544,10 +605,61 @@ private void addSchema(Schema schema, Map schemas, String group, return; } - String name = targetSchema.getJavaType().getSimpleName(); - schema.setRef("#/components/schemas/" + name); - if (schemas.putIfAbsent(name, targetSchema) == null) { - addSchema(targetSchema, schemas, group, version); + targetSchema.addSourceSchema(schema); + + schemas.computeIfAbsent(targetSchema, s -> { + Schema newSchema = s.clone(); + addSchema(newSchema, schemas, group, version); + return newSchema; + }); + } + + private void completeOperations(OpenAPI api) { + Map paths = api.getPaths(); + if (paths == null) { + return; + } + + Set operationIds = new HashSet<>(32); + walkOperations(api, operation -> { + String operationId = operation.getOperationId(); + if (operationId != null) { + operationIds.add(operationId); + } + }); + + OpenAPINamingStrategy strategy = getNamingStrategy(); + walkOperations(api, operation -> { + String id = operation.getOperationId(); + if (id != null) { + return; + } + id = strategy.generateOperationId(operation.getMeta(), api); + for (int i = 1; i < 100; i++) { + if (operationIds.contains(id)) { + id = strategy.resolveOperationIdConflict(i, id, operation.getMeta(), api); + } else { + operationIds.add(id); + break; + } + } + operation.setOperationId(id); + }); + } + + private static void walkOperations(OpenAPI api, Consumer consumer) { + Map paths = api.getPaths(); + if (paths == null) { + return; + } + + for (PathItem pathItem : paths.values()) { + Map operations = pathItem.getOperations(); + if (operations != null) { + for (Operation operation : operations.values()) { + consumer.accept(operation); + } + } } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index ccb2bd8c197..8b992875e34 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -26,6 +26,7 @@ import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.Registration; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathCondition; @@ -44,6 +45,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; import java.util.ArrayList; import java.util.Arrays; @@ -91,6 +93,12 @@ public OpenAPI resolve(ServiceMeta serviceMeta, Collection> r openAPI.setConfig(configFactory.getConfig(openAPI.getGroup())); openAPI.setMeta(serviceMeta); + String service = serviceMeta.getServiceInterface(); + int index = service.lastIndexOf('.'); + openAPI.addTag(new Tag() + .setName(index > 0 ? service.substring(index + 1) : service) + .setDescription(service)); + ResolveContext context = new ResolveContextImpl(openAPI, schemaFactory, extensionFactory); for (List registrations : registrationsByMethod) { String mainPath = null; @@ -189,9 +197,6 @@ private void resolveOperation( OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) { - if (operation.getOperationId() == null) { - operation.setOperationId(meta.getMethod().getName()); - } if (operation.getDeprecated() == null && meta.isHierarchyAnnotated(Deprecated.class)) { operation.setDeprecated(true); } @@ -215,8 +220,21 @@ private void resolveOperation( } } + ServiceMeta serviceMeta = meta.getServiceMeta(); + if (serviceMeta.getServiceVersion() != null) { + operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_GROUP.getName(), In.HEADER) + .setSchema(PrimitiveSchema.STRING.newSchema())); + } + if (serviceMeta.getServiceGroup() != null) { + operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_VERSION.getName(), In.HEADER) + .setSchema(PrimitiveSchema.STRING.newSchema())); + } + String service = serviceMeta.getServiceInterface(); + int index = service.lastIndexOf('.'); + operation.addTag(index > 0 ? service.substring(index + 1) : service); + for (ParameterMeta paramMeta : meta.getParameters()) { - resolveParameter(operation, paramMeta, true); + resolveParameter(httpMethod, operation, paramMeta, true); } if (httpMethod.supportBody()) { @@ -242,14 +260,22 @@ private void resolveOperation( } } - private void resolveParameter(Operation operation, ParameterMeta paramMeta, boolean traverse) { + private void resolveParameter( + HttpMethods httpMethod, Operation operation, ParameterMeta paramMeta, boolean traverse) { String name = paramMeta.getName(); if (name == null) { return; } NamedValueMeta valueMeta = paramMeta.getNamedValueMeta(); - In in = Helper.toIn(valueMeta.paramType()); + ParamType paramType = valueMeta.paramType(); + if (paramType == null) { + if (httpMethod.supportBody()) { + return; + } + paramType = ParamType.Param; + } + In in = Helper.toIn(paramType); if (in == null) { return; } @@ -284,7 +310,7 @@ private void resolveParameter(Operation operation, ParameterMeta paramMeta, bool BeanMeta beanMeta = paramMeta.getBeanMeta(); try { for (ParameterMeta ctorParam : beanMeta.getConstructor().getParameters()) { - resolveParameter(operation, ctorParam, false); + resolveParameter(httpMethod, operation, ctorParam, false); } } catch (Throwable ignored) { } @@ -292,7 +318,7 @@ private void resolveParameter(Operation operation, ParameterMeta paramMeta, bool if ((property.getVisibility() & 0b001) == 0) { continue; } - resolveParameter(operation, property, false); + resolveParameter(httpMethod, operation, property, false); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index 75d0b4d2db7..da8cd481857 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -82,9 +82,6 @@ public static Collection guessHttpMethod(MethodMeta method) { } public static In toIn(ParamType paramType) { - if (paramType == null) { - return In.QUERY; - } switch (paramType) { case PathVariable: return In.PATH; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java index f65600c2e65..c71acd0dddb 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java @@ -21,13 +21,11 @@ public interface OpenAPINamingStrategy extends OpenAPIExtension { - String PREFIX = "naming-strategy-"; + String generateOperationId(MethodMeta methodMeta, OpenAPI openAPI); - default String generateOperationId(MethodMeta methodMeta, OpenAPI openAPI) { - return null; - } + String resolveOperationIdConflict(int attempt, String operationId, MethodMeta methodMeta, OpenAPI openAPI); - default String generateSchemaName(Class type, OpenAPI openAPI) { - return null; - } + String generateSchemaName(Class clazz, OpenAPI openAPI); + + String resolveSchemaNameConflict(int attempt, String schemaName, Class clazz, OpenAPI openAPI); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java index 3d5d3d693c9..6a740e0517e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java @@ -32,8 +32,6 @@ interface Chain { interface Context { - void defineSchema(String name, Class type, Schema schema); - void defineSchema(Class type, Schema schema); Schema getSchema(ParameterMeta parameter); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java index 42fc2db92fc..6f7b6e6e936 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java @@ -49,7 +49,6 @@ public final class SchemaFactory { private final OpenAPISchemaResolver[] resolvers; private final OpenAPISchemaPredicate[] predicates; private final Map, Optional> schemaMap = CollectionUtils.newConcurrentHashMap(); - private final Map, String> nameMap = CollectionUtils.newConcurrentHashMap(); public SchemaFactory(FrameworkModel frameworkModel) { configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); @@ -62,10 +61,6 @@ public Map, Optional> getSchemaMap() { return schemaMap; } - public Map, String> getNameMap() { - return nameMap; - } - public Schema getSchema(Type type) { return getSchema(new TypeParameterMeta(type)); } @@ -73,12 +68,6 @@ public Schema getSchema(Type type) { public Schema getSchema(ParameterMeta parameter) { return new ChainImpl(resolvers, p -> resolveSchema(p.getActualGenericType(), p)) .resolve(parameter, new Context() { - @Override - public void defineSchema(String name, Class type, Schema schema) { - schemaMap.putIfAbsent(type, Optional.of(schema)); - nameMap.put(type, name); - } - @Override public void defineSchema(Class type, Schema schema) { schemaMap.putIfAbsent(type, Optional.of(schema)); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java index 5859a52bc14..46567b7e40e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java @@ -20,6 +20,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import java.util.TreeMap; public final class Components extends Node { @@ -37,7 +38,7 @@ public Components setSchemas(Map schemas) { public Components addSchema(String name, Schema schema) { if (schemas == null) { - schemas = new LinkedHashMap<>(); + schemas = new TreeMap<>(); } schemas.put(name, schema); return this; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java index 165aaa9b5b4..6c94e4bc837 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java @@ -22,6 +22,7 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -97,8 +98,9 @@ public Type of(String value) { private String group; private String version; + private Class javaType; private transient Schema targetSchema; - private transient Class javaType; + private transient List sourceSchemas; public String getRef() { return ref; @@ -521,6 +523,15 @@ public Schema setVersion(String version) { return this; } + public Class getJavaType() { + return javaType; + } + + public Schema setJavaType(Class javaType) { + this.javaType = javaType; + return this; + } + public Schema getTargetSchema() { return targetSchema; } @@ -530,15 +541,22 @@ public Schema setTargetSchema(Schema targetSchema) { return this; } - public Class getJavaType() { - return javaType; + public List getSourceSchemas() { + return sourceSchemas; } - public Schema setJavaType(Class javaType) { - this.javaType = javaType; + public Schema setSourceSchemas(List sourceSchemas) { + this.sourceSchemas = sourceSchemas; return this; } + public void addSourceSchema(Schema sourceSchema) { + if (sourceSchemas == null) { + sourceSchemas = new LinkedList<>(); + } + sourceSchemas.add(sourceSchema); + } + @Override public Schema clone() { Schema clone = super.clone(); @@ -565,7 +583,6 @@ public Map writeTo(Map schema, Context context) return schema; } write(schema, "format", format); - write(schema, "name", name); write(schema, "title", title); write(schema, "description", description); write(schema, "default", defaultValue); @@ -585,7 +602,16 @@ public Map writeTo(Map schema, Context context) write(schema, "required", required); write(schema, "enum", enumeration); if (type != null) { - write(schema, "type", type.toString()); + if (context.isOpenAPI31()) { + if (nullable == null || !nullable) { + write(schema, "type", type.toString()); + } else { + write(schema, "type", new String[] {type.toString(), "null"}); + } + } else { + write(schema, "type", type.toString()); + write(schema, "nullable", nullable); + } } write(schema, "items", items, context); write(schema, "properties", properties, context); @@ -603,7 +629,6 @@ public Map writeTo(Map schema, Context context) write(schema, "anyOf", anyOf, context); write(schema, "not", not, context); write(schema, "discriminator", discriminator, context); - write(schema, "nullable", nullable); write(schema, "writeOnly", writeOnly); write(schema, "deprecated", deprecated); writeExtensions(schema); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension index dca2e05d85a..c2f29afc12b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension @@ -1 +1,2 @@ resolver-basic=org.apache.dubbo.rpc.protocol.tri.rest.support.basic.BasicOpenAPIDefinitionResolver +naming-strategy-default=org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPINamingStrategy From 7412dd8ef4d1ead81759e2be452ab541574890ee Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Fri, 22 Nov 2024 11:37:12 +0800 Subject: [PATCH 10/23] Export openAPI when spring boot application ready --- .../rest/openapi/DefaultOpenAPIService.java | 20 +++++--- .../tri/rest/openapi/ExtensionFactory.java | 4 ++ .../DubboListenerAutoConfiguration.java | 9 ++++ .../dubbo-spring-boot/pom.xml | 6 +++ .../event/DubboOpenAPIExportListener.java | 49 +++++++++++++++++++ 5 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index 03cd50c9d13..d8172b3a3a8 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -207,18 +207,22 @@ public void refresh() { @Override public void export() { - if (extensionFactory.getExtensions(OpenAPIDocumentPublisher.class).length == 0) { + if (!extensionFactory.hasExtensions(OpenAPIDocumentPublisher.class)) { return; } - if (exportFuture != null) { - exportFuture.cancel(false); + try { + if (exportFuture != null) { + exportFuture.cancel(false); + } + exportFuture = frameworkModel + .getBean(FrameworkExecutorRepository.class) + .getMetadataRetryExecutor() + .schedule(this::doExport, 30, TimeUnit.SECONDS); + exported = true; + } catch (Throwable t) { + LOG.internalWarn("Failed to export OpenAPI documents", t); } - exportFuture = frameworkModel - .getBean(FrameworkExecutorRepository.class) - .getMetadataRetryExecutor() - .schedule(this::doExport, 30, TimeUnit.SECONDS); - exported = true; } private void doExport() { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java index 0823ba1c8e2..62e2e5cce7a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java @@ -41,6 +41,10 @@ public ExtensionFactory(FrameworkModel frameworkModel) { cache = CollectionUtils.newConcurrentHashMap(); } + public boolean hasExtensions(Class type) { + return getExtensions(type).length > 0; + } + public T[] getExtensions(Class type) { return (T[]) cache.computeIfAbsent(type, k -> { List list = new ArrayList<>(); diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java index f55a7ce72e9..02a97a1e394 100644 --- a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java @@ -16,8 +16,10 @@ */ package org.apache.dubbo.spring.boot.autoconfigure; +import org.apache.dubbo.rpc.Constants; import org.apache.dubbo.spring.boot.context.event.AwaitingNonWebApplicationListener; import org.apache.dubbo.spring.boot.context.event.DubboConfigBeanDefinitionConflictApplicationListener; +import org.apache.dubbo.spring.boot.context.event.DubboOpenAPIExportListener; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -46,4 +48,11 @@ public DubboConfigBeanDefinitionConflictApplicationListener dubboConfigBeanDefin public AwaitingNonWebApplicationListener awaitingNonWebApplicationListener() { return new AwaitingNonWebApplicationListener(); } + + @ConditionalOnMissingBean + @Bean + @ConditionalOnProperty(prefix = Constants.H2_SETTINGS_OPENAPI_PREFIX, name = "enabled", matchIfMissing = true) + public DubboOpenAPIExportListener dubboOpenAPIExportListener() { + return new DubboOpenAPIExportListener(); + } } diff --git a/dubbo-spring-boot-project/dubbo-spring-boot/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot/pom.xml index b9918837343..a43652782d6 100644 --- a/dubbo-spring-boot-project/dubbo-spring-boot/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot/pom.xml @@ -40,6 +40,12 @@ ${project.version} true + + org.apache.dubbo + dubbo-rpc-triple + ${project.version} + true + org.springframework.boot diff --git a/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java new file mode 100644 index 00000000000..73a0f347a6e --- /dev/null +++ b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java @@ -0,0 +1,49 @@ +/* + * 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.spring.boot.context.event; + +import org.apache.dubbo.config.spring.util.DubboBeanUtils; +import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIService; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; + +/** + * OpenAPI Export Listener + *

+ * This class exports OpenAPI specifications for Dubbo services + * when the Spring Boot application is fully started and ready. + */ +public class DubboOpenAPIExportListener implements ApplicationListener { + + private final AtomicBoolean exported = new AtomicBoolean(false); + + @Override + public void onApplicationEvent(ApplicationReadyEvent event) { + if (!exported.compareAndSet(false, true)) { + return; + } + ApplicationModel applicationModel = DubboBeanUtils.getApplicationModel(event.getApplicationContext()); + OpenAPIService openAPIService = applicationModel.getBean(OpenAPIService.class); + if (openAPIService != null) { + openAPIService.export(); + } + } +} From 71867e0948cb347c88398f5b80aac5d4bb79eeb6 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Fri, 22 Nov 2024 15:19:57 +0800 Subject: [PATCH 11/23] Swagger ui support impl --- .../dubbo/common/utils/StringUtils.java | 55 +++++- .../dubbo/config/nested/OpenAPIConfig.java | 4 + .../pom.xml | 2 +- .../pom.xml | 2 +- .../dubbo-demo-spring-boot-servlet/pom.xml | 5 + dubbo-distribution/dubbo-all-shaded/pom.xml | 7 + dubbo-distribution/dubbo-all/pom.xml | 7 + .../dubbo/metadata/MetadataService.java | 2 +- .../dubbo/metadata/MetadataServiceV2.java | 2 +- .../spring/BindParamArgumentResolver.java | 2 +- .../spring/FallbackArgumentResolver.java | 2 +- .../spring/RequestBodyArgumentResolver.java | 2 +- .../spring/RequestPartArgumentResolver.java | 2 +- dubbo-plugin/dubbo-rest-swagger/pom.xml | 29 ++- .../tri/rest/support/swagger/Helper.java | 44 +++++ .../SwaggerOpenAPIDefinitionResolver.java | 176 ++++++++++++++++++ .../swagger/SwaggerUIRequestHandler.java | 160 ++++++++++++++++ .../rest/support/swagger/WebjarHelper.java | 58 ++++++ ...protocol.tri.rest.openapi.OpenAPIExtension | 2 + .../META-INF/resources/swagger-ui/index.html | 51 +++++ .../message/codec/BinaryCodecFactory.java | 5 + ...g.http12.message.HttpMessageEncoderFactory | 1 + dubbo-rpc/dubbo-rpc-triple/pom.xml | 2 +- .../tri/rest/mapping/ContentNegotiator.java | 13 +- .../protocol/tri/rest/mapping/RadixTree.java | 8 + .../tri/rest/mapping/meta/NamedValueMeta.java | 14 +- .../rest/openapi/DefaultOpenAPIService.java | 40 +++- .../tri/rest/openapi/DefinitionMerger.java | 61 ++---- .../tri/rest/openapi/DefinitionResolver.java | 32 ++-- .../tri/rest/openapi/OpenAPIService.java | 4 + .../protocol/tri/rest/openapi/model/Node.java | 4 +- .../tri/rest/openapi/model/OpenAPI.java | 18 ++ .../basic/FallbackArgumentResolver.java | 2 +- .../basic/GRequestArgumentResolver.java | 8 + .../rpc/protocol/tri/rest/util/PathUtils.java | 19 ++ .../dubbo-spring-boot-autoconfigure/pom.xml | 6 - pom.xml | 1 + 37 files changed, 747 insertions(+), 105 deletions(-) create mode 100644 dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/Helper.java create mode 100644 dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java create mode 100644 dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java create mode 100644 dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java create mode 100644 dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension create mode 100644 dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/swagger-ui/index.html diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java index 1c3f156873c..e4c3919d937 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java @@ -1265,12 +1265,17 @@ public static boolean startsWithIgnoreCase(String str, String prefix) { return str.regionMatches(true, 0, prefix, 0, prefix.length()); } + /** + * Returns the default string if the input string is empty, otherwise returns + * the input string itself + */ public static String defaultIf(String str, String defaultStr) { return isEmpty(str) ? defaultStr : str; } /** - * Returns a substring from 'str' between 'start' and 'end', or to the end if 'end' is -1 + * Gets a substring from the specified String avoiding exceptions. If end index + * is not found, returns substring from start to the end */ public static String substring(String str, int start, int end) { if (str == null) { @@ -1280,8 +1285,8 @@ public static String substring(String str, int start, int end) { } /** - * Extracts a substring from the given string that precedes the first occurrence of the specified character separator. - * If the character is not found, the entire string is returned. + * Gets the substring before the first occurrence of a separator. + * If no match found, returns the original string */ public static String substringBefore(String str, int separator) { if (isEmpty(str)) { @@ -1292,20 +1297,41 @@ public static String substringBefore(String str, int separator) { } /** - * Extracts a substring from the given string that precedes the first occurrence of the specified string separator. - * If the separator is not found or is null, the entire string is returned. + * Gets the substring after the first occurrence of a separator. + * If no match found, returns the original string */ - public static String substringBefore(String str, String separator) { - if (isEmpty(str) || separator == null) { + public static String substringAfter(String str, int separator) { + if (isEmpty(str)) { return str; } - if (separator.isEmpty()) { - return EMPTY_STRING; - } int index = str.indexOf(separator); + return index == INDEX_NOT_FOUND ? str : str.substring(index + 1); + } + + /** + * Gets the substring before the last occurrence of a separator. + * If no match found, returns the original string + */ + public static String substringBeforeLast(String str, int separator) { + if (isEmpty(str)) { + return str; + } + int index = str.lastIndexOf(separator); return index == INDEX_NOT_FOUND ? str : str.substring(0, index); } + /** + * Gets the substring after the last occurrence of a separator. + * If no match found, returns the original string + */ + public static String substringAfterLast(String str, int separator) { + if (isEmpty(str)) { + return str; + } + int index = str.lastIndexOf(separator); + return index == INDEX_NOT_FOUND ? str : str.substring(index + 1); + } + /** * Tokenize the given String into a String array. * Trims tokens and omits empty tokens. @@ -1317,6 +1343,10 @@ public static String[] tokenize(String str, char... separators) { return tokenizeToList(str, separators).toArray(EMPTY_STRING_ARRAY); } + /** + * Splits a string into a list of tokens using specified separators, trimming whitespace + * and ignoring empty tokens. Uses comma as default separator if none provided. + */ public static List tokenizeToList(String str, char... separators) { if (isEmpty(str)) { return Collections.emptyList(); @@ -1363,6 +1393,11 @@ public static List tokenizeToList(String str, char... separators) { return tokens; } + /** + * Converts string to Boolean based on common boolean representations. + * Supports values like 'true'/'false', 'yes'/'no', 'on'/'off', '1'/'0', etc. + * Returns null if the input cannot be parsed. + */ public static Boolean toBoolean(String value) { if (isEmpty(value)) { return null; diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java index 5db16597d46..4069eb061a8 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -290,4 +290,8 @@ public void setSettings(Map settings) { public String getSetting(String key) { return settings == null ? null : settings.get(key); } + + public String getSetting(String key, String defaultValue) { + return settings == null ? defaultValue : settings.getOrDefault(key, defaultValue); + } } diff --git a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml index 2a2b74953ae..a9bb5cb4759 100644 --- a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml @@ -35,7 +35,7 @@ org.apache.dubbo dubbo-maven-plugin - ${project.version} + 3.3.2 diff --git a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml index c81d3d8bf9f..c73440fca2a 100644 --- a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml @@ -35,7 +35,7 @@ org.apache.dubbo dubbo-maven-plugin - ${project.version} + 3.3.2 diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml index 7c893bf7fbc..46bd5e28021 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml @@ -52,6 +52,11 @@ dubbo-triple-servlet ${project.version} + + org.apache.dubbo + dubbo-rest-swagger + ${project.version} + org.apache.dubbo dubbo-serialization-hessian2 diff --git a/dubbo-distribution/dubbo-all-shaded/pom.xml b/dubbo-distribution/dubbo-all-shaded/pom.xml index 86dcd6e473a..4c74741dcf7 100644 --- a/dubbo-distribution/dubbo-all-shaded/pom.xml +++ b/dubbo-distribution/dubbo-all-shaded/pom.xml @@ -276,6 +276,13 @@ compile true + + org.apache.dubbo + dubbo-rest-swagger + ${project.version} + compile + true + org.apache.dubbo dubbo-triple-servlet diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml index 9e3ca1976dd..f518a387e44 100644 --- a/dubbo-distribution/dubbo-all/pom.xml +++ b/dubbo-distribution/dubbo-all/pom.xml @@ -276,6 +276,13 @@ compile true + + org.apache.dubbo + dubbo-rest-swagger + ${project.version} + compile + true + org.apache.dubbo dubbo-triple-servlet diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java index 719c3691285..e645771afef 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java @@ -40,7 +40,7 @@ * 1. The Consumer queries the metadata information of the Provider to list the interfaces and each interface's configuration * 2. The Console (dubbo-admin) queries for the metadata of a specific process, or aggregate data of all processes. */ -@OpenAPI(hidden = "true") +@OpenAPI(group = "metadata") public interface MetadataService { /** diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java index fd3f69479a0..89e43d0b2d3 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java @@ -20,7 +20,7 @@ import java.util.concurrent.CompletableFuture; -@OpenAPI(hidden = "true") +@OpenAPI(group = "metadata") public interface MetadataServiceV2 extends org.apache.dubbo.rpc.model.DubboStub { String JAVA_SERVICE_NAME = "org.apache.dubbo.metadata.MetadataServiceV2"; diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java index f14b83637b6..99c2bfedcf5 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java @@ -43,7 +43,7 @@ protected ParamType getParamType(NamedValueMeta meta) { @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - return new NamedValueMeta(ann.getValue(), param.isAnnotated(Annotations.Nonnull), null); + return new NamedValueMeta(ann.getValue(), param.isAnnotated(Annotations.Nonnull)); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java index e43adcf7bc2..d3d28eb359a 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java @@ -36,7 +36,7 @@ public boolean accept(ParameterMeta param) { @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param) { - return new NamedValueMeta(param.isAnnotated(Annotations.Nonnull), null); + return new NamedValueMeta(param.isAnnotated(Annotations.Nonnull)); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java index 3fda32b1862..82110a68724 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java @@ -45,7 +45,7 @@ protected ParamType getParamType(NamedValueMeta meta) { @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - return new NamedValueMeta(Helper.isRequired(ann), null); + return new NamedValueMeta(Helper.isRequired(ann)); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java index 4d9eefbcfe6..e557b196076 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java @@ -46,7 +46,7 @@ protected ParamType getParamType(NamedValueMeta meta) { @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - return new NamedValueMeta(ann.getValue(), Helper.isRequired(ann), null); + return new NamedValueMeta(ann.getValue(), Helper.isRequired(ann)); } @Override diff --git a/dubbo-plugin/dubbo-rest-swagger/pom.xml b/dubbo-plugin/dubbo-rest-swagger/pom.xml index 62815d348c6..c1900eab817 100644 --- a/dubbo-plugin/dubbo-rest-swagger/pom.xml +++ b/dubbo-plugin/dubbo-rest-swagger/pom.xml @@ -19,13 +19,19 @@ 4.0.0 org.apache.dubbo - dubbo-plugin + dubbo-parent ${revision} - ../pom.xml + ../../pom.xml dubbo-rest-swagger + + 2.2.25 + 5.18.2 + 1.0.0 + + org.apache.dubbo @@ -34,16 +40,19 @@ - org.springdoc - springdoc-openapi-starter-webmvc-ui - 2.6.0 - provided + io.swagger.core.v3 + swagger-annotations + ${swagger-annotations.version} + + + org.webjars + swagger-ui + ${swagger-ui.version} - io.quarkus - quarkus-smallrye-openapi-deployment - 3.16.0 - provided + org.webjars + webjars-locator-lite + ${webjars-locator.version} diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/Helper.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/Helper.java new file mode 100644 index 00000000000..766029b71c6 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/Helper.java @@ -0,0 +1,44 @@ +/* + * 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.protocol.tri.rest.support.swagger; + +import org.apache.dubbo.common.utils.StringUtils; + +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +final class Helper { + + private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{\\{([\\w.-]+)}}"); + + private Helper() {} + + public static String render(String text, Function fn) { + if (text == null) { + return null; + } + Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); + StringBuffer result = new StringBuffer(text.length()); + while (matcher.find()) { + String value = fn.apply(matcher.group(1)); + matcher.appendReplacement(result, value == null ? StringUtils.EMPTY_STRING : value); + } + matcher.appendTail(result); + return result.toString(); + } +} diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java new file mode 100644 index 00000000000..8956369063c --- /dev/null +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java @@ -0,0 +1,176 @@ +/* + * 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.protocol.tri.rest.support.swagger; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaPredicate; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ResolveContext; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Contact; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.License; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; + +import java.util.Map; + +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.Hidden; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; + +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim; + +@Activate(order = 50, onClass = "io.swagger.v3.oas.annotations.OpenAPIDefinition") +public final class SwaggerOpenAPIDefinitionResolver + implements OpenAPIDefinitionResolver, OpenAPISchemaResolver, OpenAPISchemaPredicate { + + @Override + public boolean hidden(ServiceMeta serviceMeta) { + return serviceMeta.isHierarchyAnnotated(Hidden.class); + } + + @Override + public OpenAPI resolve(ServiceMeta serviceMeta) { + AnnotationMeta meta = serviceMeta.findAnnotation(OpenAPIDefinition.class); + if (meta == null) { + return null; + } + + OpenAPI model = new OpenAPI(); + OpenAPIDefinition definition = meta.getAnnotation(); + + Info info = new Info(); + model.setInfo(info); + io.swagger.v3.oas.annotations.info.Info infoAnn = definition.info(); + info.setTitle(trim(infoAnn.title())) + .setDescription(trim(infoAnn.description())) + .setVersion(trim(infoAnn.version())) + .setExtensions(toProperties(infoAnn.extensions())); + + Contact contact = new Contact(); + info.setContact(contact); + io.swagger.v3.oas.annotations.info.Contact contactAnn = infoAnn.contact(); + contact.setName(trim(contactAnn.name())) + .setEmail(trim(contactAnn.email())) + .setUrl(trim(contactAnn.url())) + .setExtensions(toProperties(contactAnn.extensions())); + + License license = new License(); + info.setLicense(license); + io.swagger.v3.oas.annotations.info.License licenseAnn = infoAnn.license(); + license.setName(trim(licenseAnn.name())) + .setUrl(trim(licenseAnn.url())) + .setExtensions(toProperties(licenseAnn.extensions())); + + for (io.swagger.v3.oas.annotations.tags.Tag tagAnn : definition.tags()) { + model.addTag(new Tag() + .setName(trim(tagAnn.name())) + .setDescription(trim(tagAnn.description())) + .setExternalDocs(toExternalDocs(tagAnn.externalDocs())) + .setExtensions(toProperties(tagAnn.extensions()))); + } + + model.setExternalDocs(toExternalDocs(definition.externalDocs())); + + model.setExtensions(toProperties(definition.extensions())); + return model; + } + + private static Map toProperties(io.swagger.v3.oas.annotations.extensions.Extension[] extensions) { + int len = extensions.length; + if (len == 0) { + return null; + } + Map properties = CollectionUtils.newLinkedHashMap(extensions.length); + for (io.swagger.v3.oas.annotations.extensions.Extension extension : extensions) { + for (ExtensionProperty property : extension.properties()) { + properties.put(property.name(), property.value()); + } + } + return properties; + } + + private static ExternalDocs toExternalDocs(ExternalDocumentation ann) { + return new ExternalDocs() + .setDescription(trim(ann.description())) + .setUrl(trim(ann.url())) + .setExtensions(toProperties(ann.extensions())); + } + + @Override + public boolean hidden(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { + return methodMeta.isHierarchyAnnotated(Hidden.class); + } + + @Override + public Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { + AnnotationMeta meta = + methodMeta.findAnnotation(io.swagger.v3.oas.annotations.Operation.class); + if (meta == null) { + return null; + } + + io.swagger.v3.oas.annotations.Operation operation = meta.getAnnotation(); + Operation model = new Operation(); + + String method = trim(operation.method()); + if (method != null) { + model.setHttpMethod(HttpMethods.of(method.toUpperCase())); + } + for (String tag : operation.tags()) { + model.addTag(tag); + } + return model.setSummary(trim(operation.summary())) + .setDescription(trim(operation.description())) + .setExternalDocs(toExternalDocs(operation.externalDocs())) + .setOperationId(trim(operation.operationId())) + .setDeprecated(operation.deprecated() ? Boolean.TRUE : null) + .setExtensions(toProperties(operation.extensions())); + } + + @Override + public Schema resolve(ParameterMeta parameter, Context context, Chain chain) { + return chain.resolve(parameter, context); + } + + @Override + public Boolean acceptClass(Class clazz, ParameterMeta parameter) { + AnnotationMeta schema = + parameter.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); + return schema == null ? null : !schema.getAnnotation().hidden(); + } + + @Override + public Boolean acceptProperty(BeanMeta bean, PropertyMeta property) { + AnnotationMeta schema = + property.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); + return schema == null ? null : !schema.getAnnotation().hidden(); + } +} diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java new file mode 100644 index 00000000000..d01d6de7efa --- /dev/null +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java @@ -0,0 +1,160 @@ +/* + * 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.protocol.tri.rest.support.swagger; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.io.StreamUtils; +import org.apache.dubbo.common.utils.JsonUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.HttpResult; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ConfigFactory; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequestHandler; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIService; +import org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils; +import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static java.nio.charset.StandardCharsets.UTF_8; + +@Activate +public class SwaggerUIRequestHandler implements OpenAPIRequestHandler { + + private static final String DEFAULT_CDN = "https://unpkg.com/swagger-ui-dist@5.11.0"; + private static final String INDEX_PATH = "/META-INF/resources/swagger-ui/index.html"; + + private final FrameworkModel frameworkModel; + private final ConfigFactory configFactory; + + private OpenAPIConfig config; + + public SwaggerUIRequestHandler(FrameworkModel frameworkModel) { + this.configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); + this.frameworkModel = frameworkModel; + } + + private OpenAPIConfig getConfig() { + if (config == null) { + config = configFactory.getGlobalConfig(); + } + return config; + } + + @Override + public String[] getPaths() { + return new String[] {"/swagger-ui/{*path}"}; + } + + @Override + public HttpResult handle(String path, HttpRequest request, HttpResponse response) { + String resPath = RequestUtils.getPathVariable(request, "path"); + if (StringUtils.isEmpty(resPath)) { + throw HttpResult.found(PathUtils.join(request.uri(), "index.html")).toPayload(); + } + String requestPath = StringUtils.substringBeforeLast(resPath, '.'); + switch (requestPath) { + case "index": + return handleIndex(); + case "swagger-config": + return handleSwaggerConfig(); + default: + if (requestPath.startsWith("assets/")) { + return handleSwaggerUIAssets(resPath.substring(7)); + } + } + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); + } + + private HttpResult handleIndex() { + Map variables = new HashMap<>(4); + + OpenAPIConfig config = getConfig(); + String cdn = config.getSetting("swagger-ui.cdn"); + if (cdn == null) { + if (WebjarHelper.ENABLED && WebjarHelper.getInstance().hasWebjar("swagger-ui")) { + cdn = "./assets"; + } else { + cdn = DEFAULT_CDN; + } + } + variables.put("swagger-ui.cdn", cdn); + + Map settings = config.getSettings(); + if (settings != null) { + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : settings.entrySet()) { + String key = entry.getKey(); + if (key.startsWith("swagger-ui.settings.")) { + sb.append(",\n \"") + .append(key.substring(20)) + .append("\": ") + .append(entry.getValue()); + } + } + if (sb.length() > 0) { + variables.put("swagger-ui.settings", sb.toString()); + } + } + + try { + String content = StreamUtils.toString(getClass().getResourceAsStream(INDEX_PATH)); + return HttpResult.of(Helper.render(content, variables::get).getBytes(UTF_8)); + } catch (IOException e) { + throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR.getCode(), e); + } + } + + private HttpResult handleSwaggerConfig() { + Collection groups = frameworkModel.getBean(OpenAPIService.class).getOpenAPIGroups(); + List> urls = new ArrayList<>(); + for (String group : groups) { + Map url = new LinkedHashMap<>(4); + url.put("name", group); + url.put("url", "../api-docs/" + group); + urls.add(url); + } + + Map configMap = new LinkedHashMap<>(); + configMap.put("urls", urls); + return HttpResult.of(JsonUtils.toJson(configMap).getBytes(UTF_8)); + } + + private HttpResult handleSwaggerUIAssets(String path) { + if (WebjarHelper.ENABLED) { + try { + byte[] bytes = WebjarHelper.getInstance().getWebjarResource("swagger-ui", path); + if (bytes != null) { + return HttpResult.of(bytes); + } + } catch (IOException ignored) { + } + } + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); + } +} diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java new file mode 100644 index 00000000000..8d1d210fe35 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java @@ -0,0 +1,58 @@ +/* + * 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.protocol.tri.rest.support.swagger; + +import org.apache.dubbo.common.io.StreamUtils; +import org.apache.dubbo.common.utils.ClassUtils; + +import java.io.IOException; +import java.io.InputStream; + +import org.webjars.WebJarVersionLocator; + +public class WebjarHelper { + + public static final boolean ENABLED = ClassUtils.isPresent("org.webjars.WebJarVersionLocator"); + private static volatile WebjarHelper INSTANCE; + private final WebJarVersionLocator locator = new WebJarVersionLocator(); + + public static WebjarHelper getInstance() { + if (INSTANCE == null) { + synchronized (WebjarHelper.class) { + if (INSTANCE == null) { + INSTANCE = new WebjarHelper(); + } + } + } + return INSTANCE; + } + + public boolean hasWebjar(String webjar) { + return locator.version(webjar) != null; + } + + public byte[] getWebjarResource(String webjar, String exactPath) throws IOException { + String fullPath = locator.fullPath(webjar, exactPath); + if (fullPath != null) { + InputStream is = WebJarVersionLocator.class.getClassLoader().getResourceAsStream(fullPath); + if (is != null) { + return StreamUtils.readBytes(is); + } + } + return null; + } +} diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension new file mode 100644 index 00000000000..a277affaf7e --- /dev/null +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension @@ -0,0 +1,2 @@ +resolver-swagger=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerOpenAPIDefinitionResolver +handler-swagger-ui=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerUIRequestHandler diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/swagger-ui/index.html b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/swagger-ui/index.html new file mode 100644 index 00000000000..e0675341b44 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/swagger-ui/index.html @@ -0,0 +1,51 @@ + + + + + Swagger UI + + + + + + + +

+ + + + + + diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/BinaryCodecFactory.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/BinaryCodecFactory.java index 354f0c17fb3..ec12d56bfdf 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/BinaryCodecFactory.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/BinaryCodecFactory.java @@ -38,4 +38,9 @@ public HttpMessageCodec createCodec(URL url, FrameworkModel frameworkModel, Stri public MediaType mediaType() { return MediaType.APPLICATION_OCTET_STREAM; } + + @Override + public boolean supports(String mediaType) { + return mediaType.startsWith(MediaType.APPLICATION_OCTET_STREAM.getName()) || mediaType.startsWith("image/"); + } } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory b/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory index 806a3cd1825..bbed05cd1cd 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory @@ -4,3 +4,4 @@ yaml=org.apache.dubbo.remoting.http12.message.codec.YamlCodecFactory xml=org.apache.dubbo.remoting.http12.message.codec.XmlCodecFactory html=org.apache.dubbo.remoting.http12.message.codec.HtmlCodecFactory plaintext=org.apache.dubbo.remoting.http12.message.codec.PlainTextCodecFactory +binary=org.apache.dubbo.remoting.http12.message.codec.BinaryCodecFactory diff --git a/dubbo-rpc/dubbo-rpc-triple/pom.xml b/dubbo-rpc/dubbo-rpc-triple/pom.xml index 929b7944441..dbd8b3fbc69 100644 --- a/dubbo-rpc/dubbo-rpc-triple/pom.xml +++ b/dubbo-rpc/dubbo-rpc-triple/pom.xml @@ -148,7 +148,7 @@ org.apache.dubbo dubbo-maven-plugin - ${project.version} + 3.3.2 diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java index ce00cb1a278..69b3a982a98 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java @@ -171,7 +171,18 @@ private String getMediaTypeByExtension(String extension) { for (String ext : new String[] {"txt", "md", "csv", "log", "properties"}) { extensionMapping.put(ext, MediaType.TEXT_PLAIN); } - + for (String ext : new String[] {"jpg", "jpeg", "png", "gif", "bmp", "svg", "webp", "tiff", "ico", "heif"}) { + extensionMapping.put(ext, new MediaType("image", ext)); + } + for (String ext : new String[] {"zip", "gz", "7z", "tar", "rar"}) { + extensionMapping.put(ext, MediaType.APPLICATION_OCTET_STREAM); + } + for (String ext : new String[] {"xls", "xlsx", "doc", "docx", "ppt", "pptx", "pdf"}) { + extensionMapping.put(ext, MediaType.APPLICATION_OCTET_STREAM); + } + for (String ext : new String[] {"mp3", "m4a", "mp4", "avi", "flv"}) { + extensionMapping.put(ext, MediaType.APPLICATION_OCTET_STREAM); + } this.extensionMapping = extensionMapping; } MediaType mediaType = extensionMapping.get(extension); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java index 7690dd110c6..235eb552c3a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java @@ -297,6 +297,14 @@ private void matchRecursive( private static void addMatch(Node node, Map variableMap, List> matches) { List> values = node.values; if (values.isEmpty()) { + if (node.fuzzyChildren.isEmpty()) { + return; + } + for (Entry> entry : node.fuzzyChildren.entrySet()) { + if (entry.getKey().getType() == Type.WILDCARD_TAIL) { + addMatch(entry.getValue(), variableMap, matches); + } + } return; } variableMap = variableMap.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(variableMap); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java index 1e93684ebdd..e24ae2cc9dc 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java @@ -26,7 +26,7 @@ public class NamedValueMeta { - public static final NamedValueMeta EMPTY = new NamedValueMeta(false, null); + public static final NamedValueMeta EMPTY = new NamedValueMeta(false); private String name; private final boolean required; @@ -50,12 +50,24 @@ public NamedValueMeta(String name, boolean required, String defaultValue) { this.defaultValue = defaultValue; } + public NamedValueMeta(String name, boolean required) { + this.name = name; + this.required = required; + this.defaultValue = null; + } + public NamedValueMeta(boolean required, String defaultValue) { name = null; this.required = required; this.defaultValue = defaultValue; } + public NamedValueMeta(boolean required) { + name = null; + this.required = required; + this.defaultValue = null; + } + public String name() { if (name == null) { throw new RestException(Messages.ARGUMENT_NAME_MISSING, type); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index d8172b3a3a8..4cf8ffab59d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; import org.apache.dubbo.common.utils.LRUCache; import org.apache.dubbo.common.utils.Pair; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.remoting.http12.HttpResult; @@ -37,18 +38,22 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; import java.lang.ref.SoftReference; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.IdentityHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -103,11 +108,7 @@ public HttpResult handle(String path, HttpRequest httpRequest, HttpResponse h OpenAPIRequest request = httpRequest.attribute(OpenAPIRequest.class.getName()); String group = RequestUtils.getPathVariable(httpRequest, "group"); if (group != null) { - int index = group.lastIndexOf('.'); - if (index > 0) { - group = group.substring(0, index); - } - request.setGroup(group); + request.setGroup(StringUtils.substringBeforeLast(group, '.')); } return HttpResult.builder() .contentType(MediaType.APPLICATION + '/' + request.getFormat()) @@ -115,8 +116,28 @@ public HttpResult handle(String path, HttpRequest httpRequest, HttpResponse h .build(); } + @Override + public Collection getOpenAPIGroups() { + Set groups = new LinkedHashSet<>(); + groups.add(Constants.DEFAULT_GROUP); + for (OpenAPI openAPI : getOpenAPIs()) { + groups.add(openAPI.getGroup()); + openAPI.walkOperations(operation -> { + String group = operation.getGroup(); + if (StringUtils.isNotEmpty(group)) { + groups.add(group); + } + }); + } + return groups; + } + @Override public OpenAPI getOpenAPI(OpenAPIRequest request) { + return definitionFilter.filter(definitionMerger.merge(getOpenAPIs(), request), request); + } + + private List getOpenAPIs() { if (openAPIs == null) { synchronized (this) { if (openAPIs == null) { @@ -124,7 +145,7 @@ public OpenAPI getOpenAPI(OpenAPIRequest request) { } } } - return definitionFilter.filter(definitionMerger.merge(openAPIs, request), request); + return openAPIs; } private List resolveOpenAPIs() { @@ -160,7 +181,12 @@ public String getDocument(OpenAPIRequest request) { } String path = RequestUtils.getPathVariable(httpRequest, "path"); - path = path == null ? API_DOCS : '/' + path; + if (StringUtils.isEmpty(path)) { + throw HttpResult.found(PathUtils.join(httpRequest.uri(), "swagger-ui/index.html")) + .toPayload(); + } + + path = '/' + path; List> matches = tree.matchRelaxed(path); if (matches.isEmpty()) { throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index 321b4caca7e..57229028786 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -52,7 +52,6 @@ import java.util.Objects; import java.util.Set; import java.util.TreeMap; -import java.util.function.Consumer; final class DefinitionMerger { @@ -338,30 +337,24 @@ private void mergePath(String path, PathItem pathItem, PathItem from, String gro Map fromOperations = from.getOperations(); if (fromOperations != null) { - Map operations = pathItem.getOperations(); - if (operations == null) { - pathItem.setOperations(Node.clone(fromOperations)); - } else { - for (Entry entry : fromOperations.entrySet()) { - HttpMethods httpMethod = entry.getKey(); - Operation fromOperation = entry.getValue(); - - if (isGroupNotMatch(group, fromOperation.getGroup()) - || isVersionNotMatch(version, fromOperation.getVersion()) - || isTagNotMatch(tags, fromOperation.getTags())) { - continue; - } + for (Entry entry : fromOperations.entrySet()) { + HttpMethods httpMethod = entry.getKey(); + Operation fromOperation = entry.getValue(); + if (isGroupNotMatch(group, fromOperation.getGroup()) + || isVersionNotMatch(version, fromOperation.getVersion()) + || isTagNotMatch(tags, fromOperation.getTags())) { + continue; + } - Operation operation = operations.get(httpMethod); - if (operation == null) { - operations.put(httpMethod, fromOperation.clone()); - } else if (operation.getMeta() != null) { - LOG.internalWarn( - "Operation already exists, path='{}', httpMethod='{}', method={}", - path, - httpMethod, - fromOperation.getMeta()); - } + Operation operation = pathItem.getOperation(httpMethod); + if (operation == null) { + pathItem.addOperation(httpMethod, fromOperation.clone()); + } else if (operation.getMeta() != null) { + LOG.internalWarn( + "Operation already exists, path='{}', httpMethod='{}', method={}", + path, + httpMethod, + fromOperation.getMeta()); } } } @@ -621,7 +614,7 @@ private void completeOperations(OpenAPI api) { } Set operationIds = new HashSet<>(32); - walkOperations(api, operation -> { + api.walkOperations(operation -> { String operationId = operation.getOperationId(); if (operationId != null) { operationIds.add(operationId); @@ -629,7 +622,7 @@ private void completeOperations(OpenAPI api) { }); OpenAPINamingStrategy strategy = getNamingStrategy(); - walkOperations(api, operation -> { + api.walkOperations(operation -> { String id = operation.getOperationId(); if (id != null) { return; @@ -647,22 +640,6 @@ private void completeOperations(OpenAPI api) { }); } - private static void walkOperations(OpenAPI api, Consumer consumer) { - Map paths = api.getPaths(); - if (paths == null) { - return; - } - - for (PathItem pathItem : paths.values()) { - Map operations = pathItem.getOperations(); - if (operations != null) { - for (Operation operation : operations.values()) { - consumer.accept(operation); - } - } - } - } - private void completeModel(OpenAPI api) { Info info = api.getInfo(); if (info.getTitle() == null) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index 8b992875e34..a25e3977b93 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -94,10 +94,8 @@ public OpenAPI resolve(ServiceMeta serviceMeta, Collection> r openAPI.setMeta(serviceMeta); String service = serviceMeta.getServiceInterface(); - int index = service.lastIndexOf('.'); - openAPI.addTag(new Tag() - .setName(index > 0 ? service.substring(index + 1) : service) - .setDescription(service)); + openAPI.addTag( + new Tag().setName(StringUtils.substringAfterLast(service, '.')).setDescription(service)); ResolveContext context = new ResolveContextImpl(openAPI, schemaFactory, extensionFactory); for (List registrations : registrationsByMethod) { @@ -197,9 +195,22 @@ private void resolveOperation( OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) { + if (operation.getGroup() == null) { + operation.setGroup(openAPI.getGroup()); + } if (operation.getDeprecated() == null && meta.isHierarchyAnnotated(Deprecated.class)) { operation.setDeprecated(true); } + ServiceMeta serviceMeta = meta.getServiceMeta(); + if (serviceMeta.getServiceVersion() != null) { + operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_GROUP.getName(), In.HEADER) + .setSchema(PrimitiveSchema.STRING.newSchema())); + } + if (serviceMeta.getServiceGroup() != null) { + operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_VERSION.getName(), In.HEADER) + .setSchema(PrimitiveSchema.STRING.newSchema())); + } + operation.addTag(StringUtils.substringAfterLast(serviceMeta.getServiceInterface(), '.')); for (int i = 0, len = path.length(), start = 0; i < len; i++) { char c = path.charAt(i); @@ -220,19 +231,6 @@ private void resolveOperation( } } - ServiceMeta serviceMeta = meta.getServiceMeta(); - if (serviceMeta.getServiceVersion() != null) { - operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_GROUP.getName(), In.HEADER) - .setSchema(PrimitiveSchema.STRING.newSchema())); - } - if (serviceMeta.getServiceGroup() != null) { - operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_VERSION.getName(), In.HEADER) - .setSchema(PrimitiveSchema.STRING.newSchema())); - } - String service = serviceMeta.getServiceInterface(); - int index = service.lastIndexOf('.'); - operation.addTag(index > 0 ? service.substring(index + 1) : service); - for (ParameterMeta paramMeta : meta.getParameters()) { resolveParameter(httpMethod, operation, paramMeta, true); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java index aa5e01b5e57..01d9d97d612 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java @@ -19,8 +19,12 @@ import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import java.util.Collection; + public interface OpenAPIService { + Collection getOpenAPIGroups(); + OpenAPI getOpenAPI(OpenAPIRequest request); String getDocument(OpenAPIRequest request); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java index 06eac439c85..14941784e6a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java @@ -65,8 +65,10 @@ public void removeExtension(String name) { } } - public void setExtensions(Map extensions) { + @SuppressWarnings("unchecked") + public T setExtensions(Map extensions) { this.extensions = new LinkedHashMap<>(extensions); + return (T) this; } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java index 82126a44709..1846f56a4fb 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi.model; import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; @@ -25,6 +26,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Function; public final class OpenAPI extends Node { @@ -238,6 +240,22 @@ public String getConfigSetting(String key) { return getConfigValue(config -> config == null ? null : config.getSetting(key)); } + public void walkOperations(Consumer consumer) { + Map paths = this.paths; + if (paths == null) { + return; + } + + for (PathItem pathItem : paths.values()) { + Map operations = pathItem.getOperations(); + if (operations != null) { + for (Operation operation : operations.values()) { + consumer.accept(operation); + } + } + } + } + public ServiceMeta getMeta() { return meta; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java index 96a5ceaf494..9b54f1df7bf 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java @@ -136,7 +136,7 @@ private static final class FallbackNamedValueMeta extends NamedValueMeta { private final int paramCount; FallbackNamedValueMeta(boolean required, boolean noBodyParam, int paramCount) { - super(required, null); + super(required); this.noBodyParam = noBodyParam; this.paramCount = paramCount; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/GRequestArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/GRequestArgumentResolver.java index 7651892c6b5..be02a800c40 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/GRequestArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/GRequestArgumentResolver.java @@ -22,15 +22,18 @@ import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.remoting.http12.exception.DecodeException; import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.argument.AnnotationBaseArgumentResolver; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.stub.annotations.GRequest; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.annotation.Annotation; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -43,6 +46,11 @@ public Class accept() { return GRequest.class; } + @Override + public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { + return new NamedValueMeta(null, false, ParamType.Body); + } + @Override public Object resolve( ParameterMeta parameter, AnnotationMeta annotation, HttpRequest request, HttpResponse response) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java index 6213561a74d..621d0d85914 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/PathUtils.java @@ -70,6 +70,25 @@ public static boolean isDirectPath(@Nonnull String path) { return true; } + public static String join(String path1, String path2) { + if (StringUtils.isEmpty(path1)) { + return StringUtils.isEmpty(path2) ? StringUtils.EMPTY_STRING : path2; + } + if (StringUtils.isEmpty(path2)) { + return path1; + } + if (path1.charAt(path1.length() - 1) == '/') { + if (path2.charAt(0) == '/') { + return path1 + path2.substring(1); + } + return path1 + path2; + } + if (path2.charAt(0) == '/') { + return path1 + path2; + } + return path1 + '/' + path2; + } + /** * See * AntPathMatcher#combine diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/pom.xml b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/pom.xml index 31e80c0b352..45e6e4a3b68 100644 --- a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/pom.xml +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/pom.xml @@ -217,12 +217,6 @@ true - - org.springframework.boot - spring-boot-configuration-processor - true - - org.springframework.boot diff --git a/pom.xml b/pom.xml index b289e236f75..97936591e10 100644 --- a/pom.xml +++ b/pom.xml @@ -106,6 +106,7 @@ dubbo-plugin/dubbo-filter-validation dubbo-plugin/dubbo-rest-jaxrs dubbo-plugin/dubbo-rest-spring + dubbo-plugin/dubbo-rest-swagger dubbo-plugin/dubbo-triple-servlet dubbo-plugin/dubbo-triple-websocket dubbo-demo/dubbo-demo-api From 75346e8fdca62a25a7a7c713957a9ca961afbaf0 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Sat, 23 Nov 2024 09:42:18 +0800 Subject: [PATCH 12/23] A couple of bugfix --- .artifacts | 1 + .../src/main/resources/application.yml | 1 + .../dubbo/metadata/MetadataService.java | 7 +- .../dubbo/metadata/MetadataServiceV2.java | 4 +- .../jaxrs/PathParamArgumentResolver.java | 2 - dubbo-plugin/dubbo-rest-swagger/pom.xml | 6 + .../support/swagger/RedocRequestHandler.java | 119 ++++++++++++++++++ .../swagger/SwaggerUIRequestHandler.java | 9 +- ...protocol.tri.rest.openapi.OpenAPIExtension | 1 + .../META-INF/resources/redoc/index.html | 19 +++ .../dubbo/remoting/http12/rest/Mapping.java | 5 - .../dubbo/remoting/http12/rest/Param.java | 5 - .../h12/AbstractServerTransportListener.java | 4 - .../NamedValueArgumentResolverSupport.java | 2 +- .../tri/rest/mapping/ContentNegotiator.java | 2 +- .../tri/rest/mapping/meta/BeanMeta.java | 20 ++- .../tri/rest/mapping/meta/NamedValueMeta.java | 2 +- .../tri/rest/openapi/ConfigFactory.java | 2 +- .../rest/openapi/DefaultOpenAPIService.java | 2 +- .../tri/rest/openapi/DefinitionMerger.java | 30 ++++- .../tri/rest/openapi/DefinitionResolver.java | 2 +- .../rpc/protocol/tri/rest/openapi/Helper.java | 18 ++- .../protocol/tri/rest/openapi/model/Node.java | 3 +- .../DubboListenerAutoConfiguration.java | 2 +- 24 files changed, 221 insertions(+), 47 deletions(-) create mode 100644 dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java create mode 100644 dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/redoc/index.html diff --git a/.artifacts b/.artifacts index b368e56ee7f..2abca0fd4ef 100644 --- a/.artifacts +++ b/.artifacts @@ -112,5 +112,6 @@ dubbo-xds dubbo-plugin-loom dubbo-rest-jaxrs dubbo-rest-spring +dubbo-rest-swagger dubbo-triple-servlet dubbo-triple-websocket diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml index 0f2a5571c7e..525f7b03353 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml @@ -28,6 +28,7 @@ dubbo: triple: rest: openapi: + enabled: true cache: false schema-flatten: false servlet: diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java index e645771afef..30601253a2f 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataService.java @@ -40,7 +40,7 @@ * 1. The Consumer queries the metadata information of the Provider to list the interfaces and each interface's configuration * 2. The Console (dubbo-admin) queries for the metadata of a specific process, or aggregate data of all processes. */ -@OpenAPI(group = "metadata") +@OpenAPI(hidden = "true") public interface MetadataService { /** @@ -205,6 +205,7 @@ static boolean isMetadataService(String interfaceName) { * @param instanceMetadata {@link Map} of provider Service Instance Metadata * @since 3.0 */ + @Mapping(enabled = false) void exportInstanceMetadata(String instanceMetadata); /** @@ -216,6 +217,7 @@ static boolean isMetadataService(String interfaceName) { * @return {@link Map} of {@link InstanceMetadataChangedListener} * @since 3.0 */ + @Mapping(enabled = false) Map getInstanceMetadataChangedListenerMap(); /** @@ -230,11 +232,12 @@ static boolean isMetadataService(String interfaceName) { * @return {@link Map} of provider Service Instance Metadata * @since 3.0 */ + @Mapping(enabled = false) String getAndListenInstanceMetadata(String consumerId, InstanceMetadataChangedListener listener); /** * 1. Get the openAPI definition */ - @Mapping(path = {"getOpenAPI", "//${" + H2_SETTINGS_OPENAPI_PREFIX + ".path:dubbo/openapi}/{*path}"}) + @Mapping("//${" + H2_SETTINGS_OPENAPI_PREFIX + ".path:dubbo/openapi}/{*path}") String getOpenAPI(OpenAPIRequest request); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java index 89e43d0b2d3..e938b3c2b15 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java @@ -16,11 +16,11 @@ */ package org.apache.dubbo.metadata; -import org.apache.dubbo.remoting.http12.rest.OpenAPI; +import org.apache.dubbo.remoting.http12.rest.Mapping; import java.util.concurrent.CompletableFuture; -@OpenAPI(group = "metadata") +@Mapping(enabled = false) public interface MetadataServiceV2 extends org.apache.dubbo.rpc.model.DubboStub { String JAVA_SERVICE_NAME = "org.apache.dubbo.metadata.MetadataServiceV2"; diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java index f87df32f8ff..8a18b14e6aa 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java @@ -36,8 +36,6 @@ @Activate(onClass = "javax.ws.rs.PathParam") public class PathParamArgumentResolver implements AnnotationBaseArgumentResolver { - private NamedValueMeta namedValueMeta; - @Override public Class accept() { return Annotations.PathParam.type(); diff --git a/dubbo-plugin/dubbo-rest-swagger/pom.xml b/dubbo-plugin/dubbo-rest-swagger/pom.xml index c1900eab817..ab779a0d370 100644 --- a/dubbo-plugin/dubbo-rest-swagger/pom.xml +++ b/dubbo-plugin/dubbo-rest-swagger/pom.xml @@ -29,6 +29,7 @@ 2.2.25 5.18.2 + 2.2.0 1.0.0 @@ -49,6 +50,11 @@ swagger-ui ${swagger-ui.version} + + org.webjars + redoc + 2.1.5 + org.webjars webjars-locator-lite diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java new file mode 100644 index 00000000000..1e41d20c9ce --- /dev/null +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java @@ -0,0 +1,119 @@ +/* + * 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.protocol.tri.rest.support.swagger; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.io.StreamUtils; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.OpenAPIConfig; +import org.apache.dubbo.remoting.http12.HttpRequest; +import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.HttpResult; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ConfigFactory; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequestHandler; +import org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils; +import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static java.nio.charset.StandardCharsets.UTF_8; + +@Activate +public class RedocRequestHandler implements OpenAPIRequestHandler { + + private static final String DEFAULT_CDN = "https://cdn.redoc.ly/redoc/latest/bundles"; + private static final String INDEX_PATH = "/META-INF/resources/redoc/index.html"; + + private final ConfigFactory configFactory; + + private OpenAPIConfig config; + + public RedocRequestHandler(FrameworkModel frameworkModel) { + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); + } + + private OpenAPIConfig getConfig() { + if (config == null) { + config = configFactory.getGlobalConfig(); + } + return config; + } + + @Override + public String[] getPaths() { + return new String[] {"/redoc/{*path}"}; + } + + @Override + public HttpResult handle(String path, HttpRequest request, HttpResponse response) { + String resPath = RequestUtils.getPathVariable(request, "path"); + if (StringUtils.isEmpty(resPath)) { + throw HttpResult.found(PathUtils.join(request.path(), "index.html")).toPayload(); + } + String requestPath = StringUtils.substringBeforeLast(resPath, '.'); + if (requestPath.equals("index")) { + return handleIndex(request.parameter("group", Constants.DEFAULT_GROUP)); + } else if (requestPath.startsWith("assets/")) { + return handleSwaggerUIAssets(resPath.substring(7)); + } + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); + } + + private HttpResult handleIndex(String group) { + Map variables = new HashMap<>(4); + + OpenAPIConfig config = getConfig(); + String cdn = config.getSetting("redoc.cdn"); + if (cdn == null) { + if (WebjarHelper.ENABLED && WebjarHelper.getInstance().hasWebjar("redoc")) { + cdn = "./assets"; + } else { + cdn = DEFAULT_CDN; + } + } + variables.put("redoc.cdn", cdn); + variables.put("group", group); + try { + String content = StreamUtils.toString(getClass().getResourceAsStream(INDEX_PATH)); + return HttpResult.of(Helper.render(content, variables::get).getBytes(UTF_8)); + } catch (IOException e) { + throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR.getCode(), e); + } + } + + private HttpResult handleSwaggerUIAssets(String path) { + if (WebjarHelper.ENABLED) { + try { + byte[] bytes = WebjarHelper.getInstance().getWebjarResource("redoc", path); + if (bytes != null) { + return HttpResult.builder() + .header("Cache-Control", "public, max-age=604800") + .body(bytes) + .build(); + } + } catch (IOException ignored) { + } + } + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); + } +} diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java index d01d6de7efa..3989b10969b 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java @@ -46,7 +46,7 @@ @Activate public class SwaggerUIRequestHandler implements OpenAPIRequestHandler { - private static final String DEFAULT_CDN = "https://unpkg.com/swagger-ui-dist@5.11.0"; + private static final String DEFAULT_CDN = "https://unpkg.com/swagger-ui-dist@5.18.2"; private static final String INDEX_PATH = "/META-INF/resources/swagger-ui/index.html"; private final FrameworkModel frameworkModel; @@ -55,8 +55,8 @@ public class SwaggerUIRequestHandler implements OpenAPIRequestHandler { private OpenAPIConfig config; public SwaggerUIRequestHandler(FrameworkModel frameworkModel) { - this.configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); this.frameworkModel = frameworkModel; + configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); } private OpenAPIConfig getConfig() { @@ -150,7 +150,10 @@ private HttpResult handleSwaggerUIAssets(String path) { try { byte[] bytes = WebjarHelper.getInstance().getWebjarResource("swagger-ui", path); if (bytes != null) { - return HttpResult.of(bytes); + return HttpResult.builder() + .header("Cache-Control", "public, max-age=604800") + .body(bytes) + .build(); } } catch (IOException ignored) { } diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension index a277affaf7e..90c9903e907 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension @@ -1,2 +1,3 @@ resolver-swagger=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerOpenAPIDefinitionResolver handler-swagger-ui=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerUIRequestHandler +handler-redoc=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.RedocRequestHandler diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/redoc/index.html b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/redoc/index.html new file mode 100644 index 00000000000..beed72b1acb --- /dev/null +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/redoc/index.html @@ -0,0 +1,19 @@ + + + + Redoc + + + + + + + + + + diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java index 6f3171d4fe4..f42e11768f3 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Mapping.java @@ -47,11 +47,6 @@ */ String[] value() default {}; - /** - * A title to explain the purpose of the mapping. - **/ - String title() default ""; - /** * Specifies the path patterns to be mapped. * If not specified, the method or class name is used as the default. diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Param.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Param.java index 0ee100a8e21..108dfd44db6 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Param.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/Param.java @@ -45,11 +45,6 @@ */ String value() default ""; - /** - * A title to explain the purpose of the param. - **/ - String title() default ""; - /** * The type of the parameter, such as query, header, or path variable. * Defaults to {@link ParamType#Param}. diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java index be153abd880..15ef4a0fc6e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java @@ -62,7 +62,6 @@ public abstract class AbstractServerTransportListener
headerFilters; private Executor executor; private HEADER httpMetadata; @@ -75,9 +74,6 @@ protected AbstractServerTransportListener(FrameworkModel frameworkModel, URL url this.httpChannel = httpChannel; requestRouter = frameworkModel.getOrRegisterBean(DefaultRequestRouter.class); exceptionCustomizerWrapper = new ExceptionCustomizerWrapper(frameworkModel); - headerFilters = frameworkModel - .getExtensionLoader(HeaderFilter.class) - .getActivateExtension(url, CommonConstants.HEADER_FILTER_KEY); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java index 2b914708d69..e41ab3a37f3 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java @@ -72,7 +72,7 @@ protected final NamedValueMeta updateNamedValueMeta(ParameterMeta parameter, Nam } else { meta.setNestedTypes(TypeUtils.getNestedActualTypes(meta.genericType())); } - meta.setParameterMeta(parameter); + meta.setParameter(parameter); return meta; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java index 69b3a982a98..efa3b7ca05a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/ContentNegotiator.java @@ -171,7 +171,7 @@ private String getMediaTypeByExtension(String extension) { for (String ext : new String[] {"txt", "md", "csv", "log", "properties"}) { extensionMapping.put(ext, MediaType.TEXT_PLAIN); } - for (String ext : new String[] {"jpg", "jpeg", "png", "gif", "bmp", "svg", "webp", "tiff", "ico", "heif"}) { + for (String ext : new String[] {"jpg", "jpeg", "png", "gif", "bmp", "svg", "webp", "tiff", "ico"}) { extensionMapping.put(ext, new MediaType("image", ext)); } for (String ext : new String[] {"zip", "gz", "7z", "tar", "rar"}) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java index fb308562ff9..ee26c15f075 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java @@ -17,7 +17,6 @@ package org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta; import org.apache.dubbo.common.utils.ClassUtils; -import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.remoting.http12.rest.Param; import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; @@ -34,7 +33,6 @@ import java.lang.reflect.Parameter; import java.lang.reflect.Type; import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; @@ -103,8 +101,11 @@ public PropertyMeta getProperty(String name) { } private Map getPropertiesMap() { + Map propertyMap = this.propertyMap; if (propertyMap == null) { - propertyMap = resolvePropertyMap(getToolKit(), getPrefix(), type, flatten); + propertyMap = new LinkedHashMap<>(); + resolvePropertyMap(getToolKit(), getPrefix(), type, flatten, propertyMap); + this.propertyMap = propertyMap; } return propertyMap; } @@ -130,10 +131,10 @@ public static ConstructorMeta resolveConstructor(RestToolKit toolKit, String pre return new ConstructorMeta(toolKit, prefix, ct); } - public static Map resolvePropertyMap( - RestToolKit toolKit, String prefix, Class type, boolean flatten) { + public static void resolvePropertyMap( + RestToolKit toolKit, String prefix, Class type, boolean flatten, Map propertyMap) { if (type == null || type == Object.class || TypeUtils.isSystemType(type)) { - return Collections.emptyMap(); + return; } Set pbFields = null; @@ -200,7 +201,6 @@ public static Map resolvePropertyMap( } } - Map properties = CollectionUtils.newLinkedHashMap(allNames.size()); for (String name : allNames) { Field field = fieldMap.get(name); Method getMethod = getMethodMap.get(name); @@ -209,14 +209,12 @@ public static Map resolvePropertyMap( ? (setMethod == null ? 0 : 1) << 2 | (getMethod == null ? 0 : 1) << 1 | (field == null ? 0 : 1) : 0b011; PropertyMeta meta = new PropertyMeta(toolKit, field, getMethod, setMethod, prefix, name, visibility); - properties.put(meta.getName(), meta); + propertyMap.put(meta.getName(), meta); } if (flatten) { - resolvePropertyMap(toolKit, prefix, type.getSuperclass(), flatten); + resolvePropertyMap(toolKit, prefix, type.getSuperclass(), true, propertyMap); } - - return properties; } private static String toName(String name, int index) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java index e24ae2cc9dc..6cfaf12421a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java @@ -135,7 +135,7 @@ public ParameterMeta parameter() { return parameter; } - public void setParameterMeta(ParameterMeta parameter) { + public void setParameter(ParameterMeta parameter) { this.parameter = parameter; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java index 25c5d04fe4a..553fc0d0f4d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java @@ -44,7 +44,7 @@ public ConfigFactory(FrameworkModel frameworkModel) { public static boolean isOpenAPIEnabled(FrameworkModel frameworkModel) { Environment environment = getEnvironment(frameworkModel); - return environment.getConfiguration().getBoolean(H2_SETTINGS_OPENAPI_PREFIX + ".enabled", true); + return environment.getConfiguration().getBoolean(H2_SETTINGS_OPENAPI_PREFIX + ".enabled", false); } private static Environment getEnvironment(FrameworkModel frameworkModel) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index 4cf8ffab59d..1346b411550 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -182,7 +182,7 @@ public String getDocument(OpenAPIRequest request) { String path = RequestUtils.getPathVariable(httpRequest, "path"); if (StringUtils.isEmpty(path)) { - throw HttpResult.found(PathUtils.join(httpRequest.uri(), "swagger-ui/index.html")) + throw HttpResult.found(PathUtils.join(httpRequest.path(), "swagger-ui/index.html")) .toPayload(); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index 57229028786..71749300be2 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -47,6 +47,7 @@ import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -97,6 +98,7 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { if (group == null) { group = Constants.DEFAULT_GROUP; } + model.setGroup(group); if (version != null) { info.setVersion(version); } @@ -613,11 +615,16 @@ private void completeOperations(OpenAPI api) { return; } - Set operationIds = new HashSet<>(32); + Set allOperationIds = new HashSet<>(32); + Set allTags = new HashSet<>(32); api.walkOperations(operation -> { String operationId = operation.getOperationId(); if (operationId != null) { - operationIds.add(operationId); + allOperationIds.add(operationId); + } + Set tags = operation.getTags(); + if (tags != null) { + allTags.addAll(tags); } }); @@ -629,15 +636,26 @@ private void completeOperations(OpenAPI api) { } id = strategy.generateOperationId(operation.getMeta(), api); for (int i = 1; i < 100; i++) { - if (operationIds.contains(id)) { + if (allOperationIds.contains(id)) { id = strategy.resolveOperationIdConflict(i, id, operation.getMeta(), api); } else { - operationIds.add(id); + allOperationIds.add(id); break; } } operation.setOperationId(id); }); + + List tags = api.getTags(); + if (tags != null) { + ListIterator it = tags.listIterator(); + while (it.hasNext()) { + if (allTags.contains(it.next().getName())) { + continue; + } + it.remove(); + } + } } private void completeModel(OpenAPI api) { @@ -648,5 +666,9 @@ private void completeModel(OpenAPI api) { if (info.getVersion() == null) { info.setVersion("v1"); } + ExternalDocs docs = api.getExternalDocs(); + if (docs.getUrl() == null && docs.getDescription() == null) { + docs.setUrl("../redoc/index.html?group=" + api.getGroup()).setDescription("ReDoc"); + } } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index a25e3977b93..de889b2619d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -56,7 +56,7 @@ final class DefinitionResolver { - private static final FluentLogger LOG = FluentLogger.of(DefaultOpenAPIService.class); + private static final FluentLogger LOG = FluentLogger.of(DefinitionResolver.class); private final ExtensionFactory extensionFactory; private final ConfigFactory configFactory; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index da8cd481857..20d3fdc166b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -20,6 +20,7 @@ import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; import java.util.Arrays; @@ -74,7 +75,22 @@ public static Collection guessHttpMethod(MethodMeta method) { for (String[] verbs : VERBS_TABLE) { for (int i = 1, len = verbs.length; i < len; i++) { if (name.startsWith(verbs[i])) { - return Collections.singletonList(verbs[0]); + String httpMethod = verbs[0]; + if (GET.name().equals(httpMethod)) { + for (ParameterMeta parameter : method.getParameters()) { + ParamType paramType = parameter.getNamedValueMeta().paramType(); + if (paramType != null) { + switch (paramType) { + case Form: + case Part: + case Body: + return Collections.singletonList(POST.name()); + default: + } + } + } + } + return Collections.singletonList(httpMethod); } } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java index 14941784e6a..bda5bbd3a62 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java @@ -23,6 +23,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; public abstract class Node> implements Cloneable { @@ -128,7 +129,7 @@ protected static void write(Map node, String name, Object value) if (value == null || "".equals(value)) { return; } - node.put(name, value); + node.put(name, value instanceof Set ? ((Set) value).toArray() : value); } protected static void write(Map node, String name, Node value, Context context) { diff --git a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java index 02a97a1e394..7371aad446a 100644 --- a/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot-autoconfigure/src/main/java/org/apache/dubbo/spring/boot/autoconfigure/DubboListenerAutoConfiguration.java @@ -51,7 +51,7 @@ public AwaitingNonWebApplicationListener awaitingNonWebApplicationListener() { @ConditionalOnMissingBean @Bean - @ConditionalOnProperty(prefix = Constants.H2_SETTINGS_OPENAPI_PREFIX, name = "enabled", matchIfMissing = true) + @ConditionalOnProperty(prefix = Constants.H2_SETTINGS_OPENAPI_PREFIX, name = "enabled", havingValue = "true") public DubboOpenAPIExportListener dubboOpenAPIExportListener() { return new DubboOpenAPIExportListener(); } From b7fe4f01dc92473fd21bdfca25170e395b7a3b7e Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Sat, 23 Nov 2024 16:36:30 +0800 Subject: [PATCH 13/23] Refine resolver --- .../dubbo/config/nested/OpenAPIConfig.java | 2 + .../dubbo-demo-spring-boot-servlet/pom.xml | 16 + .../dubbo/springboot/demo/servlet/Animal.java | 6 + .../dubbo/springboot/demo/servlet/Cat.java | 3 + .../demo/servlet/GreeterService.java | 6 + .../dubbo/springboot/demo/servlet/Live.java | 7 + .../jaxrs/AbstractJaxrsArgumentResolver.java | 4 +- .../support/jaxrs/BodyArgumentResolver.java | 2 +- .../jaxrs/FallbackArgumentResolver.java | 5 +- .../support/jaxrs/FormArgumentResolver.java | 2 +- .../jaxrs/PathParamArgumentResolver.java | 2 +- .../AbstractSpringArgumentResolver.java | 8 +- .../spring/BindParamArgumentResolver.java | 4 +- .../spring/FallbackArgumentResolver.java | 2 +- .../MatrixVariableArgumentResolver.java | 7 +- .../spring/PathVariableArgumentResolver.java | 2 +- .../spring/RequestBodyArgumentResolver.java | 4 +- .../spring/RequestPartArgumentResolver.java | 4 +- .../spring/SpringResponseRestFilter.java | 6 +- dubbo-plugin/dubbo-rest-swagger/pom.xml | 6 + .../JavadocOpenAPIDefinitionResolver.java | 326 ++++++++++++++++++ .../SwaggerOpenAPIDefinitionResolver.java | 112 +++--- ...protocol.tri.rest.openapi.OpenAPIExtension | 1 + .../META-INF/resources/redoc/index.html | 2 +- ...bstractAnnotationBaseArgumentResolver.java | 2 +- .../NamedValueArgumentResolverSupport.java | 1 - .../rest/mapping/condition/PathParser.java | 2 +- .../rest/mapping/meta/AnnotationSupport.java | 2 +- .../tri/rest/mapping/meta/BeanMeta.java | 4 + .../tri/rest/mapping/meta/MethodMeta.java | 12 +- .../mapping/meta/MethodParameterMeta.java | 2 +- .../tri/rest/mapping/meta/NamedValueMeta.java | 59 ++-- .../tri/rest/mapping/meta/ServiceMeta.java | 2 +- .../tri/rest/openapi/AbstractContext.java | 15 +- .../protocol/tri/rest/openapi/Context.java | 5 +- .../tri/rest/openapi/ContextImpl.java | 4 +- .../tri/rest/openapi/DefinitionEncoder.java | 6 +- .../tri/rest/openapi/DefinitionFilter.java | 6 +- .../tri/rest/openapi/DefinitionMerger.java | 4 +- .../tri/rest/openapi/DefinitionResolver.java | 220 ++++++------ .../rpc/protocol/tri/rest/openapi/Helper.java | 19 + .../openapi/OpenAPIDefinitionResolver.java | 31 +- .../rest/openapi/OpenAPIRequestHandler.java | 3 +- .../rest/openapi/OpenAPISchemaPredicate.java | 8 +- .../rest/openapi/OpenAPISchemaResolver.java | 12 +- .../tri/rest/openapi/ResolveContext.java | 39 --- ...SchemaFactory.java => SchemaResolver.java} | 109 +++--- .../tri/rest/openapi/model/Schema.java | 1 - .../basic/BasicOpenAPIDefinitionResolver.java | 187 +++++----- .../basic/FallbackArgumentResolver.java | 6 +- .../basic/GRequestArgumentResolver.java | 2 +- .../support/basic/ParamArgumentResolver.java | 9 +- 52 files changed, 859 insertions(+), 452 deletions(-) create mode 100644 dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java rename dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/{SchemaFactory.java => SchemaResolver.java} (73%) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java index 4069eb061a8..db10706fba8 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -122,6 +122,8 @@ public class OpenAPIConfig implements Serializable { */ private Boolean schemaFlatten; + private String[] schemaClassFilter; + /** * The custom settings. */ diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml index 46bd5e28021..08a74147935 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml @@ -92,6 +92,13 @@ org.springframework.boot spring-boot-starter-log4j2 + + + com.github.therapi + therapi-runtime-javadoc-scribe + 0.15.0 + provided + @@ -100,6 +107,15 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-compiler-plugin + + + -parameters + + + diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java index 435f74a5fb6..07079a375fa 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java @@ -16,8 +16,14 @@ */ package org.apache.dubbo.springboot.demo.servlet; +/** + * The animal + */ public class Animal extends Live { + /** + * The name of the animal + */ private String name; private int age; diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java index ca73161871f..be97dbfcc7e 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java @@ -18,6 +18,9 @@ public class Cat extends Animal { + /** + * The length of the cat + */ private int length; public int getLength() { diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java index 1e26ff7e62d..3f279ec58e7 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java @@ -42,5 +42,11 @@ public interface GreeterService { */ StreamObserver sayHelloBiStream(StreamObserver responseObserver); + /** + * Create an animal + * @param cat the cat + * @param dog the dog + * @return the animal + */ Animal createAnimal(Cat cat, Dog dog); } diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java index c9f2316bbc8..40453e30956 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java @@ -16,9 +16,16 @@ */ package org.apache.dubbo.springboot.demo.servlet; +/** + * The live + */ public class Live { + /** + * The alive + */ private boolean alive; + private byte[] raw; public boolean isAlive() { diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/AbstractJaxrsArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/AbstractJaxrsArgumentResolver.java index e15ea565799..e51fbf0b3d5 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/AbstractJaxrsArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/AbstractJaxrsArgumentResolver.java @@ -26,7 +26,7 @@ public abstract class AbstractJaxrsArgumentResolver extends AbstractAnnotationBaseArgumentResolver { @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - return new NamedValueMeta(ann.getValue(), Helper.isRequired(param), Helper.defaultValue(param)); + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + return new NamedValueMeta(anno.getValue(), Helper.isRequired(param), Helper.defaultValue(param)); } } diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java index 31bccf43f19..441af4f6ef2 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BodyArgumentResolver.java @@ -41,7 +41,7 @@ public Class accept() { @Override public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { - return new NamedValueMeta(null, false, ParamType.Body); + return new NamedValueMeta().setParamType(ParamType.Body); } @Override diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java index e508510d483..11d88ddabef 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FallbackArgumentResolver.java @@ -41,9 +41,8 @@ public boolean accept(ParameterMeta param) { @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param) { - NamedValueMeta meta = new NamedValueMeta(param.isAnnotated(Annotations.Nonnull), Helper.defaultValue(param)); - meta.setParamType(param.isSimple() ? null : ParamType.Body); - return meta; + return new NamedValueMeta(null, param.isAnnotated(Annotations.Nonnull), Helper.defaultValue(param)) + .setParamType(param.isSimple() ? null : ParamType.Body); } @Override diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java index 7c698243073..e1fa754537b 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/FormArgumentResolver.java @@ -37,7 +37,7 @@ public Class accept() { @Override public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { - return new NamedValueMeta(null, false, ParamType.Form); + return new NamedValueMeta().setParamType(ParamType.Body); } @Override diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java index 8a18b14e6aa..e1dcc96446a 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/PathParamArgumentResolver.java @@ -43,7 +43,7 @@ public Class accept() { @Override public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { - return new NamedValueMeta(annotation.getValue(), true, ParamType.PathVariable); + return new NamedValueMeta(annotation.getValue(), true).setParamType(ParamType.PathVariable); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/AbstractSpringArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/AbstractSpringArgumentResolver.java index 5f3b89e2789..70421f7e2c2 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/AbstractSpringArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/AbstractSpringArgumentResolver.java @@ -28,9 +28,11 @@ public abstract class AbstractSpringArgumentResolver extends AbstractAnnotationBaseArgumentResolver { @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - boolean required = param.getType() != Optional.class && Helper.isRequired(ann); - return new NamedValueMeta(ann.getValue(), required, Helper.defaultValue(ann)); + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + return new NamedValueMeta( + anno.getValue(), + param.getType() != Optional.class && Helper.isRequired(anno), + Helper.defaultValue(anno)); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java index 99c2bfedcf5..e783023245c 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BindParamArgumentResolver.java @@ -42,8 +42,8 @@ protected ParamType getParamType(NamedValueMeta meta) { } @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - return new NamedValueMeta(ann.getValue(), param.isAnnotated(Annotations.Nonnull)); + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + return new NamedValueMeta(anno.getValue(), param.isAnnotated(Annotations.Nonnull)); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java index d3d28eb359a..e9e2806bea2 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/FallbackArgumentResolver.java @@ -36,7 +36,7 @@ public boolean accept(ParameterMeta param) { @Override protected NamedValueMeta createNamedValueMeta(ParameterMeta param) { - return new NamedValueMeta(param.isAnnotated(Annotations.Nonnull)); + return new NamedValueMeta(null, param.isAnnotated(Annotations.Nonnull)); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java index 3e4541504fe..b894cfde354 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/MatrixVariableArgumentResolver.java @@ -48,9 +48,12 @@ protected ParamType getParamType(NamedValueMeta meta) { } @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { return new MatrixNamedValueMeta( - ann.getValue(), Helper.isRequired(ann), Helper.defaultValue(ann), Helper.defaultValue(ann, "pathVar")); + anno.getValue(), + Helper.isRequired(anno), + Helper.defaultValue(anno), + Helper.defaultValue(anno, "pathVar")); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java index eb5cac678af..32cc2bbfc6f 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/PathVariableArgumentResolver.java @@ -43,7 +43,7 @@ public Class accept() { @Override public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { - return new NamedValueMeta(annotation.getValue(), true, ParamType.PathVariable); + return new NamedValueMeta(annotation.getValue(), true).setParamType(ParamType.PathVariable); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java index 82110a68724..9ae5a7a2158 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestBodyArgumentResolver.java @@ -44,8 +44,8 @@ protected ParamType getParamType(NamedValueMeta meta) { } @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - return new NamedValueMeta(Helper.isRequired(ann)); + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + return new NamedValueMeta(null, Helper.isRequired(anno)); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java index e557b196076..834807d0f74 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/RequestPartArgumentResolver.java @@ -45,8 +45,8 @@ protected ParamType getParamType(NamedValueMeta meta) { } @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - return new NamedValueMeta(ann.getValue(), Helper.isRequired(ann)); + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + return new NamedValueMeta(anno.getValue(), Helper.isRequired(anno)); } @Override diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java index 2d71997ad15..a354093f3f1 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringResponseRestFilter.java @@ -114,11 +114,11 @@ private Optional findSuitableExceptionHandler(ServiceMeta serviceMet } List, MethodMeta>> candidates = new ArrayList<>(); for (MethodMeta methodMeta : serviceMeta.getExceptionHandlers()) { - ExceptionHandler ann = methodMeta.getMethod().getAnnotation(ExceptionHandler.class); - if (ann == null) { + ExceptionHandler anno = methodMeta.getMethod().getAnnotation(ExceptionHandler.class); + if (anno == null) { continue; } - for (Class type : ann.value()) { + for (Class type : anno.value()) { if (type.isAssignableFrom(exType)) { candidates.add(Pair.of(type, methodMeta)); } diff --git a/dubbo-plugin/dubbo-rest-swagger/pom.xml b/dubbo-plugin/dubbo-rest-swagger/pom.xml index ab779a0d370..472b75feda6 100644 --- a/dubbo-plugin/dubbo-rest-swagger/pom.xml +++ b/dubbo-plugin/dubbo-rest-swagger/pom.xml @@ -31,6 +31,7 @@ 5.18.2 2.2.0 1.0.0 + 0.15.0 @@ -60,6 +61,11 @@ webjars-locator-lite ${webjars-locator.version} + + com.github.therapi + therapi-runtime-javadoc + ${therapi.version} + org.spockframework diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java new file mode 100644 index 00000000000..f8d3dc8c32a --- /dev/null +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java @@ -0,0 +1,326 @@ +/* + * 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.protocol.tri.rest.support.swagger; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.common.utils.LRUCache; +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta.ReturnParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; + +import java.lang.ref.WeakReference; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import com.github.therapi.runtimejavadoc.ClassJavadoc; +import com.github.therapi.runtimejavadoc.Comment; +import com.github.therapi.runtimejavadoc.CommentFormatter; +import com.github.therapi.runtimejavadoc.FieldJavadoc; +import com.github.therapi.runtimejavadoc.MethodJavadoc; +import com.github.therapi.runtimejavadoc.ParamJavadoc; +import com.github.therapi.runtimejavadoc.RuntimeJavadoc; +import com.github.therapi.runtimejavadoc.internal.MethodSignature; +import com.github.therapi.runtimejavadoc.internal.RuntimeJavadocHelper; + +@Activate(order = -10000, onClass = "com.github.therapi.runtimejavadoc.RuntimeJavadoc") +public class JavadocOpenAPIDefinitionResolver implements OpenAPIDefinitionResolver, OpenAPISchemaResolver { + + private final LRUCache, WeakReference> cache = new LRUCache<>(128); + private final CommentFormatter formatter = new CommentFormatter(); + + @Override + public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain) { + openAPI = chain.resolve(openAPI, serviceMeta); + if (openAPI == null) { + return null; + } + + Info info = openAPI.getInfo(); + if (info == null) { + openAPI.setInfo(info = new Info()); + } + + if (info.getSummary() != null || info.getDescription() != null) { + return openAPI; + } + + ClassJavadoc javadoc = getClassJavadoc(serviceMeta.getType()).javadoc; + if (javadoc.isEmpty()) { + return openAPI; + } + + populateComment(javadoc.getComment(), info::setSummary, info::setDescription); + return openAPI; + } + + @Override + public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) { + operation = chain.resolve(operation, methodMeta, ctx); + if (operation == null) { + return null; + } + + Method method = methodMeta.getMethod(); + ClassJavadocWrapper javadoc = getClassJavadoc(method.getDeclaringClass()); + if (javadoc.isEmpty()) { + return operation; + } + + if (operation.getSummary() == null && operation.getDescription() == null) { + MethodJavadoc methodJavadoc = javadoc.getMethod(method); + if (methodJavadoc != null) { + populateComment(methodJavadoc.getComment(), operation::setSummary, operation::setDescription); + } + } + + List parameters = operation.getParameters(); + if (parameters != null) { + for (Parameter parameter : parameters) { + if (parameter.getDescription() != null) { + continue; + } + + ParameterMeta meta = parameter.getMeta(); + if (!(meta instanceof MethodParameterMeta)) { + continue; + } + + populateComment(javadoc.getParameter(method, parameter.getName()), null, parameter::setDescription); + } + } + + return operation; + } + + @Override + public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain) { + Schema schema = chain.resolve(parameter, context); + if (schema == null) { + return null; + } + + if (schema.getTitle() != null || schema.getDescription() != null) { + return schema; + } + + Comment comment = null; + if (parameter instanceof MethodParameterMeta) { + MethodParameterMeta meta = (MethodParameterMeta) parameter; + Method method = meta.getMethod(); + comment = getClassJavadoc(method.getDeclaringClass()).getParameter(method, parameter.getName()); + } else if (parameter instanceof ReturnParameterMeta) { + ReturnParameterMeta meta = (ReturnParameterMeta) parameter; + Method method = meta.getMethod(); + MethodJavadoc methodJavadoc = + getClassJavadoc(method.getDeclaringClass()).getMethod(method); + if (methodJavadoc != null) { + comment = methodJavadoc.getReturns(); + } + } else { + for (AnnotatedElement element : parameter.getAnnotatedElements()) { + if (element instanceof Class) { + comment = getClassJavadoc((Class) element).getClassComment(); + } else if (element instanceof Field) { + Field field = (Field) element; + + ClassJavadocWrapper classJavadoc = getClassJavadoc(field.getDeclaringClass()); + FieldJavadoc fieldJavadoc = classJavadoc.getField(field); + if (fieldJavadoc != null) { + comment = fieldJavadoc.getComment(); + break; + } + + ParamJavadoc paramJavadoc = classJavadoc.getRecordComponent(field.getName()); + if (paramJavadoc != null) { + comment = paramJavadoc.getComment(); + break; + } + } + } + } + + populateComment(comment, schema::setTitle, schema::setDescription); + return schema; + } + + private ClassJavadocWrapper getClassJavadoc(Class clazz) { + WeakReference ref = cache.get(clazz); + ClassJavadocWrapper javadoc = ref == null ? null : ref.get(); + if (javadoc == null) { + javadoc = new ClassJavadocWrapper(RuntimeJavadoc.getJavadoc(clazz)); + cache.put(clazz, new WeakReference<>(javadoc)); + } + return javadoc; + } + + private void populateComment(Comment comment, Consumer sConsumer, Consumer dConsumer) { + if (comment == null) { + return; + } + + String description = formatter.format(comment); + if (sConsumer == null) { + dConsumer.accept(description); + return; + } + + String summary = getFirstSentence(description); + sConsumer.accept(summary); + if (description.equals(summary)) { + return; + } + dConsumer.accept(description); + } + + private static String getFirstSentence(String text) { + if (StringUtils.isEmpty(text)) { + return text; + } + int pOpenIndex = text.indexOf("

"); + int pCloseIndex = text.indexOf("

"); + int dotIndex = text.indexOf("."); + if (pOpenIndex != -1) { + if (pOpenIndex == 0 && pCloseIndex != -1) { + if (dotIndex != -1) { + return text.substring(3, Math.min(pCloseIndex, dotIndex)); + } + return text.substring(3, pCloseIndex); + } + if (dotIndex != -1) { + return text.substring(0, Math.min(pOpenIndex, dotIndex)); + } + return text.substring(0, pOpenIndex); + } + if (dotIndex != -1 && text.length() != dotIndex + 1 && Character.isWhitespace(text.charAt(dotIndex + 1))) { + return text.substring(0, dotIndex + 1); + } + return text; + } + + private static final class ClassJavadocWrapper { + + private static final Map MAPPING = new LinkedHashMap<>(); + private static Field PARAMS; + + public final ClassJavadoc javadoc; + public Map fields; + public Map methods; + public Map recordComponents; + + static { + try { + Field[] fields = ClassJavadoc.class.getDeclaredFields(); + Field[] wFields = ClassJavadocWrapper.class.getFields(); + for (Field field : fields) { + field.setAccessible(true); + for (Field wField : wFields) { + if (wField.getName().equals(field.getName())) { + MAPPING.put(field, wField); + break; + } + } + } + PARAMS = MethodJavadoc.class.getDeclaredField("params"); + PARAMS.setAccessible(true); + } catch (Throwable ignored) { + } + } + + public ClassJavadocWrapper(ClassJavadoc javadoc) { + this.javadoc = javadoc; + try { + for (Map.Entry entry : MAPPING.entrySet()) { + entry.getValue().set(this, entry.getKey().get(javadoc)); + } + } catch (Throwable ignored) { + } + } + + public boolean isEmpty() { + return javadoc.isEmpty(); + } + + public Comment getClassComment() { + return javadoc.getComment(); + } + + public FieldJavadoc getField(Field field) { + if (fields == null) { + return null; + } + FieldJavadoc fieldJavadoc = fields.get(field.getName()); + return fieldJavadoc == null || fieldJavadoc.isEmpty() ? null : fieldJavadoc; + } + + public MethodJavadoc getMethod(Method method) { + if (methods == null) { + return null; + } + MethodJavadoc methodJavadoc = methods.get(MethodSignature.from(method)); + if (methodJavadoc != null && !methodJavadoc.isEmpty()) { + return methodJavadoc; + } + Method bridgeMethod = RuntimeJavadocHelper.findBridgeMethod(method); + if (bridgeMethod != null && bridgeMethod != method) { + methodJavadoc = methods.get(MethodSignature.from(bridgeMethod)); + if (methodJavadoc != null && !methodJavadoc.isEmpty()) { + return methodJavadoc; + } + } + return null; + } + + @SuppressWarnings("unchecked") + public Comment getParameter(Method method, String name) { + if (methods == null) { + return null; + } + MethodJavadoc methodJavadoc = methods.get(MethodSignature.from(method)); + if (methodJavadoc == null || PARAMS == null) { + return null; + } + try { + Map params = (Map) PARAMS.get(methodJavadoc); + ParamJavadoc paramJavadoc = params.get(name); + if (paramJavadoc != null) { + return paramJavadoc.getComment(); + } + } catch (Throwable ignored) { + } + return null; + } + + public ParamJavadoc getRecordComponent(String name) { + return recordComponents == null ? null : recordComponents.get(name); + } + } +} diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java index 8956369063c..1303836c2ac 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java @@ -28,7 +28,6 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaPredicate; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ResolveContext; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Contact; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; @@ -52,23 +51,23 @@ public final class SwaggerOpenAPIDefinitionResolver implements OpenAPIDefinitionResolver, OpenAPISchemaResolver, OpenAPISchemaPredicate { @Override - public boolean hidden(ServiceMeta serviceMeta) { - return serviceMeta.isHierarchyAnnotated(Hidden.class); - } - - @Override - public OpenAPI resolve(ServiceMeta serviceMeta) { - AnnotationMeta meta = serviceMeta.findAnnotation(OpenAPIDefinition.class); - if (meta == null) { + public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain) { + AnnotationMeta annoMeta = serviceMeta.findAnnotation(OpenAPIDefinition.class); + if (annoMeta == null) { + return chain.resolve(openAPI, serviceMeta); + } + if (serviceMeta.isHierarchyAnnotated(Hidden.class)) { return null; } - OpenAPI model = new OpenAPI(); - OpenAPIDefinition definition = meta.getAnnotation(); + OpenAPIDefinition anno = annoMeta.getAnnotation(); + + Info info = openAPI.getInfo(); + if (info == null) { + openAPI.setInfo(info = new Info()); + } - Info info = new Info(); - model.setInfo(info); - io.swagger.v3.oas.annotations.info.Info infoAnn = definition.info(); + io.swagger.v3.oas.annotations.info.Info infoAnn = anno.info(); info.setTitle(trim(infoAnn.title())) .setDescription(trim(infoAnn.description())) .setVersion(trim(infoAnn.version())) @@ -89,18 +88,18 @@ public OpenAPI resolve(ServiceMeta serviceMeta) { .setUrl(trim(licenseAnn.url())) .setExtensions(toProperties(licenseAnn.extensions())); - for (io.swagger.v3.oas.annotations.tags.Tag tagAnn : definition.tags()) { - model.addTag(new Tag() + for (io.swagger.v3.oas.annotations.tags.Tag tagAnn : anno.tags()) { + openAPI.addTag(new Tag() .setName(trim(tagAnn.name())) .setDescription(trim(tagAnn.description())) .setExternalDocs(toExternalDocs(tagAnn.externalDocs())) .setExtensions(toProperties(tagAnn.extensions()))); } - model.setExternalDocs(toExternalDocs(definition.externalDocs())); + openAPI.setExternalDocs(toExternalDocs(anno.externalDocs())); - model.setExtensions(toProperties(definition.extensions())); - return model; + openAPI.setExtensions(toProperties(anno.extensions())); + return openAPI; } private static Map toProperties(io.swagger.v3.oas.annotations.extensions.Extension[] extensions) { @@ -117,60 +116,63 @@ private static Map toProperties(io.swagger.v3.oas.annotations.ex return properties; } - private static ExternalDocs toExternalDocs(ExternalDocumentation ann) { + private static ExternalDocs toExternalDocs(ExternalDocumentation anno) { return new ExternalDocs() - .setDescription(trim(ann.description())) - .setUrl(trim(ann.url())) - .setExtensions(toProperties(ann.extensions())); + .setDescription(trim(anno.description())) + .setUrl(trim(anno.url())) + .setExtensions(toProperties(anno.extensions())); } @Override - public boolean hidden(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { - return methodMeta.isHierarchyAnnotated(Hidden.class); - } - - @Override - public Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { - AnnotationMeta meta = + public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) { + AnnotationMeta annoMeta = methodMeta.findAnnotation(io.swagger.v3.oas.annotations.Operation.class); - if (meta == null) { + if (annoMeta == null) { + return chain.resolve(operation, methodMeta, ctx); + } + io.swagger.v3.oas.annotations.Operation anno = annoMeta.getAnnotation(); + if (anno.hidden() || methodMeta.isHierarchyAnnotated(Hidden.class)) { return null; } - io.swagger.v3.oas.annotations.Operation operation = meta.getAnnotation(); - Operation model = new Operation(); - - String method = trim(operation.method()); + String method = trim(anno.method()); if (method != null) { - model.setHttpMethod(HttpMethods.of(method.toUpperCase())); + operation.setHttpMethod(HttpMethods.of(method.toUpperCase())); } - for (String tag : operation.tags()) { - model.addTag(tag); + for (String tag : anno.tags()) { + operation.addTag(tag); } - return model.setSummary(trim(operation.summary())) - .setDescription(trim(operation.description())) - .setExternalDocs(toExternalDocs(operation.externalDocs())) - .setOperationId(trim(operation.operationId())) - .setDeprecated(operation.deprecated() ? Boolean.TRUE : null) - .setExtensions(toProperties(operation.extensions())); + return operation + .setSummary(trim(anno.summary())) + .setDescription(trim(anno.description())) + .setExternalDocs(toExternalDocs(anno.externalDocs())) + .setOperationId(trim(anno.operationId())) + .setDeprecated(anno.deprecated() ? Boolean.TRUE : null) + .setExtensions(toProperties(anno.extensions())); } @Override - public Schema resolve(ParameterMeta parameter, Context context, Chain chain) { - return chain.resolve(parameter, context); - } - - @Override - public Boolean acceptClass(Class clazz, ParameterMeta parameter) { - AnnotationMeta schema = + public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain) { + AnnotationMeta meta = parameter.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); - return schema == null ? null : !schema.getAnnotation().hidden(); + if (meta == null) { + return chain.resolve(parameter, context); + } + io.swagger.v3.oas.annotations.media.Schema schema = meta.getAnnotation(); + if (schema.hidden() || parameter.isHierarchyAnnotated(Hidden.class)) { + return null; + } + return chain.resolve(parameter, context); } @Override public Boolean acceptProperty(BeanMeta bean, PropertyMeta property) { - AnnotationMeta schema = - property.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); - return schema == null ? null : !schema.getAnnotation().hidden(); + AnnotationMeta meta = + bean.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); + if (meta == null) { + return null; + } + io.swagger.v3.oas.annotations.media.Schema schema = meta.getAnnotation(); + return schema.hidden() || bean.isHierarchyAnnotated(Hidden.class) ? false : null; } } diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension index 90c9903e907..68c769ce618 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension @@ -1,3 +1,4 @@ resolver-swagger=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerOpenAPIDefinitionResolver +resolver-javadoc=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.JavadocOpenAPIDefinitionResolver handler-swagger-ui=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerUIRequestHandler handler-redoc=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.RedocRequestHandler diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/redoc/index.html b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/redoc/index.html index beed72b1acb..7fa9aab01d5 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/redoc/index.html +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/redoc/index.html @@ -13,7 +13,7 @@ - + diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java index 74564d22e57..9a980a1da7e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/AbstractAnnotationBaseArgumentResolver.java @@ -41,5 +41,5 @@ public final NamedValueMeta getNamedValueMeta(ParameterMeta parameter, Annotatio return cache.computeIfAbsent(parameter, k -> updateNamedValueMeta(k, createNamedValueMeta(k, annotation))); } - protected abstract NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann); + protected abstract NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java index e41ab3a37f3..e5c701449b6 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/NamedValueArgumentResolverSupport.java @@ -46,7 +46,6 @@ protected final Object resolve(NamedValueMeta meta, HttpRequest request, HttpRes if (arg != null) { return filterValue(arg, meta); } - arg = meta.defaultValue(); if (arg != null) { return arg; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathParser.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathParser.java index 8add3bd99ee..b89f0ff0e32 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathParser.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathParser.java @@ -30,7 +30,7 @@ /** * See *

- * Spring uri templates + * Spring uri templates *
* Path and regular expression mappings *

diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java index 8ade26b632b..207f4244206 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/AnnotationSupport.java @@ -207,7 +207,7 @@ public final RestToolKit getToolKit() { return toolKit; } - protected List getAnnotatedElements() { + public List getAnnotatedElements() { return Collections.singletonList(getAnnotatedElement()); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java index ee26c15f075..c689c2101a9 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java @@ -190,6 +190,10 @@ public static void resolvePropertyMap( getMethodMap.put(name, method); allNames.add(name); } + } else if (fieldMap.containsKey(name)) { + // For record class + getMethodMap.put(name, method); + allNames.add(name); } } else if (count == 1) { if (name.length() > 3 && name.startsWith("set")) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java index d61363d8ade..de2328004ea 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodMeta.java @@ -136,7 +136,7 @@ public Type getActualGenericReturnType() { } @Override - protected List getAnnotatedElements() { + public List getAnnotatedElements() { return hierarchy; } @@ -210,12 +210,12 @@ protected AnnotatedElement getAnnotatedElement() { } @Override - protected List getAnnotatedElements() { + public List getAnnotatedElements() { return elements; } } - private static final class ReturnParameterMeta extends ParameterMeta { + public static final class ReturnParameterMeta extends ParameterMeta { private final List hierarchy; private final Method method; @@ -226,6 +226,10 @@ private static final class ReturnParameterMeta extends ParameterMeta { this.method = method; } + public Method getMethod() { + return method; + } + @Override public Class getType() { return method.getReturnType(); @@ -237,7 +241,7 @@ public Type getGenericType() { } @Override - protected List getAnnotatedElements() { + public List getAnnotatedElements() { return hierarchy; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodParameterMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodParameterMeta.java index e9b82cf4828..014e6130897 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodParameterMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/MethodParameterMeta.java @@ -79,7 +79,7 @@ protected AnnotatedElement getAnnotatedElement() { } @Override - protected List getAnnotatedElements() { + public List getAnnotatedElements() { return hierarchy; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java index 6cfaf12421a..cbe12e52565 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/NamedValueMeta.java @@ -26,7 +26,7 @@ public class NamedValueMeta { - public static final NamedValueMeta EMPTY = new NamedValueMeta(false); + public static final NamedValueMeta EMPTY = new NamedValueMeta(); private String name; private final boolean required; @@ -37,13 +37,6 @@ public class NamedValueMeta { private Class[] nestedTypes; private ParameterMeta parameter; - public NamedValueMeta(String name, boolean required, ParamType paramType) { - this.name = name; - this.required = required; - this.defaultValue = null; - this.paramType = paramType; - } - public NamedValueMeta(String name, boolean required, String defaultValue) { this.name = name; this.required = required; @@ -53,19 +46,12 @@ public NamedValueMeta(String name, boolean required, String defaultValue) { public NamedValueMeta(String name, boolean required) { this.name = name; this.required = required; - this.defaultValue = null; + defaultValue = null; } - public NamedValueMeta(boolean required, String defaultValue) { - name = null; - this.required = required; - this.defaultValue = defaultValue; - } - - public NamedValueMeta(boolean required) { - name = null; - this.required = required; - this.defaultValue = null; + public NamedValueMeta() { + required = false; + defaultValue = null; } public String name() { @@ -75,8 +61,9 @@ public String name() { return name; } - public void setName(String name) { + public NamedValueMeta setName(String name) { this.name = name; + return this; } public boolean isNameEmpty() { @@ -95,48 +82,53 @@ public ParamType paramType() { return paramType; } - public void setParamType(ParamType paramType) { + public NamedValueMeta setParamType(ParamType paramType) { this.paramType = paramType; + return this; } public Class type() { return type; } - public void setType(Class type) { + public NamedValueMeta setType(Class type) { this.type = type; + return this; } public Type genericType() { return genericType; } - public void setGenericType(Type genericType) { + public NamedValueMeta setGenericType(Type genericType) { this.genericType = genericType; + return this; } - public Class nestedType() { - return nestedTypes == null ? null : nestedTypes[0]; + public Class[] nestedTypes() { + return nestedTypes; } - public Class nestedType(int index) { - return nestedTypes == null || nestedTypes.length <= index ? null : nestedTypes[index]; + public NamedValueMeta setNestedTypes(Class[] nestedTypes) { + this.nestedTypes = nestedTypes; + return this; } - public Class[] nestedTypes() { - return nestedTypes; + public Class nestedType() { + return nestedTypes == null ? null : nestedTypes[0]; } - public void setNestedTypes(Class[] nestedTypes) { - this.nestedTypes = nestedTypes; + public Class nestedType(int index) { + return nestedTypes == null || nestedTypes.length <= index ? null : nestedTypes[index]; } public ParameterMeta parameter() { return parameter; } - public void setParameter(ParameterMeta parameter) { + public NamedValueMeta setParameter(ParameterMeta parameter) { this.parameter = parameter; + return this; } @Override @@ -149,6 +141,9 @@ public String toString() { if (defaultValue != null) { sb.append(", defaultValue='").append(defaultValue).append('\''); } + if (paramType != null) { + sb.append(", paramType=").append(paramType); + } if (type != null) { sb.append(", type=").append(type); if (genericType != type) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ServiceMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ServiceMeta.java index 6c45b202cb6..cbb34bf8460 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ServiceMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/ServiceMeta.java @@ -94,7 +94,7 @@ public List getExceptionHandlers() { } @Override - protected List getAnnotatedElements() { + public List getAnnotatedElements() { return hierarchy; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java index 2486f5a45f8..cc930f6def0 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; -import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import java.util.HashMap; @@ -25,14 +24,14 @@ public abstract class AbstractContext { private final OpenAPI openAPI; - private final SchemaFactory schemaFactory; + private final SchemaResolver schemaResolver; private final ExtensionFactory extensionFactory; private Map attributes; - AbstractContext(OpenAPI openAPI, SchemaFactory schemaFactory, ExtensionFactory extensionFactory) { + AbstractContext(OpenAPI openAPI, SchemaResolver schemaResolver, ExtensionFactory extensionFactory) { this.openAPI = openAPI; - this.schemaFactory = schemaFactory; + this.schemaResolver = schemaResolver; this.extensionFactory = extensionFactory; } @@ -44,12 +43,8 @@ public final OpenAPI getOpenAPI() { return openAPI; } - public final OpenAPIConfig getConfig() { - return openAPI.getConfig(); - } - - public final SchemaFactory getSchemaFactory() { - return schemaFactory; + public final SchemaResolver getSchemaResolver() { + return schemaResolver; } public final ExtensionFactory getExtensionFactory() { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java index 560b3cbee7d..30aecbb41d7 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; -import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; @@ -34,11 +33,9 @@ public interface Context { OpenAPI getOpenAPI(); - OpenAPIConfig getConfig(); - boolean isOpenAPI31(); - SchemaFactory getSchemaFactory(); + SchemaResolver getSchemaResolver(); ExtensionFactory getExtensionFactory(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java index f9e21d4d87b..8fb1cae80e6 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java @@ -31,8 +31,8 @@ final class ContextImpl extends AbstractContext implements Context { private Holder httpRequest; private Holder httpResponse; - ContextImpl(OpenAPI openAPI, SchemaFactory schemaFactory, ExtensionFactory extFactory, OpenAPIRequest request) { - super(openAPI, schemaFactory, extFactory); + ContextImpl(OpenAPI openAPI, SchemaResolver schemaResolver, ExtensionFactory extFactory, OpenAPIRequest request) { + super(openAPI, schemaResolver, extFactory); this.request = request; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java index 8555054e98b..6ae84c5cf6b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java @@ -32,13 +32,13 @@ final class DefinitionEncoder { private final ExtensionFactory extensionFactory; - private final SchemaFactory schemaFactory; + private final SchemaResolver schemaResolver; private ProtoEncoder protoEncoder; DefinitionEncoder(FrameworkModel frameworkModel) { extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); - schemaFactory = frameworkModel.getOrRegisterBean(SchemaFactory.class); + schemaResolver = frameworkModel.getOrRegisterBean(SchemaResolver.class); } public String encode(OpenAPI openAPI, OpenAPIRequest request) { @@ -46,7 +46,7 @@ public String encode(OpenAPI openAPI, OpenAPIRequest request) { openAPI = new OpenAPI(); } Map root = new LinkedHashMap<>(); - ContextImpl context = new ContextImpl(openAPI, schemaFactory, extensionFactory, request); + ContextImpl context = new ContextImpl(openAPI, schemaResolver, extensionFactory, request); openAPI.writeTo(root, context); String format = request.getFormat(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java index 3f194c68468..f9064de1afc 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java @@ -43,11 +43,11 @@ final class DefinitionFilter { private final ExtensionFactory extensionFactory; - private final SchemaFactory schemaFactory; + private final SchemaResolver schemaResolver; public DefinitionFilter(FrameworkModel frameworkModel) { extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); - schemaFactory = frameworkModel.getOrRegisterBean(SchemaFactory.class); + schemaResolver = frameworkModel.getOrRegisterBean(SchemaResolver.class); } public OpenAPI filter(OpenAPI openAPI, OpenAPIRequest request) { @@ -56,7 +56,7 @@ public OpenAPI filter(OpenAPI openAPI, OpenAPIRequest request) { return openAPI; } - Context context = new ContextImpl(openAPI, schemaFactory, extensionFactory, request); + Context context = new ContextImpl(openAPI, schemaResolver, extensionFactory, request); for (OpenAPIFilter filter : filters) { openAPI = filter.filterOpenAPI(openAPI, context); if (openAPI == null) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index 71749300be2..4820985db62 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -80,8 +80,8 @@ private OpenAPINamingStrategy getNamingStrategy() { } public OpenAPI merge(List openAPIs, OpenAPIRequest request) { - Info info = new Info(); - OpenAPI model = new OpenAPI().setInfo(info); + OpenAPI model = new OpenAPI(); + Info info = model.getInfo(); OpenAPIConfig globalConfig = configFactory.getGlobalConfig(); model.setGlobalConfig(globalConfig); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index de889b2619d..c4bc8c0b475 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -37,6 +37,9 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.NamedValueMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver.OpenAPIChain; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver.OperationChain; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver.OperationContext; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; @@ -52,6 +55,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.function.Function; import java.util.stream.Collectors; final class DefinitionResolver { @@ -60,44 +64,36 @@ final class DefinitionResolver { private final ExtensionFactory extensionFactory; private final ConfigFactory configFactory; - private final SchemaFactory schemaFactory; + private final SchemaResolver schemaResolver; private final OpenAPIDefinitionResolver[] resolvers; DefinitionResolver(FrameworkModel frameworkModel) { extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); - schemaFactory = frameworkModel.getOrRegisterBean(SchemaFactory.class); + schemaResolver = frameworkModel.getOrRegisterBean(SchemaResolver.class); resolvers = extensionFactory.getExtensions(OpenAPIDefinitionResolver.class); } public OpenAPI resolve(ServiceMeta serviceMeta, Collection> registrationsByMethod) { - OpenAPI openAPI = null; - - for (OpenAPIDefinitionResolver resolver : resolvers) { - if (resolver.hidden(serviceMeta)) { - return null; - } - openAPI = resolver.resolve(serviceMeta); - if (openAPI != null) { - break; - } - } - - if (openAPI == null) { - openAPI = new OpenAPI(); - } - if (StringUtils.isEmpty(openAPI.getGroup())) { - openAPI.setGroup(Constants.DEFAULT_GROUP); - } - openAPI.setGlobalConfig(configFactory.getGlobalConfig()); - openAPI.setConfig(configFactory.getConfig(openAPI.getGroup())); - openAPI.setMeta(serviceMeta); - - String service = serviceMeta.getServiceInterface(); - openAPI.addTag( - new Tag().setName(StringUtils.substringAfterLast(service, '.')).setDescription(service)); - - ResolveContext context = new ResolveContextImpl(openAPI, schemaFactory, extensionFactory); + OpenAPI definition = new OpenAPIChainImpl(resolvers, openAPI -> { + if (StringUtils.isEmpty(openAPI.getGroup())) { + openAPI.setGroup(Constants.DEFAULT_GROUP); + } + openAPI.setConfig(configFactory.getConfig(openAPI.getGroup())); + String service = serviceMeta.getServiceInterface(); + int index = service.lastIndexOf('.'); + String tagName = index == -1 ? service : service.substring(index + 1); + openAPI.addTag(new Tag().setName(tagName).setDescription(service)); + return openAPI; + }) + .resolve( + new OpenAPI().setMeta(serviceMeta).setGlobalConfig(configFactory.getGlobalConfig()), + serviceMeta); + if (definition == null) { + return null; + } + + OperationContext context = new OperationContextImpl(definition, schemaResolver, extensionFactory); for (List registrations : registrationsByMethod) { String mainPath = null; for (Registration registration : registrations) { @@ -108,51 +104,64 @@ public OpenAPI resolve(ServiceMeta serviceMeta, Collection> r } for (PathExpression expression : pathCondition.getExpressions()) { String path = expression.toString(); - PathItem pathItem = openAPI.getOrAddPath(path); + PathItem pathItem = definition.getOrAddPath(path); String ref = pathItem.getRef(); if (ref != null) { path = ref; - pathItem = openAPI.getOrAddPath(path); + pathItem = definition.getOrAddPath(path); } if (mainPath != null && expression.isDirect()) { pathItem.setRef(mainPath); continue; } MethodMeta methodMeta = registration.getMeta().getMethod(); - if (resolvePath(path, pathItem, openAPI, methodMeta, mapping, context)) { + if (resolvePath(path, pathItem, definition, methodMeta, mapping, context)) { mainPath = path; } } } } - return openAPI; + return definition; } private boolean resolvePath( String path, PathItem pathItem, OpenAPI openAPI, - MethodMeta meta, + MethodMeta methodMeta, RequestMapping mapping, - ResolveContext context) { - Operation operation = null; - Collection httpMethods = null; + OperationContext context) { + return new OperationChainImpl(resolvers, operation -> { + for (String method : determineHttpMethods(openAPI, methodMeta, mapping, operation)) { + HttpMethods httpMethod = HttpMethods.of(method.toUpperCase()); + Operation existingOperation = pathItem.getOperation(httpMethod); + if (existingOperation == null) { + pathItem.addOperation(httpMethod, operation); + } else { + if (existingOperation.getMeta() != null) { + LOG.internalWarn( + "Operation already exists, path='{}', httpMethod='{}', method={}", + path, + method, + methodMeta); + } + continue; + } + resolveOperation(path, httpMethod, operation, openAPI, methodMeta, mapping); + } + return operation; + }) + .resolve(new Operation().setMeta(methodMeta), methodMeta, context) + != null; + } - for (OpenAPIDefinitionResolver resolver : resolvers) { - if (resolver.hidden(meta, openAPI, context)) { - return false; - } - operation = resolver.resolve(meta, openAPI, context); - if (operation == null) { - continue; - } - if (operation.getHttpMethod() != null) { - httpMethods = - Collections.singletonList(operation.getHttpMethod().name()); - } + private Collection determineHttpMethods( + OpenAPI openAPI, MethodMeta meta, RequestMapping mapping, Operation operation) { + Collection httpMethods = null; + if (operation.getHttpMethod() != null) { + httpMethods = Collections.singletonList(operation.getHttpMethod().name()); } - if (httpMethods == null) { if (mapping.getMethodsCondition() != null) { httpMethods = mapping.getMethodsCondition().getMethods(); @@ -166,26 +175,7 @@ private boolean resolvePath( } } } - - for (String hm : httpMethods) { - HttpMethods httpMethod = HttpMethods.of(hm.toUpperCase()); - Operation existingOperation = pathItem.getOperation(httpMethod); - if (existingOperation == null) { - if (operation == null) { - operation = new Operation(); - } - pathItem.addOperation(httpMethod, operation); - } else { - if (existingOperation.getMeta() != null) { - LOG.internalWarn("Operation already exists, path='{}', httpMethod='{}', method={}", path, hm, meta); - } - continue; - } - operation.setMeta(meta); - resolveOperation(path, httpMethod, operation, openAPI, meta, mapping); - } - - return true; + return httpMethods; } private void resolveOperation( @@ -198,9 +188,13 @@ private void resolveOperation( if (operation.getGroup() == null) { operation.setGroup(openAPI.getGroup()); } + for (Tag tag : openAPI.getTags()) { + operation.addTag(tag.getName()); + } if (operation.getDeprecated() == null && meta.isHierarchyAnnotated(Deprecated.class)) { operation.setDeprecated(true); } + ServiceMeta serviceMeta = meta.getServiceMeta(); if (serviceMeta.getServiceVersion() != null) { operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_GROUP.getName(), In.HEADER) @@ -210,24 +204,19 @@ private void resolveOperation( operation.addParameter(new Parameter(TripleHeaderEnum.SERVICE_VERSION.getName(), In.HEADER) .setSchema(PrimitiveSchema.STRING.newSchema())); } - operation.addTag(StringUtils.substringAfterLast(serviceMeta.getServiceInterface(), '.')); - for (int i = 0, len = path.length(), start = 0; i < len; i++) { - char c = path.charAt(i); - if (c == '{') { - start = i + 1; - } else if (start > 0 && c == '}') { - String name = path.substring(start, i); - Parameter parameter = operation.getParameter(name, In.PATH); + List variables = Helper.extractVariables(path); + if (variables != null) { + for (String variable : variables) { + Parameter parameter = operation.getParameter(variable, In.PATH); if (parameter == null) { - parameter = new Parameter(name, In.PATH); + parameter = new Parameter(variable, In.PATH); operation.addParameter(parameter); } parameter.setRequired(true); if (parameter.getSchema() == null) { parameter.setSchema(PrimitiveSchema.STRING.newSchema()); } - start = 0; } } @@ -258,14 +247,13 @@ private void resolveOperation( } } - private void resolveParameter( - HttpMethods httpMethod, Operation operation, ParameterMeta paramMeta, boolean traverse) { - String name = paramMeta.getName(); + private void resolveParameter(HttpMethods httpMethod, Operation operation, ParameterMeta meta, boolean traverse) { + String name = meta.getName(); if (name == null) { return; } - NamedValueMeta valueMeta = paramMeta.getNamedValueMeta(); + NamedValueMeta valueMeta = meta.getNamedValueMeta(); ParamType paramType = valueMeta.paramType(); if (paramType == null) { if (httpMethod.supportBody()) { @@ -278,7 +266,7 @@ private void resolveParameter( return; } - boolean simple = paramMeta.isSimple(); + boolean simple = meta.isSimple(); if (in != In.QUERY && !simple) { return; } @@ -293,19 +281,19 @@ private void resolveParameter( } Schema schema = parameter.getSchema(); if (schema == null) { - parameter.setSchema(schema = schemaFactory.getSchema(paramMeta)); + parameter.setSchema(schema = schemaResolver.resolve(meta)); } if (schema.getDefaultValue() == null) { schema.setDefaultValue(valueMeta.defaultValue()); } - parameter.setMeta(paramMeta); + parameter.setMeta(meta); return; } if (!traverse) { return; } - BeanMeta beanMeta = paramMeta.getBeanMeta(); + BeanMeta beanMeta = meta.getBeanMeta(); try { for (ParameterMeta ctorParam : beanMeta.getConstructor().getParameters()) { resolveParameter(httpMethod, operation, ctorParam, false); @@ -341,7 +329,7 @@ private void resolveRequestBody(RequestBody body, OpenAPI openAPI, MethodMeta me for (ParameterMeta paramMeta : meta.getParameters()) { ParamType paramType = paramMeta.getNamedValueMeta().paramType(); if (paramType == ParamType.Body) { - content.setSchema(schemaFactory.getSchema(paramMeta)); + content.setSchema(schemaResolver.resolve(paramMeta)); continue out; } } @@ -357,9 +345,9 @@ private void resolveRequestBody(RequestBody body, OpenAPI openAPI, MethodMeta me continue; } if (size == 1) { - content.setSchema(schemaFactory.getSchema(paramMetas.get(0))); + content.setSchema(schemaResolver.resolve(paramMetas.get(0))); } else { - content.setSchema(schemaFactory.getSchema(paramMetas)); + content.setSchema(schemaResolver.resolve(paramMetas)); } } } @@ -395,18 +383,58 @@ private void resolveResponse( response.getOrAddContent(mediaType.getName()); if (content.getSchema() == null) { if (httpStatus >= 400) { - content.setSchema(schemaFactory.getSchema(ErrorResponse.class)); + content.setSchema(schemaResolver.resolve(ErrorResponse.class)); } else { - content.setSchema(schemaFactory.getSchema(meta.getReturnParameter())); + content.setSchema(schemaResolver.resolve(meta.getReturnParameter())); } } } } - static final class ResolveContextImpl extends AbstractContext implements ResolveContext { + private static final class OperationContextImpl extends AbstractContext implements OperationContext { + + OperationContextImpl(OpenAPI openAPI, SchemaResolver schemaResolver, ExtensionFactory extensionFactory) { + super(openAPI, schemaResolver, extensionFactory); + } + } + + private static final class OpenAPIChainImpl implements OpenAPIChain { + + private final OpenAPIDefinitionResolver[] resolvers; + private final Function fallback; + private int cursor; + + OpenAPIChainImpl(OpenAPIDefinitionResolver[] resolvers, Function fallback) { + this.resolvers = resolvers; + this.fallback = fallback; + } + + @Override + public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta) { + if (cursor < resolvers.length) { + return resolvers[cursor++].resolve(openAPI, serviceMeta, this); + } + return fallback.apply(openAPI); + } + } + + private static final class OperationChainImpl implements OperationChain { + + private final OpenAPIDefinitionResolver[] resolvers; + private final Function fallback; + private int cursor; - ResolveContextImpl(OpenAPI openAPI, SchemaFactory schemaFactory, ExtensionFactory extensionFactory) { - super(openAPI, schemaFactory, extensionFactory); + OperationChainImpl(OpenAPIDefinitionResolver[] resolvers, Function fallback) { + this.resolvers = resolvers; + this.fallback = fallback; + } + + @Override + public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext chain) { + if (cursor < resolvers.length) { + return resolvers[cursor++].resolve(operation, methodMeta, chain, this); + } + return fallback.apply(operation); } } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index 20d3fdc166b..32fa725abf6 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -23,9 +23,11 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; import static org.apache.dubbo.remoting.http12.HttpMethods.DELETE; @@ -97,6 +99,23 @@ public static Collection guessHttpMethod(MethodMeta method) { return Collections.singletonList(POST.name()); } + public static List extractVariables(String path) { + List variables = null; + for (int i = 0, len = path.length(), start = 0; i < len; i++) { + char c = path.charAt(i); + if (c == '{') { + start = i + 1; + } else if (start > 0 && c == '}') { + if (variables == null) { + variables = new ArrayList<>(); + } + variables.add(path.substring(start, i)); + start = 0; + } + } + return variables; + } + public static In toIn(ParamType paramType) { switch (paramType) { case PathVariable: diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java index f2701691467..14f55eaba3f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java @@ -23,15 +23,34 @@ public interface OpenAPIDefinitionResolver extends OpenAPIExtension { - default boolean hidden(ServiceMeta serviceMeta) { - return false; + OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain); + + Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext context, OperationChain chain); + + interface OpenAPIChain { + + OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta); } - OpenAPI resolve(ServiceMeta serviceMeta); + interface OperationChain { - default boolean hidden(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { - return false; + Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext context); } - Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context); + interface OperationContext { + + String getGroup(); + + OpenAPI getOpenAPI(); + + SchemaResolver getSchemaResolver(); + + ExtensionFactory getExtensionFactory(); + + T getAttribute(String name); + + T removeAttribute(String name); + + void setAttribute(String name, Object value); + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java index 47c5619f6e7..a89706cda8d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.remoting.http12.HttpResult; @@ -23,7 +24,7 @@ public interface OpenAPIRequestHandler extends OpenAPIExtension { default String[] getPaths() { - return null; + return StringUtils.EMPTY_STRING_ARRAY; } HttpResult handle(String path, HttpRequest request, HttpResponse response); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java index d9130b15b39..0e22369ba0d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java @@ -22,7 +22,11 @@ public interface OpenAPISchemaPredicate extends OpenAPIExtension { - Boolean acceptClass(Class clazz, ParameterMeta parameter); + default Boolean acceptClass(Class clazz, ParameterMeta parameter) { + return null; + } - Boolean acceptProperty(BeanMeta bean, PropertyMeta property); + default Boolean acceptProperty(BeanMeta bean, PropertyMeta property) { + return null; + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java index 6a740e0517e..e8518b0058c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java @@ -23,19 +23,19 @@ public interface OpenAPISchemaResolver extends OpenAPIExtension { - Schema resolve(ParameterMeta parameter, Context context, Chain chain); + Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain); - interface Chain { + interface SchemaChain { - Schema resolve(ParameterMeta parameter, Context context); + Schema resolve(ParameterMeta parameter, SchemaContext context); } - interface Context { + interface SchemaContext { void defineSchema(Class type, Schema schema); - Schema getSchema(ParameterMeta parameter); + Schema resolve(ParameterMeta parameter); - Schema getSchema(Type type); + Schema resolve(Type type); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java deleted file mode 100644 index 0b0f53f9b2b..00000000000 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ResolveContext.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.protocol.tri.rest.openapi; - -import org.apache.dubbo.config.nested.OpenAPIConfig; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; - -public interface ResolveContext { - - String getGroup(); - - OpenAPI getOpenAPI(); - - OpenAPIConfig getConfig(); - - SchemaFactory getSchemaFactory(); - - ExtensionFactory getExtensionFactory(); - - T getAttribute(String name); - - T removeAttribute(String name); - - void setAttribute(String name, Object value); -} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java similarity index 73% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java rename to dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java index 6f7b6e6e936..13498dda719 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java @@ -23,8 +23,8 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.TypeParameterMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.Chain; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.Context; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.SchemaChain; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver.SchemaContext; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import org.apache.dubbo.rpc.protocol.tri.rest.support.basic.Annotations; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; @@ -43,63 +43,51 @@ import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.PrimitiveSchema.ARRAY; import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.PrimitiveSchema.OBJECT; -public final class SchemaFactory { +public final class SchemaResolver { private final ConfigFactory configFactory; private final OpenAPISchemaResolver[] resolvers; private final OpenAPISchemaPredicate[] predicates; private final Map, Optional> schemaMap = CollectionUtils.newConcurrentHashMap(); - public SchemaFactory(FrameworkModel frameworkModel) { + public SchemaResolver(FrameworkModel frameworkModel) { configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); ExtensionFactory extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); resolvers = extensionFactory.getExtensions(OpenAPISchemaResolver.class); predicates = extensionFactory.getExtensions(OpenAPISchemaPredicate.class); } - public Map, Optional> getSchemaMap() { - return schemaMap; + public Schema resolve(Type type) { + return resolve(new TypeParameterMeta(type)); } - public Schema getSchema(Type type) { - return getSchema(new TypeParameterMeta(type)); + public Schema resolve(ParameterMeta parameter) { + return new SchemaChainImpl(resolvers, this::fallbackResolve).resolve(parameter, new SchemaContextImpl()); } - public Schema getSchema(ParameterMeta parameter) { - return new ChainImpl(resolvers, p -> resolveSchema(p.getActualGenericType(), p)) - .resolve(parameter, new Context() { - @Override - public void defineSchema(Class type, Schema schema) { - schemaMap.putIfAbsent(type, Optional.of(schema)); - } - - @Override - public Schema getSchema(ParameterMeta parameter) { - return SchemaFactory.this.getSchema(parameter); - } - - @Override - public Schema getSchema(Type type) { - return SchemaFactory.this.getSchema(type); - } - }); - } - - public Schema getSchema(List parameters) { + public Schema resolve(List parameters) { Schema schema = OBJECT.newSchema(); for (ParameterMeta parameter : parameters) { String name = parameter.getName(); if (name == null) { return ARRAY.newSchema(); } - schema.addProperty(name, getSchema(parameter)); + schema.addProperty(name, resolve(parameter)); } return schema; } - private Schema resolveSchema(Type type, ParameterMeta parameter) { + private Schema fallbackResolve(ParameterMeta parameter) { + return doResolveType(parameter.getActualGenericType(), parameter); + } + + private Schema doResolveNestedType(Type nestedType, ParameterMeta parameter) { + return doResolveType(nestedType, new TypeParameterMeta(parameter.getToolKit(), nestedType)); + } + + private Schema doResolveType(Type type, ParameterMeta parameter) { if (type instanceof Class) { - return resolveClassSchema((Class) type, parameter); + return doResolveClass((Class) type, parameter); } if (type instanceof ParameterizedType) { ParameterizedType pType = (ParameterizedType) type; @@ -109,7 +97,7 @@ private Schema resolveSchema(Type type, ParameterMeta parameter) { Type[] argTypes = pType.getActualTypeArguments(); if (Iterable.class.isAssignableFrom(clazz)) { Type itemType = TypeUtils.getActualGenericType(argTypes[0]); - return ARRAY.newSchema().setItems(resolveNestedSchema(itemType, parameter)); + return ARRAY.newSchema().setItems(doResolveNestedType(itemType, parameter)); } if (Map.class.isAssignableFrom(clazz)) { @@ -118,33 +106,33 @@ private Schema resolveSchema(Type type, ParameterMeta parameter) { if (String.class != keyType) { schema.addExtension(Constants.X_JAVA_TYPE, TypeUtils.toTypeString(keyType)); } - return schema.setAdditionalPropertiesSchema(resolveNestedSchema(argTypes[1], parameter)); + return schema.setAdditionalPropertiesSchema(doResolveNestedType(argTypes[1], parameter)); } - return resolveClassSchema(clazz, parameter); + return doResolveClass(clazz, parameter); } } if (type instanceof TypeVariable) { - return resolveNestedSchema(((TypeVariable) type).getBounds()[0], parameter); + return doResolveNestedType(((TypeVariable) type).getBounds()[0], parameter); } if (type instanceof WildcardType) { - return resolveNestedSchema(((WildcardType) type).getUpperBounds()[0], parameter); + return doResolveNestedType(((WildcardType) type).getUpperBounds()[0], parameter); } if (type instanceof GenericArrayType) { Type nestedType = ((GenericArrayType) type).getGenericComponentType(); - return ARRAY.newSchema().setItems(resolveNestedSchema(nestedType, parameter)); + return ARRAY.newSchema().setItems(doResolveNestedType(nestedType, parameter)); } return OBJECT.newSchema(); } - private Schema resolveClassSchema(Class clazz, ParameterMeta parameter) { + private Schema doResolveClass(Class clazz, ParameterMeta parameter) { Schema schema = PrimitiveSchema.newSchemaOf(clazz); if (schema != null) { return schema; } if (clazz.isArray()) { - return ARRAY.newSchema().setItems(resolveNestedSchema(clazz.getComponentType(), parameter)); + return ARRAY.newSchema().setItems(doResolveNestedType(clazz.getComponentType(), parameter)); } Optional existingSchema = schemaMap.get(clazz); @@ -182,14 +170,14 @@ private Schema resolveClassSchema(Class clazz, ParameterMeta parameter) { Boolean flatten = configFactory.getGlobalConfig().getSchemaFlatten(); if (flatten == null) { - AnnotationMeta ann = typeParameter.getAnnotation(Annotations.Schema); - flatten = ann != null && ann.getBoolean("flatten"); + AnnotationMeta anno = typeParameter.getAnnotation(Annotations.Schema); + flatten = anno != null && anno.getBoolean("flatten"); } - return new Schema().setTargetSchema(resolveBeanSchema(parameter.getToolKit(), clazz, flatten)); + return new Schema().setTargetSchema(doResolveBeanClass(parameter.getToolKit(), clazz, flatten)); } - private Schema resolveBeanSchema(RestToolKit toolKit, Class clazz, boolean flatten) { + private Schema doResolveBeanClass(RestToolKit toolKit, Class clazz, boolean flatten) { Schema beanSchema = OBJECT.newSchema().setJavaType(clazz); schemaMap.put(clazz, Optional.of(beanSchema)); BeanMeta beanMeta = new BeanMeta(toolKit, clazz, flatten); @@ -215,7 +203,7 @@ private Schema resolveBeanSchema(RestToolKit toolKit, Class clazz, boolean fl continue; } } - beanSchema.addProperty(property.getName(), getSchema(property)); + beanSchema.addProperty(property.getName(), resolve(property)); } if (flatten) { @@ -226,31 +214,44 @@ private Schema resolveBeanSchema(RestToolKit toolKit, Class clazz, boolean fl return beanSchema; } - return beanSchema.addAllOf(getSchema(superClass)); - } - - private Schema resolveNestedSchema(Type nestedType, ParameterMeta parameter) { - return resolveSchema(nestedType, new TypeParameterMeta(parameter.getToolKit(), nestedType)); + return beanSchema.addAllOf(resolve(superClass)); } - static final class ChainImpl implements Chain { + private static final class SchemaChainImpl implements SchemaChain { private final OpenAPISchemaResolver[] resolvers; private final Function fallback; - private int cursor; - ChainImpl(OpenAPISchemaResolver[] resolvers, Function fallback) { + SchemaChainImpl(OpenAPISchemaResolver[] resolvers, Function fallback) { this.resolvers = resolvers; this.fallback = fallback; } @Override - public Schema resolve(ParameterMeta parameter, Context context) { + public Schema resolve(ParameterMeta parameter, SchemaContext context) { if (cursor < resolvers.length) { return resolvers[cursor++].resolve(parameter, context, this); } return fallback.apply(parameter); } } + + private final class SchemaContextImpl implements SchemaContext { + + @Override + public void defineSchema(Class type, Schema schema) { + schemaMap.putIfAbsent(type, Optional.of(schema)); + } + + @Override + public Schema resolve(ParameterMeta parameter) { + return SchemaResolver.this.resolve(parameter); + } + + @Override + public Schema resolve(Type type) { + return SchemaResolver.this.resolve(type); + } + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java index 6c94e4bc837..355497bc59c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java @@ -580,7 +580,6 @@ public Schema clone() { public Map writeTo(Map schema, Context context) { if (ref != null) { schema.put("$ref", ref); - return schema; } write(schema, "format", format); write(schema, "title", title); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java index 33d925a6e9d..a6a348e7d31 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java @@ -28,7 +28,6 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaPredicate; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ResolveContext; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ExternalDocs; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; @@ -51,114 +50,130 @@ public final class BasicOpenAPIDefinitionResolver private static final String HIDDEN = "hidden"; @Override - public boolean hidden(ServiceMeta serviceMeta) { - AnnotationMeta openAPI = serviceMeta.findAnnotation(Annotations.OpenAPI); - return openAPI != null && openAPI.getBoolean(HIDDEN); - } - - @Override - public OpenAPI resolve(ServiceMeta serviceMeta) { - AnnotationMeta openAPI = serviceMeta.findAnnotation(Annotations.OpenAPI); - if (openAPI == null) { + public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain) { + AnnotationMeta annoMeta = serviceMeta.findAnnotation(Annotations.OpenAPI); + if (annoMeta == null) { + return chain.resolve(openAPI, serviceMeta); + } + if (annoMeta.getBoolean(HIDDEN)) { return null; } - OpenAPI model = new OpenAPI(); - Map tags = Helper.toProperties(openAPI.getStringArray("tags")); + Info info = openAPI.getInfo(); + if (info == null) { + openAPI.setInfo(info = new Info()); + } + + Map tags = Helper.toProperties(annoMeta.getStringArray("tags")); for (Map.Entry entry : tags.entrySet()) { - model.addTag(new Tag().setName(entry.getKey()).setDescription(entry.getValue())); + openAPI.addTag(new Tag().setName(entry.getKey()).setDescription(entry.getValue())); } - model.setGroup(trim(openAPI.getString("group"))); - String title = trim(openAPI.getString("infoTitle")); - String description = trim(openAPI.getString("infoDescription")); - String version = trim(openAPI.getString("infoVersion")); - if (title != null || description != null || version != null) { - model.setInfo(new Info().setTitle(title).setDescription(description).setVersion(version)); + String group = trim(annoMeta.getString("group")); + if (group != null) { + openAPI.setGroup(group); } - String docDescription = trim(openAPI.getString("docDescription")); - String docUrl = trim(openAPI.getString("docUrl")); + String title = trim(annoMeta.getString("infoTitle")); + if (title != null) { + info.setTitle(title); + } + String description = trim(annoMeta.getString("infoDescription")); + if (description != null) { + info.setDescription(description); + } + String version = trim(annoMeta.getString("infoVersion")); + if (version != null) { + info.setVersion(version); + } + + String docDescription = trim(annoMeta.getString("docDescription")); + String docUrl = trim(annoMeta.getString("docUrl")); if (docDescription != null || docUrl != null) { - model.setExternalDocs( + openAPI.setExternalDocs( new ExternalDocs().setDescription(docDescription).setUrl(docUrl)); } - model.setPriority(openAPI.getNumber("order")); - model.setExtensions(Helper.toProperties(openAPI.getStringArray("extensions"))); - return model; + openAPI.setPriority(annoMeta.getNumber("order")); + openAPI.setExtensions(Helper.toProperties(annoMeta.getStringArray("extensions"))); + return chain.resolve(openAPI, serviceMeta); } @Override - public boolean hidden(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { - AnnotationMeta operation = methodMeta.findAnnotation(Annotations.Operation); - return operation != null && operation.getBoolean(HIDDEN); - } - - @Override - public Operation resolve(MethodMeta methodMeta, OpenAPI openAPI, ResolveContext context) { - AnnotationMeta operation = methodMeta.findAnnotation(Annotations.Operation); - if (operation == null) { + public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) { + AnnotationMeta annoMeta = methodMeta.findAnnotation(Annotations.Operation); + if (annoMeta == null) { + return chain.resolve(operation, methodMeta, ctx); + } + if (annoMeta.getBoolean(HIDDEN)) { return null; } - Operation model = new Operation(); - String method = trim(operation.getString("method")); + String method = trim(annoMeta.getString("method")); if (method != null) { - model.setHttpMethod(HttpMethods.of(method.toUpperCase())); + operation.setHttpMethod(HttpMethods.of(method.toUpperCase())); } - String[] tags = trim(operation.getStringArray("tags")); + String[] tags = trim(annoMeta.getStringArray("tags")); if (tags != null) { - model.setTags(new LinkedHashSet<>(Arrays.asList(tags))); - } - - model.setGroup(trim(operation.getString("group"))); - model.setVersion(trim(operation.getString("version"))); - model.setOperationId(trim(operation.getString("id"))); - String summary = trim(operation.getValue()); - model.setSummary(summary == null ? trim(operation.getString("summary")) : summary); - model.setDescription(trim(operation.getString("description"))); - model.setDeprecated(operation.getBoolean("deprecated")); - model.setExtensions(Helper.toProperties(operation.getStringArray("extensions"))); - return model; + operation.setTags(new LinkedHashSet<>(Arrays.asList(tags))); + } + + operation.setGroup(trim(annoMeta.getString("group"))); + operation.setVersion(trim(annoMeta.getString("version"))); + operation.setOperationId(trim(annoMeta.getString("id"))); + String summary = trim(annoMeta.getValue()); + operation.setSummary(summary == null ? trim(annoMeta.getString("summary")) : summary); + operation.setDescription(trim(annoMeta.getString("description"))); + operation.setDeprecated(annoMeta.getBoolean("deprecated")); + operation.setExtensions(Helper.toProperties(annoMeta.getStringArray("extensions"))); + return operation; } @Override - public Schema resolve(ParameterMeta parameter, Context context, Chain chain) { - AnnotationMeta schema = parameter.getAnnotation(Annotations.Schema); - if (schema == null) { + public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain) { + AnnotationMeta annoMeta = parameter.getAnnotation(Annotations.Schema); + if (annoMeta == null) { return chain.resolve(parameter, context); } + if (annoMeta.getBoolean(HIDDEN)) { + return null; + } - Class impl = schema.getClass("implementation"); - Schema model = impl == Void.class ? chain.resolve(parameter, context) : context.getSchema(impl); - - setValue(schema, "group", model::setGroup); - setValue(schema, "version", model::setVersion); - setValue(schema, "type", v -> model.setType(Type.valueOf(v))); - setValue(schema, "format", model::setFormat); - setValue(schema, "name", model::setName); - String title = trim(schema.getValue()); - model.setTitle(title == null ? trim(schema.getString("title")) : title); - setValue(schema, "title", model::setTitle); - setValue(schema, "description", model::setDescription); - setValue(schema, "max", v -> model.setMaxLength(Integer.parseInt(v))); - setValue(schema, "min", v -> model.setMinLength(Integer.parseInt(v))); - setValue(schema, "pattern", model::setPattern); - setValue(schema, "example", model::setExample); - String[] enumItems = trim(schema.getStringArray("enumeration")); + Class impl = annoMeta.getClass("implementation"); + Schema schema = impl == Void.class ? chain.resolve(parameter, context) : context.resolve(impl); + + setValue(annoMeta, "group", schema::setGroup); + setValue(annoMeta, "version", schema::setVersion); + setValue(annoMeta, "type", v -> schema.setType(Type.valueOf(v))); + setValue(annoMeta, "format", schema::setFormat); + setValue(annoMeta, "name", schema::setName); + String title = trim(annoMeta.getValue()); + schema.setTitle(title == null ? trim(annoMeta.getString("title")) : title); + setValue(annoMeta, "title", schema::setTitle); + setValue(annoMeta, "description", schema::setDescription); + setValue(annoMeta, "max", v -> schema.setMaxLength(Integer.parseInt(v))); + setValue(annoMeta, "min", v -> schema.setMinLength(Integer.parseInt(v))); + setValue(annoMeta, "pattern", schema::setPattern); + setValue(annoMeta, "example", schema::setExample); + String[] enumItems = trim(annoMeta.getStringArray("enumeration")); if (enumItems != null) { - model.setEnumeration(Arrays.asList(enumItems)); - } - setBoolValue(schema, "required", model::setRequired); - setValue(schema, "defaultValue", model::setDefaultValue); - setBoolValue(schema, "readOnly", model::setReadOnly); - setBoolValue(schema, "writeOnly", model::setWriteOnly); - setBoolValue(schema, "nullable", model::setNullable); - setBoolValue(schema, "deprecated", model::setDeprecated); - model.setExtensions(Helper.toProperties(schema.getStringArray("extensions"))); - return model; + schema.setEnumeration(Arrays.asList(enumItems)); + } + setBoolValue(annoMeta, "required", schema::setRequired); + setValue(annoMeta, "defaultValue", schema::setDefaultValue); + setBoolValue(annoMeta, "readOnly", schema::setReadOnly); + setBoolValue(annoMeta, "writeOnly", schema::setWriteOnly); + setBoolValue(annoMeta, "nullable", schema::setNullable); + setBoolValue(annoMeta, "deprecated", schema::setDeprecated); + schema.setExtensions(Helper.toProperties(annoMeta.getStringArray("extensions"))); + return schema; + } + + @Override + public Boolean acceptProperty(BeanMeta bean, PropertyMeta property) { + AnnotationMeta annoMeta = property.getAnnotation(Annotations.Schema); + return annoMeta == null ? null : annoMeta.getBoolean(HIDDEN); } private static void setValue(AnnotationMeta schema, String key, Consumer setter) { @@ -174,16 +189,4 @@ private static void setBoolValue(AnnotationMeta schema, String key, Consumer< setter.accept(true); } } - - @Override - public Boolean acceptClass(Class clazz, ParameterMeta parameter) { - AnnotationMeta schema = parameter.getAnnotation(Annotations.Schema); - return schema == null ? null : schema.getBoolean(HIDDEN); - } - - @Override - public Boolean acceptProperty(BeanMeta bean, PropertyMeta property) { - AnnotationMeta schema = property.getAnnotation(Annotations.Schema); - return schema == null ? null : schema.getBoolean(HIDDEN); - } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java index 9b54f1df7bf..82caf9dfd5a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/FallbackArgumentResolver.java @@ -54,8 +54,8 @@ protected NamedValueMeta createNamedValueMeta(ParameterMeta param) { MethodMeta methodMeta = ((MethodParameterMeta) param).getMethodMeta(); ParameterMeta[] paramMetas = methodMeta.getParameters(); for (ParameterMeta paramMeta : paramMetas) { - AnnotationMeta ann = paramMeta.findAnnotation(Param.class); - if (ann != null && ann.getAnnotation().type() == ParamType.Body) { + AnnotationMeta anno = paramMeta.findAnnotation(Param.class); + if (anno != null && anno.getAnnotation().type() == ParamType.Body) { noBodyParam = false; break; } @@ -136,7 +136,7 @@ private static final class FallbackNamedValueMeta extends NamedValueMeta { private final int paramCount; FallbackNamedValueMeta(boolean required, boolean noBodyParam, int paramCount) { - super(required); + super(null, required); this.noBodyParam = noBodyParam; this.paramCount = paramCount; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/GRequestArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/GRequestArgumentResolver.java index be02a800c40..0f0e0e7caef 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/GRequestArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/GRequestArgumentResolver.java @@ -48,7 +48,7 @@ public Class accept() { @Override public NamedValueMeta getNamedValueMeta(ParameterMeta parameter, AnnotationMeta annotation) { - return new NamedValueMeta(null, false, ParamType.Body); + return new NamedValueMeta().setParamType(ParamType.Body); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java index 8e5085e3a7b..4e1bdf7029b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/ParamArgumentResolver.java @@ -48,14 +48,13 @@ public class ParamArgumentResolver extends AbstractAnnotationBaseArgumentResolver { @Override - protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta ann) { - String defaultValue = ann.getString("defaultValue"); + protected NamedValueMeta createNamedValueMeta(ParameterMeta param, AnnotationMeta anno) { + String defaultValue = anno.getString("defaultValue"); if (Param.DEFAULT_NONE.equals(defaultValue)) { defaultValue = null; } - NamedValueMeta meta = new NamedValueMeta(ann.getValue(), ann.getBoolean("required"), defaultValue); - meta.setParamType(ann.getEnum("type")); - return meta; + return new NamedValueMeta(anno.getValue(), anno.getBoolean("required"), defaultValue) + .setParamType(anno.getEnum("type")); } @Override From aa53c9bd9b09b1ee707785cb9747795526c354cb Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Sun, 24 Nov 2024 22:29:24 +0800 Subject: [PATCH 14/23] Schema class exclude support --- .../dubbo/common/utils/StringUtils.java | 10 ++-- .../dubbo/config/nested/OpenAPIConfig.java | 22 ++++++- .../pom.xml | 8 --- .../pom.xml | 8 --- .../src/main/resources/application.yml | 4 ++ .../support/spring/BeanArgumentBinder.java | 10 ++-- .../support/swagger/RedocRequestHandler.java | 20 +------ .../swagger/SwaggerUIRequestHandler.java | 20 +------ .../rest/support/swagger/WebjarHelper.java | 19 +++++- .../protocol/tri/servlet/TripleFilter.java | 10 ++-- .../java/org/apache/dubbo/rpc/Constants.java | 2 - dubbo-rpc/dubbo-rpc-triple/pom.xml | 8 --- .../filter/RestExtensionExecutionFilter.java | 18 +++--- .../protocol/tri/rest/mapping/RadixTree.java | 13 ++++- .../rest/mapping/condition/PathParser.java | 2 +- .../tri/rest/openapi/ConfigFactory.java | 25 ++++++++ .../tri/rest/openapi/DefinitionMerger.java | 4 +- .../tri/rest/openapi/DefinitionResolver.java | 3 + .../tri/rest/openapi/SchemaResolver.java | 58 ++++++++++++++++++- .../rpc/protocol/tri/rest/util/TypeUtils.java | 2 +- pom.xml | 17 +++++- 21 files changed, 187 insertions(+), 96 deletions(-) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java index e4c3919d937..78ee6f5530d 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java @@ -1286,7 +1286,7 @@ public static String substring(String str, int start, int end) { /** * Gets the substring before the first occurrence of a separator. - * If no match found, returns the original string + *

If nothing is found, returns the original string

*/ public static String substringBefore(String str, int separator) { if (isEmpty(str)) { @@ -1298,7 +1298,7 @@ public static String substringBefore(String str, int separator) { /** * Gets the substring after the first occurrence of a separator. - * If no match found, returns the original string + *

If nothing is found, the empty string is returned.

*/ public static String substringAfter(String str, int separator) { if (isEmpty(str)) { @@ -1310,7 +1310,7 @@ public static String substringAfter(String str, int separator) { /** * Gets the substring before the last occurrence of a separator. - * If no match found, returns the original string + *

If nothing is found, returns the original string

*/ public static String substringBeforeLast(String str, int separator) { if (isEmpty(str)) { @@ -1322,14 +1322,14 @@ public static String substringBeforeLast(String str, int separator) { /** * Gets the substring after the last occurrence of a separator. - * If no match found, returns the original string + *

If nothing is found, the empty string is returned.

*/ public static String substringAfterLast(String str, int separator) { if (isEmpty(str)) { return str; } int index = str.lastIndexOf(separator); - return index == INDEX_NOT_FOUND ? str : str.substring(index + 1); + return index == INDEX_NOT_FOUND || index == str.length() - 1 ? EMPTY_STRING : str.substring(index + 1); } /** diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java index db10706fba8..5460d775df3 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -122,7 +122,19 @@ public class OpenAPIConfig implements Serializable { */ private Boolean schemaFlatten; - private String[] schemaClassFilter; + /** + * Specifies the classes to be excluded from schema generation. + *

For example: + *

    + *
  • com.example.MyClass - Exclude the MyClass class.
  • + *
  • com.example. - Exclude all classes in the com.example package.
  • + *
  • !com.example.exclude. - Exclude all classes except those in the com.example.exclude package.
  • + *
+ * Note that the package name should end with a dot (.) or an exclamation mark (!) to indicate the exclusion scope. + *

Multiple classes or package names can be separated by commas, for + * example: com.example.MyClass,com.example.,!com.example.exclude + */ + private String[] schemaClassExcludes; /** * The custom settings. @@ -281,6 +293,14 @@ public void setSchemaFlatten(Boolean schemaFlatten) { this.schemaFlatten = schemaFlatten; } + public String[] getSchemaClassExcludes() { + return schemaClassExcludes; + } + + public void setSchemaClassExcludes(String[] schemaClassExcludes) { + this.schemaClassExcludes = schemaClassExcludes; + } + public Map getSettings() { return settings; } diff --git a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml index a9bb5cb4759..5f574918aa3 100644 --- a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-consumer/pom.xml @@ -35,14 +35,6 @@ org.apache.dubbo dubbo-maven-plugin - 3.3.2 - - - - compile - - - diff --git a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml index c73440fca2a..68e1fabef6f 100644 --- a/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot-idl/dubbo-demo-spring-boot-idl-provider/pom.xml @@ -35,14 +35,6 @@ org.apache.dubbo dubbo-maven-plugin - 3.3.2 - - - - compile - - - diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml index 525f7b03353..88754252174 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml @@ -31,6 +31,10 @@ dubbo: enabled: true cache: false schema-flatten: false + schema-class-excludes: + - a. + - "!b.c." + - "!org.apache.dubbo.springboot.demo." servlet: enabled: true registry: diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java index c918e568436..6f721ddfe4b 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/BeanArgumentBinder.java @@ -75,12 +75,12 @@ private Object createBean(ParameterMeta paramMeta, HttpRequest request, HttpResp throw new IllegalStateException(Messages.ARGUMENT_COULD_NOT_RESOLVED.format(paramMeta.getDescription())); } ConstructorMeta ct = CACHE.computeIfAbsent(type, k -> { - ConstructorMeta meta = resolveConstructor(paramMeta.getToolKit(), null, type); - if (meta == null) { - throw new IllegalStateException( - Messages.ARGUMENT_COULD_NOT_RESOLVED.format(paramMeta.getDescription())); + try { + return resolveConstructor(paramMeta.getToolKit(), null, type); + } catch (IllegalArgumentException e) { + throw new IllegalStateException(Messages.ARGUMENT_COULD_NOT_RESOLVED.format(paramMeta.getDescription()) + + ", " + e.getMessage()); } - return meta; }); ParameterMeta[] parameters = ct.getParameters(); int len = parameters.length; diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java index 1e41d20c9ce..0469ab8e202 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java @@ -73,8 +73,8 @@ public HttpResult handle(String path, HttpRequest request, HttpResponse respo String requestPath = StringUtils.substringBeforeLast(resPath, '.'); if (requestPath.equals("index")) { return handleIndex(request.parameter("group", Constants.DEFAULT_GROUP)); - } else if (requestPath.startsWith("assets/")) { - return handleSwaggerUIAssets(resPath.substring(7)); + } else if (WebjarHelper.ENABLED && requestPath.startsWith("assets/")) { + return WebjarHelper.getInstance().handleAssets("redoc", resPath.substring(7)); } throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); } @@ -100,20 +100,4 @@ private HttpResult handleIndex(String group) { throw new HttpStatusException(HttpStatus.INTERNAL_SERVER_ERROR.getCode(), e); } } - - private HttpResult handleSwaggerUIAssets(String path) { - if (WebjarHelper.ENABLED) { - try { - byte[] bytes = WebjarHelper.getInstance().getWebjarResource("redoc", path); - if (bytes != null) { - return HttpResult.builder() - .header("Cache-Control", "public, max-age=604800") - .body(bytes) - .build(); - } - } catch (IOException ignored) { - } - } - throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); - } } diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java index 3989b10969b..67cd6f25652 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java @@ -84,8 +84,8 @@ public HttpResult handle(String path, HttpRequest request, HttpResponse respo case "swagger-config": return handleSwaggerConfig(); default: - if (requestPath.startsWith("assets/")) { - return handleSwaggerUIAssets(resPath.substring(7)); + if (WebjarHelper.ENABLED && requestPath.startsWith("assets/")) { + return WebjarHelper.getInstance().handleAssets("swagger-ui", resPath.substring(7)); } } throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); @@ -144,20 +144,4 @@ private HttpResult handleSwaggerConfig() { configMap.put("urls", urls); return HttpResult.of(JsonUtils.toJson(configMap).getBytes(UTF_8)); } - - private HttpResult handleSwaggerUIAssets(String path) { - if (WebjarHelper.ENABLED) { - try { - byte[] bytes = WebjarHelper.getInstance().getWebjarResource("swagger-ui", path); - if (bytes != null) { - return HttpResult.builder() - .header("Cache-Control", "public, max-age=604800") - .body(bytes) - .build(); - } - } catch (IOException ignored) { - } - } - throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); - } } diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java index 8d1d210fe35..8e37f50bd42 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java @@ -18,6 +18,9 @@ import org.apache.dubbo.common.io.StreamUtils; import org.apache.dubbo.common.utils.ClassUtils; +import org.apache.dubbo.remoting.http12.HttpResult; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import java.io.IOException; import java.io.InputStream; @@ -41,11 +44,25 @@ public static WebjarHelper getInstance() { return INSTANCE; } + public HttpResult handleAssets(String webjar, String path) { + try { + byte[] bytes = getWebjarResource(webjar, path); + if (bytes != null) { + return HttpResult.builder() + .header("Cache-Control", "public, max-age=604800") + .body(bytes) + .build(); + } + } catch (IOException ignored) { + } + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); + } + public boolean hasWebjar(String webjar) { return locator.version(webjar) != null; } - public byte[] getWebjarResource(String webjar, String exactPath) throws IOException { + private byte[] getWebjarResource(String webjar, String exactPath) throws IOException { String fullPath = locator.fullPath(webjar, exactPath); if (fullPath != null) { InputStream is = WebJarVersionLocator.class.getClassLoader().getResourceAsStream(fullPath); diff --git a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java index 5802def926c..749063dcc79 100644 --- a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java +++ b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/TripleFilter.java @@ -88,7 +88,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo return; } } else { - if (!isUpgradeRequest(request) && mappingRegistry.exists(request.getRequestURI(), request.getMethod())) { + if (notUpgradeRequest(request) && mappingRegistry.exists(request.getRequestURI(), request.getMethod())) { handleHttp1(request, response); return; } @@ -157,6 +157,10 @@ private boolean hasGrpcMapping(HttpServletRequest request) { return pathResolver.resolve(path.getPath(), group, version) != null; } + private boolean notUpgradeRequest(HttpServletRequest request) { + return request.getHeader(UPGRADE_HEADER_KEY) == null; + } + private Http2ServerTransportListenerFactory determineHttp2ServerTransportListenerFactory(String contentType) { Set http2ServerTransportListenerFactories = FrameworkModel.defaultModel() .getExtensionLoader(Http2ServerTransportListenerFactory.class) @@ -190,10 +194,6 @@ private static int resolveTimeout(HttpServletRequest request, boolean isGrpc) { return 0; } - private boolean isUpgradeRequest(HttpServletRequest request) { - return request.getHeader(UPGRADE_HEADER_KEY) != null; - } - private static final class TripleAsyncListener implements AsyncListener { private final ServletStreamChannel streamChannel; diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java index 4ef8731af80..7abc0aa40a6 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java @@ -103,8 +103,6 @@ public interface Constants { String HTTP3_KEY = "http3"; - String TRIPLE_SERVLET_KEY = "triple.servlet"; - String H2_SETTINGS_SUPPORT_NO_LOWER_HEADER_KEY = "dubbo.rpc.tri.support-no-lower-header"; String H2_SETTINGS_IGNORE_1_0_0_KEY = "dubbo.rpc.tri.ignore-1.0.0-version"; String H2_SETTINGS_RESOLVE_FALLBACK_TO_DEFAULT_KEY = "dubbo.rpc.tri.resolve-fallback-to-default"; diff --git a/dubbo-rpc/dubbo-rpc-triple/pom.xml b/dubbo-rpc/dubbo-rpc-triple/pom.xml index dbd8b3fbc69..a516e70137f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/pom.xml +++ b/dubbo-rpc/dubbo-rpc-triple/pom.xml @@ -148,14 +148,6 @@ org.apache.dubbo dubbo-maven-plugin - 3.3.2 - - - - compile - - - diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java index 66f53fa94bb..d49198ebee8 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java @@ -48,6 +48,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -143,13 +144,13 @@ protected void onError( private RestFilter[] matchFilters(RestFilter[] filters, String path) { int len = filters.length; BitSet bitSet = new BitSet(len); - out: for (int i = 0; i < len; i++) { RestFilter filter = filters[i]; String[] patterns = filter.getPatterns(); if (ArrayUtils.isEmpty(patterns)) { continue; } + RadixTree filterTree = filterTreeCache.computeIfAbsent(filter, f -> { RadixTree tree = new RadixTree<>(); for (String pattern : patterns) { @@ -166,16 +167,15 @@ private RestFilter[] matchFilters(RestFilter[] filters, String path) { List> matches = filterTree.match(path); int size = matches.size(); - if (size == 0) { - bitSet.set(i); - continue; - } - for (int j = 0; j < size; j++) { - if (!matches.get(j).getValue()) { - bitSet.set(i); - continue out; + if (size > 0) { + if (size > 1) { + Collections.sort(matches); + } + if (matches.get(size - 1).getValue()) { + continue; } } + bitSet.set(i); } if (bitSet.isEmpty()) { return filters; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java index 235eb552c3a..786f29ded91 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RadixTree.java @@ -96,7 +96,18 @@ public T addPath(PathExpression path, T value) { } public T addPath(String path, T value) { - return addPath(PathExpression.parse(PathUtils.normalize(path)), value); + if (path == null) { + return value; + } + if (separator == '/') { + path = PathUtils.normalize(path); + } else { + path = path.replace(separator, '/'); + if (path.isEmpty() || path.charAt(0) != '/') { + path = '/' + path; + } + } + return addPath(PathExpression.parse(path), value); } public void addPath(T value, String... paths) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathParser.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathParser.java index b89f0ff0e32..8add3bd99ee 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathParser.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathParser.java @@ -30,7 +30,7 @@ /** * See *

- * Spring uri templates + * Spring uri templates *
* Path and regular expression mappings *

diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java index 553fc0d0f4d..9d8a54687f1 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.config.Configuration; import org.apache.dubbo.common.config.Environment; +import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.nested.OpenAPIConfig; import org.apache.dubbo.rpc.model.FrameworkModel; @@ -28,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_OPENAPI_PREFIX; @@ -87,6 +89,7 @@ private Map readConfigMap() { } int len = H2_SETTINGS_OPENAPI_PREFIX.length(); + Map, TreeMap> valuesMap = new HashMap<>(); for (String fullKey : allKeys) { if (fullKey.length() > len) { char c = fullKey.charAt(len); @@ -101,9 +104,31 @@ private Map readConfigMap() { } else { continue; } + + int brkStart = key.lastIndexOf('['); + if (brkStart > 0) { + try { + String value = configuration.getString(fullKey); + if (StringUtils.isEmpty(value)) { + continue; + } + int index = Integer.parseInt(key.substring(brkStart + 1, key.length() - 1)); + valuesMap + .computeIfAbsent(Pair.of(group, key.substring(0, brkStart)), k -> new TreeMap<>()) + .put(index, value); + } catch (NumberFormatException ignored) { + } + continue; + } + applyConfigValue(map, group, key, configuration.getString(fullKey)); } } + for (Map.Entry, TreeMap> entry : valuesMap.entrySet()) { + Pair pair = entry.getKey(); + String value = StringUtils.join(entry.getValue().values(), ","); + applyConfigValue(map, pair.getKey(), pair.getValue(), value); + } map.computeIfAbsent(Constants.GLOBAL_GROUP, k -> new OpenAPIConfig()); return map; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index 4820985db62..71749300be2 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -80,8 +80,8 @@ private OpenAPINamingStrategy getNamingStrategy() { } public OpenAPI merge(List openAPIs, OpenAPIRequest request) { - OpenAPI model = new OpenAPI(); - Info info = model.getInfo(); + Info info = new Info(); + OpenAPI model = new OpenAPI().setInfo(info); OpenAPIConfig globalConfig = configFactory.getGlobalConfig(); model.setGlobalConfig(globalConfig); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index c4bc8c0b475..1b2b43bc94e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -92,6 +92,9 @@ public OpenAPI resolve(ServiceMeta serviceMeta, Collection> r if (definition == null) { return null; } + if (definition.getConfig() == null) { + definition.setConfig(configFactory.getConfig(definition.getGroup())); + } OperationContext context = new OperationContextImpl(definition, schemaResolver, extensionFactory); for (List registrations : registrationsByMethod) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java index 13498dda719..724c976a582 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java @@ -18,6 +18,8 @@ import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree.Match; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.PropertyMeta; @@ -35,6 +37,7 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -50,6 +53,8 @@ public final class SchemaResolver { private final OpenAPISchemaPredicate[] predicates; private final Map, Optional> schemaMap = CollectionUtils.newConcurrentHashMap(); + private volatile RadixTree classFilter; + public SchemaResolver(FrameworkModel frameworkModel) { configFactory = frameworkModel.getOrRegisterBean(ConfigFactory.class); ExtensionFactory extensionFactory = frameworkModel.getOrRegisterBean(ExtensionFactory.class); @@ -140,7 +145,7 @@ private Schema doResolveClass(Class clazz, ParameterMeta parameter) { return existingSchema.map(s -> new Schema().setTargetSchema(s)).orElseGet(OBJECT::newSchema); } - if (TypeUtils.isSystemType(clazz)) { + if (isClassExcluded(clazz)) { schemaMap.put(clazz, Optional.empty()); return OBJECT.newSchema(); } @@ -217,6 +222,57 @@ private Schema doResolveBeanClass(RestToolKit toolKit, Class clazz, boolean f return beanSchema.addAllOf(resolve(superClass)); } + private boolean isClassExcluded(Class clazz) { + RadixTree classFilter = this.classFilter; + if (classFilter == null) { + synchronized (this) { + classFilter = this.classFilter; + if (classFilter == null) { + classFilter = new RadixTree<>('.'); + for (String prefix : TypeUtils.getSystemPrefixes()) { + addPath(classFilter, prefix); + } + String[] excludes = configFactory.getGlobalConfig().getSchemaClassExcludes(); + if (excludes != null) { + for (String exclude : excludes) { + addPath(classFilter, exclude); + } + } + this.classFilter = classFilter; + } + } + } + + List> matches = classFilter.match('.' + clazz.getName()); + int size = matches.size(); + if (size == 0) { + return false; + } else if (size > 1) { + Collections.sort(matches); + } + return matches.get(size - 1).getValue(); + } + + public static void addPath(RadixTree tree, String path) { + if (path == null) { + return; + } + int size = path.length(); + if (size == 0) { + return; + } + boolean value = true; + if (path.charAt(0) == '!') { + path = path.substring(1); + size--; + value = false; + } + if (path.charAt(size - 1) == '.') { + path += "**"; + } + tree.addPath(path, value); + } + private static final class SchemaChainImpl implements SchemaChain { private final OpenAPISchemaResolver[] resolvers; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java index 59a5e20bea0..54ddde9eedf 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java @@ -133,7 +133,7 @@ public static void addSystemPrefixes(String... prefixes) { public static boolean isSystemType(Class type) { String name = type.getName(); - List systemPrefixes = TypeUtils.getSystemPrefixes(); + List systemPrefixes = getSystemPrefixes(); for (int i = 0, size = systemPrefixes.size(); i < size; i++) { if (name.startsWith(systemPrefixes.get(i))) { return true; diff --git a/pom.xml b/pom.xml index 97936591e10..6fc69afbfd0 100644 --- a/pom.xml +++ b/pom.xml @@ -162,7 +162,8 @@ 3.1.0 1.7.1 0.6.1 - 3.0.2 + 3.0.2 + 3.3.2 6.2.0 @@ -316,6 +317,18 @@ maven-antrun-plugin ${maven_antrun_version} + + org.apache.dubbo + dubbo-maven-plugin + ${dubbo_maven_version} + + + + compile + + + + @@ -383,7 +396,7 @@ org.codehaus.gmavenplus gmavenplus-plugin - ${maven_gmavenplus.version} + ${maven_gmavenplus_version} true From 1b8a57513c48e21b926fd6c1314bf49b0ecbde51 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Mon, 25 Nov 2024 12:23:24 +0800 Subject: [PATCH 15/23] Add error log for OpenAPI processing --- .../rpc/protocol/tri/ExceptionUtils.java | 18 +++++- .../tri/h12/CompositeExceptionHandler.java | 11 +--- .../rest/openapi/DefaultOpenAPIService.java | 56 +++++++++++-------- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ExceptionUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ExceptionUtils.java index 17417b51372..39edd43fe6a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ExceptionUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/ExceptionUtils.java @@ -16,7 +16,10 @@ */ package org.apache.dubbo.rpc.protocol.tri; +import org.apache.dubbo.common.logger.Level; import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import java.io.PrintWriter; import java.io.StringWriter; @@ -30,8 +33,6 @@ public class ExceptionUtils { - private static final int NOT_FOUND = -1; - public static String getStackTrace(final Throwable throwable) { final StringWriter sw = new StringWriter(); final PrintWriter pw = new PrintWriter(sw, true); @@ -82,6 +83,19 @@ public static List getStackFrameList(final Throwable t) { return getStackFrameList(t, Integer.MAX_VALUE); } + public static Level resolveLogLevel(final Throwable t) { + if (t instanceof HttpStatusException) { + int httpStatusCode = ((HttpStatusException) t).getStatusCode(); + if (httpStatusCode < HttpStatus.BAD_REQUEST.getCode()) { + return TripleProtocol.VERBOSE_ENABLED ? Level.INFO : Level.DEBUG; + } + if (httpStatusCode < HttpStatus.INTERNAL_SERVER_ERROR.getCode()) { + return Level.INFO; + } + } + return Level.ERROR; + } + /** * Wrap as runtime exception */ diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompositeExceptionHandler.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompositeExceptionHandler.java index 493b0f6ef94..f9d32724056 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompositeExceptionHandler.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompositeExceptionHandler.java @@ -62,16 +62,7 @@ public Level resolveLogLevel(Throwable throwable) { } } - if (throwable instanceof HttpStatusException) { - int httpStatusCode = ((HttpStatusException) throwable).getStatusCode(); - if (httpStatusCode < HttpStatus.BAD_REQUEST.getCode()) { - return TripleProtocol.VERBOSE_ENABLED ? Level.INFO : Level.DEBUG; - } - if (httpStatusCode < HttpStatus.INTERNAL_SERVER_ERROR.getCode()) { - return Level.INFO; - } - } - return Level.ERROR; + return ExceptionUtils.resolveLogLevel(throwable); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index 1346b411550..808dadc90fa 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.common.logger.FluentLogger; +import org.apache.dubbo.common.logger.Level; import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; import org.apache.dubbo.common.utils.LRUCache; import org.apache.dubbo.common.utils.Pair; @@ -30,6 +31,7 @@ import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RadixTree.Match; @@ -173,34 +175,42 @@ private List resolveOpenAPIs() { @Override public String getDocument(OpenAPIRequest request) { - request = Helper.formatRequest(request); + String path = null; + HttpResult result; + try { + request = Helper.formatRequest(request); - HttpRequest httpRequest = RpcContext.getServiceContext().getRequest(HttpRequest.class); - if (!RequestUtils.isRestRequest(httpRequest)) { - return handleDocument(request); - } + HttpRequest httpRequest = RpcContext.getServiceContext().getRequest(HttpRequest.class); + if (!RequestUtils.isRestRequest(httpRequest)) { + return handleDocument(request); + } - String path = RequestUtils.getPathVariable(httpRequest, "path"); - if (StringUtils.isEmpty(path)) { - throw HttpResult.found(PathUtils.join(httpRequest.path(), "swagger-ui/index.html")) - .toPayload(); - } + path = RequestUtils.getPathVariable(httpRequest, "path"); + if (StringUtils.isEmpty(path)) { + throw HttpResult.found(PathUtils.join(httpRequest.path(), "swagger-ui/index.html")).toPayload(); + } - path = '/' + path; - List> matches = tree.matchRelaxed(path); - if (matches.isEmpty()) { - throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); - } + path = '/' + path; + List> matches = tree.matchRelaxed(path); + if (matches.isEmpty()) { + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); + } - Collections.sort(matches); - Match match = matches.get(0); - HttpResponse httpResponse = RpcContext.getServiceContext().getResponse(HttpResponse.class); - if (request.getFormat() == null) { - request.setFormat(Helper.parseFormat(httpResponse.contentType())); + Collections.sort(matches); + Match match = matches.get(0); + HttpResponse httpResponse = RpcContext.getServiceContext().getResponse(HttpResponse.class); + if (request.getFormat() == null) { + request.setFormat(Helper.parseFormat(httpResponse.contentType())); + } + httpRequest.setAttribute(OpenAPIRequest.class.getName(), request); + httpRequest.setAttribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE, match.getVariableMap()); + result = match.getValue().handle(path, httpRequest, httpResponse); + } catch (Throwable t) { + Level level = ExceptionUtils.resolveLogLevel(t); + LOG.log(level, "Failed to processing OpenAPI request {} for path: '{}'", request, path, t); + throw t; } - httpRequest.setAttribute(OpenAPIRequest.class.getName(), request); - httpRequest.setAttribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE, match.getVariableMap()); - throw match.getValue().handle(path, httpRequest, httpResponse).toPayload(); + throw result.toPayload(); } private String handleDocument(OpenAPIRequest request) { From 10b133d0ae48bf2e6b1d483b66545c413bed1571 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Mon, 25 Nov 2024 12:43:41 +0800 Subject: [PATCH 16/23] Fix route matching order mistake --- .../filter/RestExtensionExecutionFilter.java | 2 +- .../rest/mapping/condition/PathCondition.java | 4 +++- .../rest/mapping/condition/PathExpression.java | 2 +- .../tri/rest/mapping/condition/PathSegment.java | 12 ++++++------ .../tri/rest/openapi/DefaultOpenAPIService.java | 16 ++++++++-------- .../tri/rest/openapi/SchemaResolver.java | 2 +- .../mapping/condition/PathExpressionTest.groovy | 1 + 7 files changed, 21 insertions(+), 18 deletions(-) diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java index d49198ebee8..a1851fe0a48 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/filter/RestExtensionExecutionFilter.java @@ -171,7 +171,7 @@ private RestFilter[] matchFilters(RestFilter[] filters, String path) { if (size > 1) { Collections.sort(matches); } - if (matches.get(size - 1).getValue()) { + if (matches.get(0).getValue()) { continue; } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathCondition.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathCondition.java index 5291c504a72..ab1e7147746 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathCondition.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathCondition.java @@ -105,7 +105,9 @@ public PathCondition match(HttpRequest request) { } } if (matches != null) { - Collections.sort(matches); + if (matches.size() > 1) { + Collections.sort(matches); + } Set result = CollectionUtils.newLinkedHashSet(matches.size()); for (int i = 0, size = matches.size(); i < size; i++) { result.add(matches.get(i).getPath()); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java index c3fa4360f5b..183b718b423 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpression.java @@ -104,7 +104,7 @@ public int compareTo(PathExpression other) { return result; } } - return otherSize - size; + return size - otherSize; } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathSegment.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathSegment.java index 44c50eb852b..e19dbbaf12d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathSegment.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathSegment.java @@ -193,9 +193,9 @@ public int compareTo(PathSegment other) { return comparison; } } - int size = variables == null ? 0 : variables.size(); - int otherSize = other.variables == null ? 0 : other.variables.size(); - return otherSize - size; + int size = variables == null ? 99 : variables.size(); + int otherSize = other.variables == null ? 99 : other.variables.size(); + return size - otherSize; } public enum Type { @@ -212,18 +212,18 @@ public enum Type { LITERAL(1), /** * A wildcard segment. - * E.g.: 't?st*uv' and '/foo/*/bar' + * E.g.: 't?st*uv' */ WILDCARD, /** * A wildcard matching suffix. * Transient type used for parsing, will not be present in the PathExpression - * E.g.: '/foo/**' and '/**' and '/{*bar}' + * E.g.: '/foo/**' or '/**' or '/{*bar}' */ WILDCARD_TAIL, /** * A template variable segment. - * E.g.: '{foo}' + * E.g.: '{foo}' or '/foo/*/bar' */ VARIABLE(10), /** diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index 808dadc90fa..99344f184be 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -25,8 +25,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; import org.apache.dubbo.remoting.http12.HttpResult; -import org.apache.dubbo.remoting.http12.HttpStatus; -import org.apache.dubbo.remoting.http12.exception.HttpStatusException; +import org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException; import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.RpcContext; @@ -176,7 +175,6 @@ private List resolveOpenAPIs() { @Override public String getDocument(OpenAPIRequest request) { String path = null; - HttpResult result; try { request = Helper.formatRequest(request); @@ -187,13 +185,14 @@ public String getDocument(OpenAPIRequest request) { path = RequestUtils.getPathVariable(httpRequest, "path"); if (StringUtils.isEmpty(path)) { - throw HttpResult.found(PathUtils.join(httpRequest.path(), "swagger-ui/index.html")).toPayload(); + String url = PathUtils.join(httpRequest.path(), "swagger-ui/index.html"); + throw HttpResult.found(url).toPayload(); } path = '/' + path; List> matches = tree.matchRelaxed(path); if (matches.isEmpty()) { - throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode()); + throw HttpResult.notFound().toPayload(); } Collections.sort(matches); @@ -204,13 +203,14 @@ public String getDocument(OpenAPIRequest request) { } httpRequest.setAttribute(OpenAPIRequest.class.getName(), request); httpRequest.setAttribute(RestConstants.URI_TEMPLATE_VARIABLES_ATTRIBUTE, match.getVariableMap()); - result = match.getValue().handle(path, httpRequest, httpResponse); + throw match.getValue().handle(path, httpRequest, httpResponse).toPayload(); + } catch (HttpResultPayloadException e) { + throw e; } catch (Throwable t) { - Level level = ExceptionUtils.resolveLogLevel(t); + Level level = ExceptionUtils.resolveLogLevel(ExceptionUtils.unwrap(t)); LOG.log(level, "Failed to processing OpenAPI request {} for path: '{}'", request, path, t); throw t; } - throw result.toPayload(); } private String handleDocument(OpenAPIRequest request) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java index 724c976a582..d67febed9fe 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java @@ -250,7 +250,7 @@ private boolean isClassExcluded(Class clazz) { } else if (size > 1) { Collections.sort(matches); } - return matches.get(size - 1).getValue(); + return matches.get(0).getValue(); } public static void addPath(RadixTree tree, String path) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpressionTest.groovy b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpressionTest.groovy index 1061fcea658..19ad12542fc 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpressionTest.groovy +++ b/dubbo-rpc/dubbo-rpc-triple/src/test/groovy/org/apache/dubbo/rpc/protocol/tri/rest/mapping/condition/PathExpressionTest.groovy @@ -206,6 +206,7 @@ class PathExpressionTest extends Specification { '/one' | '/one' | 0 '/one' | '/two' | 0 '/one/{two}/three' | '/one/{t}/three' | 0 + '/one/two' | '/one/{two}' | -1 '/one/{two}/three' | '/one/*/three' | -1 '/one/*/three' | '/one/**/three' | -1 '/one/two' | '/one' | -1 From a02b471fc774704a43b4dea39fb29a78aca48f64 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Tue, 26 Nov 2024 12:32:25 +0800 Subject: [PATCH 17/23] Enhance parameter resolve --- .../rest/argument/CompositeArgumentResolver.java | 9 +++++++-- .../protocol/tri/rest/mapping/meta/BeanMeta.java | 3 +++ .../rpc/protocol/tri/rest/openapi/Helper.java | 7 ++++++- .../rpc/protocol/tri/rest/util/TypeUtils.java | 16 +++++++++++++--- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java index ffc859b4e30..a3a4a77bd71 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/argument/CompositeArgumentResolver.java @@ -18,6 +18,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.HttpResponse; +import org.apache.dubbo.remoting.http12.rest.ParamType; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; @@ -89,8 +90,12 @@ public NamedValueMeta getNamedValueMeta(ParameterMeta parameter) { } for (ArgumentResolver resolver : resolvers) { - if (resolver.accept(parameter) && resolver instanceof AbstractArgumentResolver) { - return ((AbstractArgumentResolver) resolver).getNamedValueMeta(parameter); + if (resolver.accept(parameter)) { + if (resolver instanceof AbstractArgumentResolver) { + return ((AbstractArgumentResolver) resolver).getNamedValueMeta(parameter); + } else { + return new NamedValueMeta().setParamType(ParamType.Attribute); + } } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java index c689c2101a9..9d74e4ec6b1 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java @@ -242,6 +242,9 @@ public ConstructorParameterMeta[] getParameters() { private ConstructorParameterMeta[] initParameters(RestToolKit toolKit, String prefix, Constructor ct) { Parameter[] cps = ct.getParameters(); int len = cps.length; + if (len == 0) { + return new ConstructorParameterMeta[0]; + } String[] parameterNames = toolKit == null ? null : toolKit.getParameterNames(ct); ConstructorParameterMeta[] parameters = new ConstructorParameterMeta[len]; for (int i = 0; i < len; i++) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index 32fa725abf6..a435b1adb9f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -81,7 +81,12 @@ public static Collection guessHttpMethod(MethodMeta method) { if (GET.name().equals(httpMethod)) { for (ParameterMeta parameter : method.getParameters()) { ParamType paramType = parameter.getNamedValueMeta().paramType(); - if (paramType != null) { + if (paramType == null) { + if (parameter.isSimple()) { + continue; + } + return Arrays.asList(GET.name(), POST.name()); + } else { switch (paramType) { case Form: case Part: diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java index 54ddde9eedf..a96f42aacee 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.common.utils.ConcurrentHashSet; +import org.apache.dubbo.common.utils.StringUtils; import java.io.File; import java.lang.reflect.Array; @@ -128,14 +129,23 @@ public static List getSystemPrefixes() { } public static void addSystemPrefixes(String... prefixes) { - SYSTEM_PREFIXES.addAll(Arrays.asList(prefixes)); + for (String prefix : prefixes) { + if (StringUtils.isNotEmpty(prefix)) { + SYSTEM_PREFIXES.add(prefix); + } + } } public static boolean isSystemType(Class type) { String name = type.getName(); List systemPrefixes = getSystemPrefixes(); - for (int i = 0, size = systemPrefixes.size(); i < size; i++) { - if (name.startsWith(systemPrefixes.get(i))) { + for (int i = systemPrefixes.size() - 1; i >= 0; i--) { + String prefix = systemPrefixes.get(i); + if (prefix.charAt(0) == '!') { + if (name.regionMatches(0, prefix, 1, prefix.length() - 1)) { + return false; + } + } else if (name.startsWith(prefix)) { return true; } } From b80d947f9da2a904c82bee4e170c3bb02032a0cd Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Wed, 27 Nov 2024 02:57:20 +0800 Subject: [PATCH 18/23] Add dubbo bind host to server --- .../dubbo/config/nested/OpenAPIConfig.java | 13 ++ .../http12/message/DefaultHttpRequest.java | 2 +- .../protocol/tri/rest/openapi/Constants.java | 3 + .../rest/openapi/DefaultOpenAPIService.java | 18 ++- .../tri/rest/openapi/DefinitionFilter.java | 58 +++++-- .../tri/rest/openapi/DefinitionMerger.java | 153 +++++++----------- .../tri/rest/openapi/DefinitionResolver.java | 9 ++ .../rpc/protocol/tri/rest/openapi/Helper.java | 27 ++++ .../tri/rest/openapi/model/OpenAPI.java | 13 +- .../rest/openapi/model/SecurityScheme.java | 10 +- 10 files changed, 184 insertions(+), 122 deletions(-) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java index 5460d775df3..a482f0937d3 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/OpenAPIConfig.java @@ -91,6 +91,11 @@ public class OpenAPIConfig implements Serializable { */ private String securityScheme; + /** + * The security. + */ + private String security; + /** * The strategy used to generate operation id and schema name. */ @@ -245,6 +250,14 @@ public void setSecurityScheme(String securityScheme) { this.securityScheme = securityScheme; } + public String getSecurity() { + return security; + } + + public void setSecurity(String security) { + this.security = security; + } + public String getNameStrategy() { return nameStrategy; } diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java index 5ed4c0ef9bb..f3166707b4c 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultHttpRequest.java @@ -300,7 +300,7 @@ public String scheme() { if (isHttp2()) { scheme = headers.getFirst(PseudoHeaderName.SCHEME.value()); } - return scheme == null ? HttpConstants.HTTPS : scheme; + return scheme == null ? HttpConstants.HTTP : scheme; } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java index f7b0fe1cbb6..7798481a2a2 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java @@ -29,5 +29,8 @@ public final class Constants { public static final String X_JAVA_METHOD = "x-java-method"; public static final String X_JAVA_PARAM = "x-java-param"; + public static final String DUBBO_SERVER = "Dubbo Server"; + public static final String REFERER = "referer"; + private Constants() {} } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index 99344f184be..a7c4538fc5d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -113,7 +113,7 @@ public HttpResult handle(String path, HttpRequest httpRequest, HttpResponse h } return HttpResult.builder() .contentType(MediaType.APPLICATION + '/' + request.getFormat()) - .body(handleDocument(request).getBytes(StandardCharsets.UTF_8)) + .body(handleDocument(request, httpRequest).getBytes(StandardCharsets.UTF_8)) .build(); } @@ -180,7 +180,7 @@ public String getDocument(OpenAPIRequest request) { HttpRequest httpRequest = RpcContext.getServiceContext().getRequest(HttpRequest.class); if (!RequestUtils.isRestRequest(httpRequest)) { - return handleDocument(request); + return handleDocument(request, null); } path = RequestUtils.getPathVariable(httpRequest, "path"); @@ -213,12 +213,22 @@ public String getDocument(OpenAPIRequest request) { } } - private String handleDocument(OpenAPIRequest request) { + private String handleDocument(OpenAPIRequest request, HttpRequest httpRequest) { if (Boolean.FALSE.equals(configFactory.getGlobalConfig().getCache())) { return definitionEncoder.encode(getOpenAPI(request), request); } - String cacheKey = request.toString(); + StringBuilder sb = new StringBuilder(); + if (httpRequest != null) { + String host = httpRequest.serverHost(); + if (host != null) { + String referer = httpRequest.header(Constants.REFERER); + sb.append(referer != null && referer.contains(host) ? '/' : host); + } + } + sb.append('|').append(request.toString()); + + String cacheKey = sb.toString(); SoftReference ref = cache.get(cacheKey); if (ref != null) { String value = ref.get(); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java index f9064de1afc..741c1fc212d 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.remoting.http12.HttpMethods; +import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.ApiResponse; @@ -31,6 +32,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.SecurityScheme; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; import java.util.Iterator; import java.util.List; @@ -52,32 +54,58 @@ public DefinitionFilter(FrameworkModel frameworkModel) { public OpenAPI filter(OpenAPI openAPI, OpenAPIRequest request) { OpenAPIFilter[] filters = extensionFactory.getExtensions(OpenAPIFilter.class, request.getGroup()); - if (filters.length == 0) { - return openAPI; - } - Context context = new ContextImpl(openAPI, schemaResolver, extensionFactory, request); - for (OpenAPIFilter filter : filters) { - openAPI = filter.filterOpenAPI(openAPI, context); - if (openAPI == null) { - return null; + + if (filters.length > 0) { + for (OpenAPIFilter filter : filters) { + openAPI = filter.filterOpenAPI(openAPI, context); + if (openAPI == null) { + return null; + } } - } - filterPaths(openAPI, filters, context); + filterPaths(openAPI, filters, context); - filterComponents(openAPI, filters, context); + filterComponents(openAPI, filters, context); - for (OpenAPIFilter filter : filters) { - openAPI = filter.filterOpenAPICompletion(openAPI, context); - if (openAPI == null) { - return null; + for (OpenAPIFilter filter : filters) { + openAPI = filter.filterOpenAPICompletion(openAPI, context); + if (openAPI == null) { + return null; + } } } + filterServer(openAPI, context); + return openAPI; } + private static void filterServer(OpenAPI openAPI, Context context) { + List servers = openAPI.getServers(); + if (servers == null || servers.size() != 1) { + return; + } + Server server = servers.get(0); + if (!Constants.DUBBO_SERVER.equals(server.getDescription())) { + return; + } + HttpRequest httpRequest = context.getHttpRequest(); + if (httpRequest == null) { + return; + } + String host = httpRequest.serverHost(); + if (host == null) { + return; + } + String referer = httpRequest.header(Constants.REFERER); + if (referer != null && referer.contains(host)) { + servers.clear(); + } else { + server.setUrl(httpRequest.scheme() + "://" + host); + } + } + private void filterPaths(OpenAPI openAPI, OpenAPIFilter[] filters, Context context) { Map paths = openAPI.getPaths(); if (paths == null) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index 71749300be2..e172c2aa304 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -43,6 +43,8 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; +import java.lang.reflect.Type; +import java.util.Arrays; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; @@ -53,12 +55,17 @@ import java.util.Objects; import java.util.Set; import java.util.TreeMap; +import java.util.stream.Collectors; + +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setValue; final class DefinitionMerger { private static final FluentLogger LOG = FluentLogger.of(DefinitionMerger.class); private static final String NAMING_STRATEGY_PREFIX = "naming-strategy-"; private static final String NAMING_STRATEGY_DEFAULT = "default"; + private static Type SECURITY_SCHEMES_TYPE; + private static Type SECURITY_TYPE; private final ExtensionFactory extensionFactory; private final ConfigFactory configFactory; @@ -85,8 +92,8 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { OpenAPIConfig globalConfig = configFactory.getGlobalConfig(); model.setGlobalConfig(globalConfig); + applyConfig(model, globalConfig); if (openAPIs.isEmpty()) { - applyConfig(model, globalConfig); return model; } @@ -106,7 +113,6 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { OpenAPIConfig config = configFactory.getConfig(group); model.setConfig(config); - applyConfig(model, config); for (OpenAPI api : openAPIs) { if (isServiceNotMatch(api.getMeta().getServiceInterface(), services)) { @@ -124,7 +130,7 @@ public OpenAPI merge(List openAPIs, OpenAPIRequest request) { mergeTags(model, api); } - applyConfig(model, globalConfig); + applyConfig(model, config); addSchemas(model, version, group); @@ -141,67 +147,55 @@ private void applyConfig(OpenAPI api, OpenAPIConfig config) { } Info info = api.getInfo(); - if (info.getTitle() == null) { - info.setTitle(config.getInfoTitle()); - } - if (info.getDescription() == null) { - info.setDescription(config.getInfoDescription()); - } - if (info.getVersion() == null) { - info.setVersion(config.getInfoVersion()); - } + setValue(info::setTitle, config::getInfoTitle); + setValue(info::setDescription, config::getInfoDescription); + setValue(info::setVersion, config::getInfoVersion); Contact contact = info.getContact(); if (contact == null) { info.setContact(contact = new Contact()); } - if (contact.getName() == null) { - contact.setName(config.getInfoContactName()); - } - if (contact.getUrl() == null) { - contact.setUrl(config.getInfoContactUrl()); - } - if (contact.getEmail() == null) { - contact.setEmail(config.getInfoContactEmail()); - } - - if (info.getVersion() == null) { - info.setVersion(config.getInfoVersion()); - } + setValue(contact::setName, config::getInfoContactName); + setValue(contact::setUrl, config::getInfoContactUrl); + setValue(contact::setEmail, config::getInfoContactEmail); ExternalDocs externalDocs = api.getExternalDocs(); if (externalDocs == null) { api.setExternalDocs(externalDocs = new ExternalDocs()); } - if (externalDocs.getDescription() == null) { - externalDocs.setDescription(config.getExternalDocsDescription()); - } - if (externalDocs.getUrl() == null) { - externalDocs.setUrl(config.getExternalDocsUrl()); - } + setValue(externalDocs::setDescription, config::getExternalDocsDescription); + setValue(externalDocs::setUrl, config::getExternalDocsUrl); - if (api.getServers() == null) { - String[] servers = config.getServers(); - if (servers != null) { - for (String server : servers) { - api.addServer(new Server().setUrl(server)); - } - } + String[] servers = config.getServers(); + if (servers != null) { + api.setServers(Arrays.stream(servers).map(Helper::parseServer).collect(Collectors.toList())); } Components components = api.getComponents(); if (api.getComponents() == null) { api.setComponents(components = new Components()); } - if (components.getSecuritySchemes() == null) { - String securityScheme = config.getSecurityScheme(); - if (securityScheme != null) { - try { - components.setSecuritySchemes(JsonUtils.toJavaObject( - securityScheme, - Components.class.getDeclaredField("securitySchemes").getGenericType())); - } catch (NoSuchFieldException ignored) { + + String securityScheme = config.getSecurityScheme(); + if (securityScheme != null) { + try { + if (SECURITY_SCHEMES_TYPE == null) { + SECURITY_SCHEMES_TYPE = + Components.class.getDeclaredField("securitySchemes").getGenericType(); } + components.setSecuritySchemes(JsonUtils.toJavaObject(securityScheme, SECURITY_SCHEMES_TYPE)); + } catch (NoSuchFieldException ignored) { + } + } + + String security = config.getSecurity(); + if (security != null) { + try { + if (SECURITY_TYPE == null) { + SECURITY_TYPE = OpenAPI.class.getDeclaredField("security").getGenericType(); + } + api.setSecurity(JsonUtils.toJavaObject(securityScheme, SECURITY_TYPE)); + } catch (NoSuchFieldException ignored) { } } } @@ -209,31 +203,20 @@ private void applyConfig(OpenAPI api, OpenAPIConfig config) { private void mergeBasic(OpenAPI api, OpenAPI from) { mergeInfo(api, from); - List fromServers = from.getServers(); - if (fromServers != null) { - List servers = api.getServers(); - if (servers == null) { - api.setServers(Node.clone(fromServers)); - } + if (api.getServers() == null) { + api.setServers(Node.clone(from.getServers())); } List fromSecurity = from.getSecurity(); - if (fromSecurity != null) { - List security = api.getSecurity(); - if (security == null) { - api.setSecurity(Node.clone(fromSecurity)); - } + if (api.getSecurity() == null) { + api.setSecurity(Node.clone(fromSecurity)); } ExternalDocs fromExternalDocs = from.getExternalDocs(); if (fromExternalDocs != null) { ExternalDocs externalDocs = api.getExternalDocs(); - if (externalDocs.getDescription() == null) { - externalDocs.setDescription(fromExternalDocs.getDescription()); - } - if (externalDocs.getUrl() == null) { - externalDocs.setUrl(fromExternalDocs.getUrl()); - } + setValue(externalDocs::setDescription, fromExternalDocs::getDescription); + setValue(externalDocs::setUrl, fromExternalDocs::getUrl); externalDocs.addExtensions(fromExternalDocs.getExtensions()); } @@ -247,54 +230,30 @@ private void mergeInfo(OpenAPI api, OpenAPI from) { } Info info = api.getInfo(); - if (info.getTitle() == null) { - info.setTitle(fromInfo.getTitle()); - } - if (info.getSummary() == null) { - info.setDescription(fromInfo.getSummary()); - } - if (info.getDescription() == null) { - info.setDescription(fromInfo.getDescription()); - } - if (info.getTermsOfService() == null) { - info.setTermsOfService(fromInfo.getTermsOfService()); - } + setValue(info::setTitle, fromInfo::getTitle); + setValue(info::setSummary, fromInfo::getSummary); + setValue(info::setDescription, fromInfo::getDescription); + setValue(info::setTermsOfService, fromInfo::getTermsOfService); + setValue(info::setVersion, fromInfo::getVersion); Contact fromContact = fromInfo.getContact(); if (fromContact != null) { Contact contact = info.getContact(); - if (contact.getName() == null) { - contact.setName(fromContact.getName()); - } - if (contact.getUrl() == null) { - contact.setUrl(fromContact.getUrl()); - } - if (contact.getEmail() == null) { - contact.setEmail(fromContact.getEmail()); - } + setValue(contact::setName, fromContact::getName); + setValue(contact::setUrl, fromContact::getUrl); + setValue(contact::setEmail, fromContact::getEmail); - if (info.getVersion() == null) { - info.setVersion(fromInfo.getVersion()); - } contact.addExtensions(fromContact.getExtensions()); } License fromLicense = fromInfo.getLicense(); if (fromLicense != null) { License license = info.getLicense(); - if (license.getName() == null) { - license.setName(fromLicense.getName()); - } - if (license.getUrl() == null) { - license.setUrl(fromLicense.getUrl()); - } + setValue(license::setName, fromLicense::getName); + setValue(license::setUrl, fromLicense::getUrl); license.addExtensions(fromLicense.getExtensions()); } - if (info.getVersion() == null) { - info.setVersion(fromInfo.getVersion()); - } - info.addExtensions(fromInfo.getExtensions()); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index 1b2b43bc94e..24c2f90371f 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +import org.apache.dubbo.common.URL; import org.apache.dubbo.common.logger.FluentLogger; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.StringUtils; @@ -48,6 +49,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.RequestBody; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; import java.util.ArrayList; @@ -96,6 +98,13 @@ public OpenAPI resolve(ServiceMeta serviceMeta, Collection> r definition.setConfig(configFactory.getConfig(definition.getGroup())); } + if (CollectionUtils.isEmpty(definition.getServers())) { + URL url = serviceMeta.getUrl(); + definition.addServer(new Server() + .setUrl("http://" + url.getHost() + ':' + url.getPort()) + .setDescription(Constants.DUBBO_SERVER)); + } + OperationContext context = new OperationContextImpl(definition, schemaResolver, extensionFactory); for (List registrations : registrationsByMethod) { String mainPath = null; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index a435b1adb9f..135f466c904 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -22,6 +22,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Server; import java.util.ArrayList; import java.util.Arrays; @@ -29,6 +30,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Supplier; import static org.apache.dubbo.remoting.http12.HttpMethods.DELETE; import static org.apache.dubbo.remoting.http12.HttpMethods.GET; @@ -227,6 +230,30 @@ public static Map toProperties(String[] array) { return properties; } + public static Server parseServer(String server) { + String url = null; + String description = null; + int equalIndex = server.indexOf('='); + if (equalIndex > 0) { + int index = server.indexOf("://"); + if (index == -1 || index > equalIndex) { + url = trim(server.substring(equalIndex + 1)); + description = trim(server.substring(0, equalIndex)); + } + } + if (url == null) { + url = trim(server); + } + return new Server().setDescription(description).setUrl(url); + } + + public static void setValue(Consumer setter, Supplier getter) { + String value = trim(getter.get()); + if (value != null) { + setter.accept(value); + } + } + public static String pathToRef(String path) { StringBuilder sb = new StringBuilder(path.length() + 16); sb.append("#/paths/"); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java index 1846f56a4fb..1a3d9650139 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java @@ -75,10 +75,17 @@ public OpenAPI setServers(List servers) { } public OpenAPI addServer(Server server) { - if (servers == null) { - servers = new ArrayList<>(); + List thisServers = servers; + if (thisServers == null) { + servers = thisServers = new ArrayList<>(); + } else { + for (int i = 0, size = thisServers.size(); i < size; i++) { + if (thisServers.get(i).getUrl().equals(server.getUrl())) { + return this; + } + } } - servers.add(server); + thisServers.add(server); return this; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java index 7ac3f4e0d01..74e297878eb 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java @@ -26,6 +26,7 @@ public enum Type { APIKEY("apiKey"), HTTP("http"), OAUTH2("oauth2"), + MUTUAL_TLS("mutualTLS"), OPEN_ID_CONNECT("openIdConnect"); private final String value; @@ -147,10 +148,15 @@ public SecurityScheme clone() { @Override public Map writeTo(Map node, Context context) { - write(node, "type", type); + if (type == null) { + return node; + } + write(node, "type", type.toString()); write(node, "description", description); write(node, "name", name); - write(node, "in", in); + if (in != null) { + write(node, "in", in.toString()); + } write(node, "scheme", scheme); write(node, "bearerFormat", bearerFormat); write(node, "flows", flows, context); From 69fe8bb4736d89e8d6dbe87d70c95b28eba51197 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Wed, 27 Nov 2024 12:11:58 +0800 Subject: [PATCH 19/23] Refine DefinitionMerger --- .../dubbo-demo-spring-boot-servlet/pom.xml | 1 + .../dubbo/springboot/demo/servlet/Animal.java | 46 --- .../dubbo/springboot/demo/servlet/Cat.java | 33 -- .../dubbo/springboot/demo/servlet/Dog.java | 30 -- .../demo/servlet/GreeterService.java | 8 - .../demo/servlet/GreeterServiceImpl.java | 5 - .../dubbo/springboot/demo/servlet/Live.java | 46 --- .../springboot/demo/servlet/sub/Dog.java | 32 -- .../src/main/resources/application.yml | 5 - .../SwaggerOpenAPIDefinitionResolver.java | 76 ++++- .../tri/servlet/HttpMetadataAdapter.java | 7 + .../protocol/tri/rest/openapi/Constants.java | 9 +- .../tri/rest/openapi/DefinitionFilter.java | 4 +- .../tri/rest/openapi/DefinitionMerger.java | 315 +++++++++--------- .../tri/rest/openapi/DefinitionResolver.java | 2 +- .../rpc/protocol/tri/rest/openapi/Helper.java | 25 +- .../tri/rest/openapi/PrimitiveSchema.java | 5 +- .../tri/rest/openapi/SchemaResolver.java | 47 +-- .../tri/rest/openapi/model/Operation.java | 4 +- .../tri/rest/openapi/model/Schema.java | 2 +- .../basic/BasicOpenAPIDefinitionResolver.java | 20 +- .../rpc/protocol/tri/rest/util/TypeUtils.java | 37 +- 22 files changed, 339 insertions(+), 420 deletions(-) delete mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java delete mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java delete mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java delete mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java delete mode 100644 dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/sub/Dog.java diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml index 08a74147935..c9728a77575 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml @@ -93,6 +93,7 @@ spring-boot-starter-log4j2
+ com.github.therapi therapi-runtime-javadoc-scribe diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java deleted file mode 100644 index 07079a375fa..00000000000 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Animal.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.springboot.demo.servlet; - -/** - * The animal - */ -public class Animal extends Live { - - /** - * The name of the animal - */ - private String name; - - private int age; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } -} diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java deleted file mode 100644 index be97dbfcc7e..00000000000 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Cat.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.springboot.demo.servlet; - -public class Cat extends Animal { - - /** - * The length of the cat - */ - private int length; - - public int getLength() { - return length; - } - - public void setLength(int length) { - this.length = length; - } -} diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java deleted file mode 100644 index 063e886cb77..00000000000 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Dog.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.springboot.demo.servlet; - -public class Dog extends Animal { - - private String color; - - public String getColor() { - return color; - } - - public void setColor(String color) { - this.color = color; - } -} diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java index 3f279ec58e7..e777429e71d 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterService.java @@ -41,12 +41,4 @@ public interface GreeterService { * Sends greetings with bi streaming */ StreamObserver sayHelloBiStream(StreamObserver responseObserver); - - /** - * Create an animal - * @param cat the cat - * @param dog the dog - * @return the animal - */ - Animal createAnimal(Cat cat, Dog dog); } diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterServiceImpl.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterServiceImpl.java index 8340b7a9a3d..ef699dd69d7 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterServiceImpl.java +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/GreeterServiceImpl.java @@ -74,11 +74,6 @@ public void onCompleted() { }; } - @Override - public Animal createAnimal(Cat cat, Dog dog) { - return cat; - } - private static HelloReply toReply(String message) { HelloReply reply = new HelloReply(); reply.setMessage(message); diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java deleted file mode 100644 index 40453e30956..00000000000 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/Live.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.springboot.demo.servlet; - -/** - * The live - */ -public class Live { - - /** - * The alive - */ - private boolean alive; - - private byte[] raw; - - public boolean isAlive() { - return alive; - } - - public void setAlive(boolean alive) { - this.alive = alive; - } - - public byte[] getRaw() { - return raw; - } - - public void setRaw(byte[] raw) { - this.raw = raw; - } -} diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/sub/Dog.java b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/sub/Dog.java deleted file mode 100644 index 89916a98b5d..00000000000 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/java/org/apache/dubbo/springboot/demo/servlet/sub/Dog.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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.springboot.demo.servlet.sub; - -import org.apache.dubbo.springboot.demo.servlet.Animal; - -public class Dog extends Animal { - - private String color; - - public String getColor() { - return color; - } - - public void setColor(String color) { - this.color = color; - } -} diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml index 88754252174..0ff09750d54 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/src/main/resources/application.yml @@ -30,11 +30,6 @@ dubbo: openapi: enabled: true cache: false - schema-flatten: false - schema-class-excludes: - - a. - - "!b.c." - - "!org.apache.dubbo.springboot.demo." servlet: enabled: true registry: diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java index 1303836c2ac..e34c1c98712 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java +++ b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java @@ -25,6 +25,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIDefinitionResolver; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaPredicate; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPISchemaResolver; @@ -35,15 +36,20 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; +import java.util.Arrays; import java.util.Map; import io.swagger.v3.oas.annotations.ExternalDocumentation; import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.extensions.ExtensionProperty; +import io.swagger.v3.oas.annotations.media.Schema.AccessMode; +import io.swagger.v3.oas.annotations.media.Schema.RequiredMode; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setValue; import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim; @Activate(order = 50, onClass = "io.swagger.v3.oas.annotations.OpenAPIDefinition") @@ -98,7 +104,14 @@ public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain ch openAPI.setExternalDocs(toExternalDocs(anno.externalDocs())); - openAPI.setExtensions(toProperties(anno.extensions())); + Map properties = toProperties(anno.extensions()); + if (properties != null) { + String group = properties.remove(Constants.X_API_GROUP); + if (group != null) { + openAPI.setGroup(group); + } + openAPI.setExtensions(properties); + } return openAPI; } @@ -142,27 +155,74 @@ public Operation resolve(Operation operation, MethodMeta methodMeta, OperationCo for (String tag : anno.tags()) { operation.addTag(tag); } + Map properties = toProperties(anno.extensions()); + if (properties != null) { + String group = properties.remove(Constants.X_API_GROUP); + if (group != null) { + operation.setGroup(group); + } + String version = properties.remove(Constants.X_API_VERSION); + if (version != null) { + operation.setVersion(version); + } + operation.setExtensions(properties); + } return operation .setSummary(trim(anno.summary())) .setDescription(trim(anno.description())) .setExternalDocs(toExternalDocs(anno.externalDocs())) .setOperationId(trim(anno.operationId())) - .setDeprecated(anno.deprecated() ? Boolean.TRUE : null) - .setExtensions(toProperties(anno.extensions())); + .setDeprecated(anno.deprecated() ? Boolean.TRUE : null); } @Override public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChain chain) { - AnnotationMeta meta = + AnnotationMeta annoMeta = parameter.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); - if (meta == null) { + if (annoMeta == null) { return chain.resolve(parameter, context); } - io.swagger.v3.oas.annotations.media.Schema schema = meta.getAnnotation(); - if (schema.hidden() || parameter.isHierarchyAnnotated(Hidden.class)) { + io.swagger.v3.oas.annotations.media.Schema anno = annoMeta.getAnnotation(); + if (anno.hidden() || parameter.isHierarchyAnnotated(Hidden.class)) { return null; } - return chain.resolve(parameter, context); + Schema schema = chain.resolve(parameter, context); + if (schema == null) { + return null; + } + + Map properties = toProperties(anno.extensions()); + if (properties != null) { + String group = properties.remove(Constants.X_API_GROUP); + if (group != null) { + schema.setGroup(group); + } + String version = properties.remove(Constants.X_API_VERSION); + if (version != null) { + schema.setVersion(version); + } + schema.setExtensions(properties); + } + + setValue(anno::type, v -> schema.setType(Type.valueOf(v))); + setValue(anno::format, schema::setFormat); + setValue(anno::name, schema::setName); + setValue(anno::title, schema::setTitle); + setValue(anno::description, schema::setDescription); + setValue(anno::defaultValue, schema::setDefaultValue); + setValue(anno::pattern, schema::setPattern); + setValue(anno::example, schema::setExample); + String[] enumItems = trim(anno.allowableValues()); + if (enumItems != null) { + schema.setEnumeration(Arrays.asList(enumItems)); + } + schema.setRequired(anno.requiredMode() == RequiredMode.REQUIRED ? Boolean.TRUE : null); + schema.setReadOnly(anno.accessMode() == AccessMode.READ_ONLY ? Boolean.TRUE : null); + schema.setWriteOnly(anno.accessMode() == AccessMode.WRITE_ONLY ? Boolean.TRUE : null); + schema.setNullable(anno.nullable() ? Boolean.TRUE : null); + schema.setDeprecated(anno.deprecated() ? Boolean.TRUE : null); + + return schema; } @Override diff --git a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java index 4ebfbf770c3..829d046497a 100644 --- a/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java +++ b/dubbo-plugin/dubbo-triple-servlet/src/main/java/org/apache/dubbo/rpc/protocol/tri/servlet/HttpMetadataAdapter.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.rpc.protocol.tri.servlet; +import org.apache.dubbo.remoting.http12.HttpHeaderNames; import org.apache.dubbo.remoting.http12.HttpHeaders; import org.apache.dubbo.remoting.http12.h2.Http2Header; @@ -23,6 +24,8 @@ import java.util.Enumeration; +import io.netty.handler.codec.http2.Http2Headers.PseudoHeaderName; + public final class HttpMetadataAdapter implements Http2Header { private final HttpServletRequest request; @@ -50,6 +53,10 @@ public HttpHeaders headers() { headers.add(key, ven.nextElement()); } } + headers.add(PseudoHeaderName.METHOD.value(), method()); + headers.add(PseudoHeaderName.SCHEME.value(), request.getScheme()); + headers.add(PseudoHeaderName.AUTHORITY.value(), request.getHeader(HttpHeaderNames.HOST.getName())); + headers.add(PseudoHeaderName.PROTOCOL.value(), request.getProtocol()); this.headers = headers; } return headers; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java index 7798481a2a2..91dc4827d8e 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java @@ -25,11 +25,14 @@ public final class Constants { public static final String DEFAULT_GROUP = "default"; public static final String GLOBAL_GROUP = ""; - public static final String X_JAVA_TYPE = "x-java-type"; + public static final String X_API_GROUP = "x-api-group"; + public static final String X_API_VERSION = "x-api-version"; + + public static final String X_JAVA_CLASS = "x-java-class"; public static final String X_JAVA_METHOD = "x-java-method"; - public static final String X_JAVA_PARAM = "x-java-param"; + public static final String X_JAVA_METHOD_DESCRIPTOR = "x-java-method-descriptor"; - public static final String DUBBO_SERVER = "Dubbo Server"; + public static final String DUBBO_DEFAULT_SERVER = "Dubbo Default Server"; public static final String REFERER = "referer"; private Constants() {} diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java index 741c1fc212d..2c6b037c6c6 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java @@ -87,7 +87,7 @@ private static void filterServer(OpenAPI openAPI, Context context) { return; } Server server = servers.get(0); - if (!Constants.DUBBO_SERVER.equals(server.getDescription())) { + if (!Constants.DUBBO_DEFAULT_SERVER.equals(server.getDescription())) { return; } HttpRequest httpRequest = context.getHttpRequest(); @@ -375,6 +375,8 @@ private void filterSchema( filterSchema(it::next, it::set, schema, filters, context); } } + + filterSchema(schema::getNot, schema::setNot, schema, filters, context); } private void filterSecuritySchemes(Components components, OpenAPIFilter[] filters, Context context) { diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index e172c2aa304..f8be87a0165 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -88,92 +88,93 @@ private OpenAPINamingStrategy getNamingStrategy() { public OpenAPI merge(List openAPIs, OpenAPIRequest request) { Info info = new Info(); - OpenAPI model = new OpenAPI().setInfo(info); + OpenAPI target = new OpenAPI().setInfo(info); OpenAPIConfig globalConfig = configFactory.getGlobalConfig(); - model.setGlobalConfig(globalConfig); - applyConfig(model, globalConfig); + target.setGlobalConfig(globalConfig); + applyConfig(target, globalConfig); if (openAPIs.isEmpty()) { - return model; + return target; } String group = request.getGroup(); - String version = request.getVersion(); - String[] tags = request.getTag(); - String[] services = request.getService(); - if (group == null) { group = Constants.DEFAULT_GROUP; } - model.setGroup(group); + target.setGroup(group); + + String version = request.getVersion(); if (version != null) { info.setVersion(version); } - model.setOpenapi(Helper.formatSpecVersion(request.getOpenapi())); + target.setOpenapi(Helper.formatSpecVersion(request.getOpenapi())); OpenAPIConfig config = configFactory.getConfig(group); - model.setConfig(config); + target.setConfig(config); - for (OpenAPI api : openAPIs) { - if (isServiceNotMatch(api.getMeta().getServiceInterface(), services)) { + String[] tags = request.getTag(); + String[] services = request.getService(); + for (int i = openAPIs.size() - 1; i >= 0; i--) { + OpenAPI source = openAPIs.get(i); + if (isServiceNotMatch(source.getMeta().getServiceInterface(), services)) { continue; } - if (group.equals(api.getGroup())) { - mergeBasic(model, api); + if (group.equals(source.getGroup())) { + mergeBasic(target, source); } - mergePaths(model, api, group, version, tags); + mergePaths(target, source, group, version, tags); - mergeSecuritySchemes(model, api); + mergeSecuritySchemes(target, source); - mergeTags(model, api); + mergeTags(target, source); } - applyConfig(model, config); + applyConfig(target, config); - addSchemas(model, version, group); + addSchemas(target, version, group); - completeOperations(model); + completeOperations(target); - completeModel(model); + completeModel(target); - return model; + return target; } - private void applyConfig(OpenAPI api, OpenAPIConfig config) { + private void applyConfig(OpenAPI target, OpenAPIConfig config) { if (config == null) { return; } - Info info = api.getInfo(); - setValue(info::setTitle, config::getInfoTitle); - setValue(info::setDescription, config::getInfoDescription); - setValue(info::setVersion, config::getInfoVersion); + Info info = target.getInfo(); + setValue(config::getInfoTitle, info::setTitle); + setValue(config::getInfoDescription, info::setDescription); + setValue(config::getInfoVersion, info::setVersion); Contact contact = info.getContact(); if (contact == null) { info.setContact(contact = new Contact()); } - setValue(contact::setName, config::getInfoContactName); - setValue(contact::setUrl, config::getInfoContactUrl); - setValue(contact::setEmail, config::getInfoContactEmail); + setValue(config::getInfoContactName, contact::setName); + setValue(config::getInfoContactUrl, contact::setUrl); + setValue(config::getInfoContactEmail, contact::setEmail); - ExternalDocs externalDocs = api.getExternalDocs(); + ExternalDocs externalDocs = target.getExternalDocs(); if (externalDocs == null) { - api.setExternalDocs(externalDocs = new ExternalDocs()); + target.setExternalDocs(externalDocs = new ExternalDocs()); } - setValue(externalDocs::setDescription, config::getExternalDocsDescription); - setValue(externalDocs::setUrl, config::getExternalDocsUrl); + setValue(config::getExternalDocsDescription, externalDocs::setDescription); + setValue(config::getExternalDocsUrl, externalDocs::setUrl); String[] servers = config.getServers(); if (servers != null) { - api.setServers(Arrays.stream(servers).map(Helper::parseServer).collect(Collectors.toList())); + target.setServers(Arrays.stream(servers).map(Helper::parseServer).collect(Collectors.toList())); } - Components components = api.getComponents(); - if (api.getComponents() == null) { - api.setComponents(components = new Components()); + Components components = target.getComponents(); + if (target.getComponents() == null) { + target.setComponents(components = new Components()); } String securityScheme = config.getSecurityScheme(); @@ -194,86 +195,86 @@ private void applyConfig(OpenAPI api, OpenAPIConfig config) { if (SECURITY_TYPE == null) { SECURITY_TYPE = OpenAPI.class.getDeclaredField("security").getGenericType(); } - api.setSecurity(JsonUtils.toJavaObject(securityScheme, SECURITY_TYPE)); + target.setSecurity(JsonUtils.toJavaObject(securityScheme, SECURITY_TYPE)); } catch (NoSuchFieldException ignored) { } } } - private void mergeBasic(OpenAPI api, OpenAPI from) { - mergeInfo(api, from); + private void mergeBasic(OpenAPI target, OpenAPI source) { + mergeInfo(target, source); - if (api.getServers() == null) { - api.setServers(Node.clone(from.getServers())); + if (target.getServers() == null) { + target.setServers(Node.clone(source.getServers())); } - List fromSecurity = from.getSecurity(); - if (api.getSecurity() == null) { - api.setSecurity(Node.clone(fromSecurity)); + List sourceSecurity = source.getSecurity(); + if (target.getSecurity() == null) { + target.setSecurity(Node.clone(sourceSecurity)); } - ExternalDocs fromExternalDocs = from.getExternalDocs(); - if (fromExternalDocs != null) { - ExternalDocs externalDocs = api.getExternalDocs(); - setValue(externalDocs::setDescription, fromExternalDocs::getDescription); - setValue(externalDocs::setUrl, fromExternalDocs::getUrl); - externalDocs.addExtensions(fromExternalDocs.getExtensions()); + ExternalDocs sourceExternalDocs = source.getExternalDocs(); + if (sourceExternalDocs != null) { + ExternalDocs targetExternalDocs = target.getExternalDocs(); + setValue(sourceExternalDocs::getDescription, targetExternalDocs::setDescription); + setValue(sourceExternalDocs::getUrl, targetExternalDocs::setUrl); + targetExternalDocs.addExtensions(sourceExternalDocs.getExtensions()); } - api.addExtensions(from.getExtensions()); + target.addExtensions(source.getExtensions()); } - private void mergeInfo(OpenAPI api, OpenAPI from) { - Info fromInfo = from.getInfo(); - if (fromInfo == null) { + private void mergeInfo(OpenAPI target, OpenAPI source) { + Info sourceInfo = source.getInfo(); + if (sourceInfo == null) { return; } - Info info = api.getInfo(); - setValue(info::setTitle, fromInfo::getTitle); - setValue(info::setSummary, fromInfo::getSummary); - setValue(info::setDescription, fromInfo::getDescription); - setValue(info::setTermsOfService, fromInfo::getTermsOfService); - setValue(info::setVersion, fromInfo::getVersion); + Info info = target.getInfo(); + setValue(sourceInfo::getTitle, info::setTitle); + setValue(sourceInfo::getSummary, info::setSummary); + setValue(sourceInfo::getDescription, info::setDescription); + setValue(sourceInfo::getTermsOfService, info::setTermsOfService); + setValue(sourceInfo::getVersion, info::setVersion); - Contact fromContact = fromInfo.getContact(); - if (fromContact != null) { + Contact sourceContact = sourceInfo.getContact(); + if (sourceContact != null) { Contact contact = info.getContact(); - setValue(contact::setName, fromContact::getName); - setValue(contact::setUrl, fromContact::getUrl); - setValue(contact::setEmail, fromContact::getEmail); + setValue(sourceContact::getName, contact::setName); + setValue(sourceContact::getUrl, contact::setUrl); + setValue(sourceContact::getEmail, contact::setEmail); - contact.addExtensions(fromContact.getExtensions()); + contact.addExtensions(sourceContact.getExtensions()); } - License fromLicense = fromInfo.getLicense(); - if (fromLicense != null) { + License sourceLicense = sourceInfo.getLicense(); + if (sourceLicense != null) { License license = info.getLicense(); - setValue(license::setName, fromLicense::getName); - setValue(license::setUrl, fromLicense::getUrl); - license.addExtensions(fromLicense.getExtensions()); + setValue(sourceLicense::getName, license::setName); + setValue(sourceLicense::getUrl, license::setUrl); + license.addExtensions(sourceLicense.getExtensions()); } - info.addExtensions(fromInfo.getExtensions()); + info.addExtensions(sourceInfo.getExtensions()); } - private void mergePaths(OpenAPI api, OpenAPI from, String group, String version, String[] tags) { - Map fromPaths = from.getPaths(); - if (fromPaths == null) { + private void mergePaths(OpenAPI target, OpenAPI source, String group, String version, String[] tags) { + Map sourcePaths = source.getPaths(); + if (sourcePaths == null) { return; } - Map paths = api.getPaths(); + Map paths = target.getPaths(); if (paths == null) { - api.setPaths(paths = new TreeMap<>()); + target.setPaths(paths = new TreeMap<>()); } - for (Entry entry : fromPaths.entrySet()) { + for (Entry entry : sourcePaths.entrySet()) { String path = entry.getKey(); - PathItem fromPathItem = entry.getValue(); + PathItem sourcePathItem = entry.getValue(); PathItem pathItem = paths.get(path); if (pathItem != null) { - String ref = fromPathItem.getRef(); + String ref = sourcePathItem.getRef(); if (ref != null) { pathItem = paths.get(ref); } @@ -281,64 +282,64 @@ private void mergePaths(OpenAPI api, OpenAPI from, String group, String version, if (pathItem == null) { paths.put(path, pathItem = new PathItem()); } - mergePath(path, pathItem, fromPathItem, group, version, tags); + mergePath(path, pathItem, sourcePathItem, group, version, tags); } } - private void mergePath(String path, PathItem pathItem, PathItem from, String group, String version, String[] tags) { - if (pathItem.getRef() == null) { - pathItem.setRef(from.getRef()); + private void mergePath(String path, PathItem target, PathItem source, String group, String version, String[] tags) { + if (target.getRef() == null) { + target.setRef(source.getRef()); } - if (pathItem.getSummary() == null) { - pathItem.setSummary(from.getSummary()); + if (target.getSummary() == null) { + target.setSummary(source.getSummary()); } - if (pathItem.getDescription() == null) { - pathItem.setDescription(from.getDescription()); + if (target.getDescription() == null) { + target.setDescription(source.getDescription()); } - Map fromOperations = from.getOperations(); - if (fromOperations != null) { - for (Entry entry : fromOperations.entrySet()) { + Map sourceOperations = source.getOperations(); + if (sourceOperations != null) { + for (Entry entry : sourceOperations.entrySet()) { HttpMethods httpMethod = entry.getKey(); - Operation fromOperation = entry.getValue(); - if (isGroupNotMatch(group, fromOperation.getGroup()) - || isVersionNotMatch(version, fromOperation.getVersion()) - || isTagNotMatch(tags, fromOperation.getTags())) { + Operation sourceOperation = entry.getValue(); + if (isGroupNotMatch(group, sourceOperation.getGroup()) + || isVersionNotMatch(version, sourceOperation.getVersion()) + || isTagNotMatch(tags, sourceOperation.getTags())) { continue; } - Operation operation = pathItem.getOperation(httpMethod); + Operation operation = target.getOperation(httpMethod); if (operation == null) { - pathItem.addOperation(httpMethod, fromOperation.clone()); + target.addOperation(httpMethod, sourceOperation.clone()); } else if (operation.getMeta() != null) { LOG.internalWarn( "Operation already exists, path='{}', httpMethod='{}', method={}", path, httpMethod, - fromOperation.getMeta()); + sourceOperation.getMeta()); } } } - if (pathItem.getServers() == null) { - List fromServers = from.getServers(); - if (fromServers != null) { - pathItem.setServers(Node.clone(fromServers)); + if (target.getServers() == null) { + List sourceServers = source.getServers(); + if (sourceServers != null) { + target.setServers(Node.clone(sourceServers)); } } - List fromParameters = from.getParameters(); - if (fromParameters != null) { - if (pathItem.getParameters() == null) { - pathItem.setParameters(Node.clone(fromParameters)); + List sourceParameters = source.getParameters(); + if (sourceParameters != null) { + if (target.getParameters() == null) { + target.setParameters(Node.clone(sourceParameters)); } else { - for (Parameter parameter : fromParameters) { - pathItem.addParameter(parameter.clone()); + for (Parameter parameter : sourceParameters) { + target.addParameter(parameter.clone()); } } } - pathItem.addExtensions(from.getExtensions()); + target.addExtensions(source.getExtensions()); } private static boolean isServiceNotMatch(String apiService, String[] services) { @@ -353,14 +354,14 @@ private static boolean isServiceNotMatch(String apiService, String[] services) { return true; } - private static boolean isGroupNotMatch(String group, String fromGroup) { - return !(fromGroup == null && Constants.DEFAULT_GROUP.equals(group) + private static boolean isGroupNotMatch(String group, String sourceGroup) { + return !(sourceGroup == null && Constants.DEFAULT_GROUP.equals(group) || Constants.ALL_GROUP.equals(group) - || group.equals(fromGroup)); + || group.equals(sourceGroup)); } - private static boolean isVersionNotMatch(String version, String fromVersion) { - return !(version == null || fromVersion == null || Helper.isVersionGreaterOrEqual(fromVersion, version)); + private static boolean isVersionNotMatch(String version, String sourceVersion) { + return !(version == null || sourceVersion == null || Helper.isVersionGreaterOrEqual(sourceVersion, version)); } private static boolean isTagNotMatch(String[] tags, Set operationTags) { @@ -375,50 +376,47 @@ private static boolean isTagNotMatch(String[] tags, Set operationTags) { return true; } - private void mergeSecuritySchemes(OpenAPI api, OpenAPI from) { - Components fromComponents = from.getComponents(); - if (fromComponents == null) { + private void mergeSecuritySchemes(OpenAPI target, OpenAPI source) { + Components sourceComponents = source.getComponents(); + if (sourceComponents == null) { return; } - Map fromSecuritySchemes = fromComponents.getSecuritySchemes(); - if (fromSecuritySchemes == null) { + Map sourceSecuritySchemes = sourceComponents.getSecuritySchemes(); + if (sourceSecuritySchemes == null) { return; } - Components components = api.getComponents(); + Components components = target.getComponents(); Map securitySchemes = components.getSecuritySchemes(); if (securitySchemes == null) { - components.setSecuritySchemes(Node.clone(fromSecuritySchemes)); + components.setSecuritySchemes(Node.clone(sourceSecuritySchemes)); } else { - for (Entry entry : fromSecuritySchemes.entrySet()) { - String key = entry.getKey(); - if (securitySchemes.containsKey(key)) { - continue; - } - securitySchemes.put(key, entry.getValue().clone()); + for (Entry entry : sourceSecuritySchemes.entrySet()) { + securitySchemes.computeIfAbsent( + entry.getKey(), k -> entry.getValue().clone()); } } } - private void mergeTags(OpenAPI api, OpenAPI from) { - List fromTags = from.getTags(); - if (fromTags == null) { + private void mergeTags(OpenAPI target, OpenAPI source) { + List sourceTags = source.getTags(); + if (sourceTags == null) { return; } - if (api.getTags() == null) { - api.setTags(Node.clone(fromTags)); + if (target.getTags() == null) { + target.setTags(Node.clone(sourceTags)); } else { - for (Tag tag : fromTags) { - api.addTag(tag.clone()); + for (Tag tag : sourceTags) { + target.addTag(tag.clone()); } } } - private void addSchemas(OpenAPI api, String version, String group) { + private void addSchemas(OpenAPI target, String version, String group) { Map schemas = new IdentityHashMap<>(); - for (PathItem pathItem : api.getPaths().values()) { + for (PathItem pathItem : target.getPaths().values()) { Map operations = pathItem.getOperations(); if (operations == null) { continue; @@ -469,9 +467,9 @@ private void addSchemas(OpenAPI api, String version, String group) { } } - Components components = api.getComponents(); + Components components = target.getComponents(); if (components == null) { - api.setComponents(components = new Components()); + target.setComponents(components = new Components()); } Set names = CollectionUtils.newHashSet(schemas.size()); @@ -487,10 +485,10 @@ private void addSchemas(OpenAPI api, String version, String group) { String name = schema.getName(); if (name == null) { Class clazz = schema.getJavaType(); - name = strategy.generateSchemaName(clazz, api); + name = strategy.generateSchemaName(clazz, target); for (int i = 1; i < 100; i++) { if (names.contains(name)) { - name = strategy.resolveSchemaNameConflict(i, name, clazz, api); + name = strategy.resolveSchemaNameConflict(i, name, clazz, target); } else { names.add(name); break; @@ -561,22 +559,23 @@ private void addSchema(Schema schema, Map schemas, String group, targetSchema.addSourceSchema(schema); - schemas.computeIfAbsent(targetSchema, s -> { - Schema newSchema = s.clone(); + Schema newSchema = schemas.get(targetSchema); + if (newSchema == null) { + newSchema = targetSchema.clone(); + schemas.put(targetSchema, newSchema); addSchema(newSchema, schemas, group, version); - return newSchema; - }); + } } - private void completeOperations(OpenAPI api) { - Map paths = api.getPaths(); + private void completeOperations(OpenAPI target) { + Map paths = target.getPaths(); if (paths == null) { return; } Set allOperationIds = new HashSet<>(32); Set allTags = new HashSet<>(32); - api.walkOperations(operation -> { + target.walkOperations(operation -> { String operationId = operation.getOperationId(); if (operationId != null) { allOperationIds.add(operationId); @@ -588,15 +587,15 @@ private void completeOperations(OpenAPI api) { }); OpenAPINamingStrategy strategy = getNamingStrategy(); - api.walkOperations(operation -> { + target.walkOperations(operation -> { String id = operation.getOperationId(); if (id != null) { return; } - id = strategy.generateOperationId(operation.getMeta(), api); + id = strategy.generateOperationId(operation.getMeta(), target); for (int i = 1; i < 100; i++) { if (allOperationIds.contains(id)) { - id = strategy.resolveOperationIdConflict(i, id, operation.getMeta(), api); + id = strategy.resolveOperationIdConflict(i, id, operation.getMeta(), target); } else { allOperationIds.add(id); break; @@ -605,7 +604,7 @@ private void completeOperations(OpenAPI api) { operation.setOperationId(id); }); - List tags = api.getTags(); + List tags = target.getTags(); if (tags != null) { ListIterator it = tags.listIterator(); while (it.hasNext()) { @@ -617,17 +616,17 @@ private void completeOperations(OpenAPI api) { } } - private void completeModel(OpenAPI api) { - Info info = api.getInfo(); + private void completeModel(OpenAPI target) { + Info info = target.getInfo(); if (info.getTitle() == null) { info.setTitle("Dubbo OpenAPI"); } if (info.getVersion() == null) { info.setVersion("v1"); } - ExternalDocs docs = api.getExternalDocs(); + ExternalDocs docs = target.getExternalDocs(); if (docs.getUrl() == null && docs.getDescription() == null) { - docs.setUrl("../redoc/index.html?group=" + api.getGroup()).setDescription("ReDoc"); + docs.setUrl("../redoc/index.html?group=" + target.getGroup()).setDescription("ReDoc"); } } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index 24c2f90371f..e873bc00cb0 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -102,7 +102,7 @@ public OpenAPI resolve(ServiceMeta serviceMeta, Collection> r URL url = serviceMeta.getUrl(); definition.addServer(new Server() .setUrl("http://" + url.getHost() + ':' + url.getPort()) - .setDescription(Constants.DUBBO_SERVER)); + .setDescription(Constants.DUBBO_DEFAULT_SERVER)); } OperationContext context = new OperationContextImpl(definition, schemaResolver, extensionFactory); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index 135f466c904..729b3205d07 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -17,8 +17,10 @@ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; import org.apache.dubbo.common.utils.CollectionUtils; +import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; import org.apache.dubbo.remoting.http12.rest.ParamType; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; @@ -247,13 +249,34 @@ public static Server parseServer(String server) { return new Server().setDescription(description).setUrl(url); } - public static void setValue(Consumer setter, Supplier getter) { + public static void setValue(Supplier getter, Consumer setter) { String value = trim(getter.get()); if (value != null) { setter.accept(value); } } + public static void setBoolValue(Supplier getter, Consumer setter) { + String value = trim(getter.get()); + if (value != null) { + setter.accept(StringUtils.toBoolean(value)); + } + } + + public static void setValue(AnnotationMeta schema, String key, Consumer setter) { + String value = trim(schema.getString(key)); + if (value != null) { + setter.accept(value); + } + } + + public static void setBoolValue(AnnotationMeta schema, String key, Consumer setter) { + Boolean value = schema.getBoolean(key); + if (Boolean.TRUE.equals(value)) { + setter.accept(true); + } + } + public static String pathToRef(String path) { StringBuilder sb = new StringBuilder(path.length() + 16); sb.append("#/paths/"); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java index e9305cf48ae..81deb1693c0 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java @@ -98,7 +98,6 @@ public enum PrimitiveSchema { TYPE_MAPPING.put(java.io.InputStream.class, BYTE); TYPE_MAPPING.put(java.net.InetAddress.class, IP_V4); - TYPE_MAPPING.put("int", INT); TYPE_MAPPING.put("object", OBJECT); } @@ -130,6 +129,10 @@ public static Schema newSchemaOf(Class type) { return schema == null ? null : schema.newSchema(); } + public static boolean isPrimitive(Class type) { + return TYPE_MAPPING.containsKey(type); + } + public static void addTypeMapping(Object key, PrimitiveSchema schema) { TYPE_MAPPING.put(key, schema); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java index d67febed9fe..8bfddba6a76 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java @@ -40,7 +40,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.function.Function; import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.PrimitiveSchema.ARRAY; @@ -51,7 +50,7 @@ public final class SchemaResolver { private final ConfigFactory configFactory; private final OpenAPISchemaResolver[] resolvers; private final OpenAPISchemaPredicate[] predicates; - private final Map, Optional> schemaMap = CollectionUtils.newConcurrentHashMap(); + private final Map, Schema> schemaMap = CollectionUtils.newConcurrentHashMap(); private volatile RadixTree classFilter; @@ -102,16 +101,15 @@ private Schema doResolveType(Type type, ParameterMeta parameter) { Type[] argTypes = pType.getActualTypeArguments(); if (Iterable.class.isAssignableFrom(clazz)) { Type itemType = TypeUtils.getActualGenericType(argTypes[0]); - return ARRAY.newSchema().setItems(doResolveNestedType(itemType, parameter)); + return ARRAY.newSchema() + .addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(type)) + .setItems(doResolveNestedType(itemType, parameter)); } if (Map.class.isAssignableFrom(clazz)) { - Schema schema = OBJECT.newSchema(); - Type keyType = argTypes[0]; - if (String.class != keyType) { - schema.addExtension(Constants.X_JAVA_TYPE, TypeUtils.toTypeString(keyType)); - } - return schema.setAdditionalPropertiesSchema(doResolveNestedType(argTypes[1], parameter)); + return OBJECT.newSchema() + .addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(type)) + .setAdditionalPropertiesSchema(doResolveNestedType(argTypes[1], parameter)); } return doResolveClass(clazz, parameter); @@ -124,8 +122,9 @@ private Schema doResolveType(Type type, ParameterMeta parameter) { return doResolveNestedType(((WildcardType) type).getUpperBounds()[0], parameter); } if (type instanceof GenericArrayType) { - Type nestedType = ((GenericArrayType) type).getGenericComponentType(); - return ARRAY.newSchema().setItems(doResolveNestedType(nestedType, parameter)); + return ARRAY.newSchema() + .addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(type)) + .setItems(doResolveNestedType(((GenericArrayType) type).getGenericComponentType(), parameter)); } return OBJECT.newSchema(); } @@ -137,17 +136,22 @@ private Schema doResolveClass(Class clazz, ParameterMeta parameter) { } if (clazz.isArray()) { - return ARRAY.newSchema().setItems(doResolveNestedType(clazz.getComponentType(), parameter)); + schema = ARRAY.newSchema(); + if (!PrimitiveSchema.isPrimitive(clazz.getComponentType())) { + schema.addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(clazz)); + } + return schema.setItems(doResolveNestedType(clazz.getComponentType(), parameter)); } - Optional existingSchema = schemaMap.get(clazz); + Schema existingSchema = schemaMap.get(clazz); if (existingSchema != null) { - return existingSchema.map(s -> new Schema().setTargetSchema(s)).orElseGet(OBJECT::newSchema); + return new Schema().setTargetSchema(existingSchema); } if (isClassExcluded(clazz)) { - schemaMap.put(clazz, Optional.empty()); - return OBJECT.newSchema(); + schema = OBJECT.newSchema().addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(clazz)); + schemaMap.put(clazz, schema); + return schema; } TypeParameterMeta typeParameter = new TypeParameterMeta(clazz); @@ -159,8 +163,9 @@ private Schema doResolveClass(Class clazz, ParameterMeta parameter) { if (accepted) { break; } else { - schemaMap.put(clazz, Optional.empty()); - return OBJECT.newSchema(); + schema = OBJECT.newSchema().addExtension(Constants.X_JAVA_CLASS, TypeUtils.toTypeString(clazz)); + schemaMap.put(clazz, schema); + return schema; } } @@ -169,7 +174,7 @@ private Schema doResolveClass(Class clazz, ParameterMeta parameter) { for (Object value : clazz.getEnumConstants()) { schema.addEnumeration(value); } - schemaMap.put(clazz, Optional.of(schema)); + schemaMap.put(clazz, schema); return schema.clone(); } @@ -184,7 +189,7 @@ private Schema doResolveClass(Class clazz, ParameterMeta parameter) { private Schema doResolveBeanClass(RestToolKit toolKit, Class clazz, boolean flatten) { Schema beanSchema = OBJECT.newSchema().setJavaType(clazz); - schemaMap.put(clazz, Optional.of(beanSchema)); + schemaMap.put(clazz, beanSchema); BeanMeta beanMeta = new BeanMeta(toolKit, clazz, flatten); out: for (PropertyMeta property : beanMeta.getProperties()) { @@ -297,7 +302,7 @@ private final class SchemaContextImpl implements SchemaContext { @Override public void defineSchema(Class type, Schema schema) { - schemaMap.putIfAbsent(type, Optional.of(schema)); + schemaMap.putIfAbsent(type, schema); } @Override diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java index ef5b1298ba5..b4d394d3b4a 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java @@ -21,6 +21,7 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Context; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter.In; +import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -311,8 +312,9 @@ public Map writeTo(Map node, Context context) { write(node, "security", security, context); write(node, "servers", servers, context); writeExtensions(node); - write(node, Constants.X_JAVA_TYPE, meta.getServiceMeta().getServiceInterface()); + write(node, Constants.X_JAVA_CLASS, meta.getServiceMeta().getServiceInterface()); write(node, Constants.X_JAVA_METHOD, meta.getMethod().getName()); + write(node, Constants.X_JAVA_METHOD_DESCRIPTOR, TypeUtils.getMethodDescriptor(meta)); return node; } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java index 355497bc59c..62ae7184428 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java @@ -632,7 +632,7 @@ public Map writeTo(Map schema, Context context) write(schema, "deprecated", deprecated); writeExtensions(schema); if (javaType != null) { - schema.put(Constants.X_JAVA_TYPE, javaType.getName()); + schema.put(Constants.X_JAVA_CLASS, javaType.getName()); } return schema; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java index a6a348e7d31..7ec64728724 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java @@ -39,8 +39,9 @@ import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Map; -import java.util.function.Consumer; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setBoolValue; +import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.setValue; import static org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper.trim; @Activate(order = 100) @@ -150,8 +151,8 @@ public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChai setValue(annoMeta, "name", schema::setName); String title = trim(annoMeta.getValue()); schema.setTitle(title == null ? trim(annoMeta.getString("title")) : title); - setValue(annoMeta, "title", schema::setTitle); setValue(annoMeta, "description", schema::setDescription); + setValue(annoMeta, "defaultValue", schema::setDefaultValue); setValue(annoMeta, "max", v -> schema.setMaxLength(Integer.parseInt(v))); setValue(annoMeta, "min", v -> schema.setMinLength(Integer.parseInt(v))); setValue(annoMeta, "pattern", schema::setPattern); @@ -161,7 +162,6 @@ public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChai schema.setEnumeration(Arrays.asList(enumItems)); } setBoolValue(annoMeta, "required", schema::setRequired); - setValue(annoMeta, "defaultValue", schema::setDefaultValue); setBoolValue(annoMeta, "readOnly", schema::setReadOnly); setBoolValue(annoMeta, "writeOnly", schema::setWriteOnly); setBoolValue(annoMeta, "nullable", schema::setNullable); @@ -175,18 +175,4 @@ public Boolean acceptProperty(BeanMeta bean, PropertyMeta property) { AnnotationMeta annoMeta = property.getAnnotation(Annotations.Schema); return annoMeta == null ? null : annoMeta.getBoolean(HIDDEN); } - - private static void setValue(AnnotationMeta schema, String key, Consumer setter) { - String value = trim(schema.getString(key)); - if (value != null) { - setter.accept(value); - } - } - - private static void setBoolValue(AnnotationMeta schema, String key, Consumer setter) { - Boolean value = schema.getBoolean(key); - if (Boolean.TRUE.equals(value)) { - setter.accept(true); - } - } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java index a96f42aacee..1bc6e2e9379 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/util/TypeUtils.java @@ -21,6 +21,8 @@ import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.common.utils.ConcurrentHashSet; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta; import java.io.File; import java.lang.reflect.Array; @@ -409,7 +411,8 @@ public static String buildSig(Method method) { public static String toTypeString(Type type) { if (type instanceof Class) { - return ((Class) type).getName(); + Class clazz = (Class) type; + return clazz.isArray() ? clazz.getComponentType().getName() + "[]" : clazz.getName(); } StringBuilder result = new StringBuilder(32); buildGenericTypeString(type, result); @@ -418,7 +421,13 @@ public static String toTypeString(Type type) { private static void buildGenericTypeString(Type type, StringBuilder sb) { if (type instanceof Class) { - sb.append(((Class) type).getName()); + Class clazz = (Class) type; + if (clazz.isArray()) { + buildGenericTypeString(clazz.getComponentType(), sb); + sb.append("[]"); + } else { + sb.append(clazz.getName()); + } } else if (type instanceof ParameterizedType) { ParameterizedType pzType = (ParameterizedType) type; Type[] typeArgs = pzType.getActualTypeArguments(); @@ -466,4 +475,28 @@ private static void buildGenericTypeString(Type type, StringBuilder sb) { sb.append(type.toString()); } } + + public static Object getMethodDescriptor(MethodMeta methodMeta) { + StringBuilder sb = new StringBuilder(64); + sb.append(toTypeString(methodMeta.getGenericReturnType())) + .append(' ') + .append(methodMeta.getMethod().getName()) + .append('('); + ParameterMeta[] parameters = methodMeta.getParameters(); + for (int i = 0, len = parameters.length; i < len; i++) { + if (i > 0) { + sb.append(", "); + } + ParameterMeta paramMeta = parameters[i]; + String name = paramMeta.getName(); + sb.append(toTypeString(paramMeta.getGenericType())).append(' '); + if (name == null) { + sb.append("arg").append(i + 1); + } else { + sb.append(name); + } + } + sb.append(')'); + return sb.toString(); + } } From 8a966e69945c10efa48bc4fc772ac2ebe984555e Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Sat, 30 Nov 2024 12:32:23 +0800 Subject: [PATCH 20/23] Refine --- .artifacts | 2 +- LICENSE | 8 + .../common/extension/ExtensionAccessor.java | 8 + .../dubbo/config/nested/RestConfig.java | 28 + .../dubbo-demo-spring-boot-servlet/pom.xml | 7 +- dubbo-dependencies-bom/pom.xml | 6 + dubbo-distribution/dubbo-all-shaded/pom.xml | 7 +- dubbo-distribution/dubbo-all/pom.xml | 7 +- dubbo-distribution/dubbo-bom/pom.xml | 2 +- dubbo-distribution/dubbo-core-spi/pom.xml | 3 + dubbo-metadata/dubbo-metadata-api/pom.xml | 13 + .../DubboMetadataServiceV2Triple.java | 105 + .../apache/dubbo/metadata/MetadataInfoV2.java | 204 +- .../metadata/MetadataInfoV2OrBuilder.java | 43 + .../dubbo/metadata/MetadataRequest.java | 102 +- .../metadata/MetadataRequestOrBuilder.java | 9 + .../dubbo/metadata/MetadataServiceV2.java | 17 +- .../metadata/MetadataServiceV2OuterClass.java | 43 +- .../org/apache/dubbo/metadata/OpenAPI.java | 587 ++++++ .../apache/dubbo/metadata/OpenAPIFormat.java | 158 ++ .../dubbo/metadata/OpenAPIOrBuilder.java | 43 + .../apache/dubbo/metadata/OpenAPIRequest.java | 1748 +++++++++++++++++ .../metadata/OpenAPIRequestOrBuilder.java | 228 +++ .../apache/dubbo/metadata/ServiceInfoV2.java | 345 +++- .../metadata/ServiceInfoV2OrBuilder.java | 74 + .../src/main/proto/metadata_service_v2.proto | 59 + .../dubbo/qos/command/impl/GetOpenAPI.java | 95 + .../org.apache.dubbo.qos.api.BaseCommand | 1 + .../qos/command/util/CommandHelperTest.java | 2 + dubbo-plugin/dubbo-rest-jaxrs/pom.xml | 5 + .../jaxrs/JaxrsRequestMappingResolver.java | 11 +- .../support/jaxrs/ParamConverterFactory.java | 2 - .../pom.xml | 2 +- .../tri/rest/openapi/AbstractContext.java | 0 .../tri/rest/openapi/ConfigFactory.java | 5 - .../protocol/tri/rest/openapi/Constants.java | 0 .../protocol/tri/rest/openapi/Context.java | 0 .../tri/rest/openapi/ContextImpl.java | 0 .../openapi/DefaultOpenAPINamingStrategy.java | 0 .../rest/openapi/DefaultOpenAPIService.java | 14 +- .../tri/rest/openapi/DefinitionEncoder.java | 0 .../tri/rest/openapi/DefinitionFilter.java | 0 .../tri/rest/openapi/DefinitionMerger.java | 9 +- .../tri/rest/openapi/DefinitionResolver.java | 0 .../tri/rest/openapi/ExtensionFactory.java | 0 .../rpc/protocol/tri/rest/openapi/Helper.java | 21 +- .../openapi/OpenAPIDefinitionResolver.java | 0 .../openapi/OpenAPIDocumentPublisher.java | 0 .../tri/rest/openapi/OpenAPIExtension.java | 0 .../tri/rest/openapi/OpenAPIFilter.java | 0 .../rest/openapi/OpenAPINamingStrategy.java | 0 .../rest/openapi/OpenAPIRequestHandler.java | 0 .../rest/openapi/OpenAPISchemaPredicate.java | 0 .../rest/openapi/OpenAPISchemaResolver.java | 0 .../tri/rest/openapi/PrimitiveSchema.java | 0 .../tri/rest/openapi/ProtoEncoder.java | 0 .../tri/rest/openapi/SchemaResolver.java | 0 .../tri/rest/openapi/model/ApiResponse.java | 0 .../tri/rest/openapi/model/Components.java | 0 .../tri/rest/openapi/model/Contact.java | 0 .../tri/rest/openapi/model/Discriminator.java | 0 .../tri/rest/openapi/model/Encoding.java | 0 .../tri/rest/openapi/model/Example.java | 0 .../tri/rest/openapi/model/ExternalDocs.java | 0 .../tri/rest/openapi/model/Header.java | 0 .../protocol/tri/rest/openapi/model/Info.java | 0 .../tri/rest/openapi/model/License.java | 0 .../tri/rest/openapi/model/MediaType.java | 0 .../protocol/tri/rest/openapi/model/Node.java | 0 .../tri/rest/openapi/model/OAuthFlow.java | 0 .../tri/rest/openapi/model/OAuthFlows.java | 0 .../tri/rest/openapi/model/OpenAPI.java | 0 .../tri/rest/openapi/model/Operation.java | 0 .../tri/rest/openapi/model/Parameter.java | 0 .../tri/rest/openapi/model/PathItem.java | 0 .../tri/rest/openapi/model/RequestBody.java | 0 .../tri/rest/openapi/model/Schema.java | 0 .../openapi/model/SecurityRequirement.java | 0 .../rest/openapi/model/SecurityScheme.java | 0 .../tri/rest/openapi/model/Server.java | 0 .../rest/openapi/model/ServerVariable.java | 0 .../protocol/tri/rest/openapi/model/Tag.java | 0 .../protocol/tri/rest/openapi/model/XML.java | 0 .../basic/BasicOpenAPIDefinitionResolver.java | 0 .../JavadocOpenAPIDefinitionResolver.java | 0 .../support/swagger/RedocRequestHandler.java | 1 + .../SwaggerOpenAPIDefinitionResolver.java | 0 .../swagger/SwaggerUIRequestHandler.java | 9 +- .../rest/support/swagger/WebjarHelper.java | 0 ....dubbo.remoting.http12.rest.OpenAPIService | 1 + ...protocol.tri.rest.openapi.OpenAPIExtension | 2 + .../META-INF/resources/redoc/index.html | 1 + .../META-INF/resources/swagger-ui/index.html | 1 + dubbo-plugin/dubbo-rest-spring/pom.xml | 5 + .../SpringMvcRequestMappingResolver.java | 11 +- .../support/spring/SpringRestToolKit.java | 3 - .../tri/rest/support/swagger/Helper.java | 44 - dubbo-plugin/dubbo-triple-websocket/pom.xml | 5 + .../metadata/MetadataServiceDelegation.java | 15 +- .../metadata/MetadataServiceDelegationV2.java | 41 +- dubbo-remoting/dubbo-remoting-http12/pom.xml | 10 +- .../remoting/http12/rest}/OpenAPIService.java | 10 +- .../java/org/apache/dubbo/rpc/Constants.java | 2 + dubbo-rpc/dubbo-rpc-triple/pom.xml | 46 +- .../rpc/protocol/tri/TripleProtocol.java | 19 +- .../rpc/protocol/tri/rest/cors/CorsUtils.java | 17 +- .../DefaultRequestMappingRegistry.java | 14 +- .../rest/mapping/RequestMappingResolver.java | 3 + .../basic/BasicRequestMappingResolver.java | 22 +- ...protocol.tri.rest.openapi.OpenAPIExtension | 2 - .../event/DubboOpenAPIExportListener.java | 8 +- dubbo-test/dubbo-dependencies-all/pom.xml | 2 +- pom.xml | 2 +- 113 files changed, 4127 insertions(+), 192 deletions(-) create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPI.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIFormat.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIOrBuilder.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java create mode 100644 dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequestOrBuilder.java create mode 100644 dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.java rename dubbo-plugin/{dubbo-rest-swagger => dubbo-rest-openapi}/pom.xml (98%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java (96%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java (97%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java (98%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java (93%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java (100%) rename {dubbo-rpc/dubbo-rpc-triple => dubbo-plugin/dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java (100%) rename dubbo-plugin/{dubbo-rest-swagger => dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java (100%) rename dubbo-plugin/{dubbo-rest-swagger => dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java (98%) rename dubbo-plugin/{dubbo-rest-swagger => dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java (100%) rename dubbo-plugin/{dubbo-rest-swagger => dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java (93%) rename dubbo-plugin/{dubbo-rest-swagger => dubbo-rest-openapi}/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java (100%) create mode 100644 dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService rename dubbo-plugin/{dubbo-rest-swagger => dubbo-rest-openapi}/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension (66%) rename dubbo-plugin/{dubbo-rest-swagger => dubbo-rest-openapi}/src/main/resources/META-INF/resources/redoc/index.html (84%) rename dubbo-plugin/{dubbo-rest-swagger => dubbo-rest-openapi}/src/main/resources/META-INF/resources/swagger-ui/index.html (93%) delete mode 100644 dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/Helper.java rename {dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi => dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest}/OpenAPIService.java (77%) delete mode 100644 dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension diff --git a/.artifacts b/.artifacts index 2abca0fd4ef..27974610f1f 100644 --- a/.artifacts +++ b/.artifacts @@ -112,6 +112,6 @@ dubbo-xds dubbo-plugin-loom dubbo-rest-jaxrs dubbo-rest-spring -dubbo-rest-swagger +dubbo-rest-openapi dubbo-triple-servlet dubbo-triple-websocket diff --git a/LICENSE b/LICENSE index b2d3628b89d..3716d3930ed 100644 --- a/LICENSE +++ b/LICENSE @@ -287,3 +287,11 @@ This product contains a modified portion of 'Istio', an open platform to connect under a "Apache License 2.0" license, see https://github.com/istio/api/blob/master/LICENSE: * security/v1alpha1/ca.proto + +For the file dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/swagger-ui/index.html: + +Under a "Apache License 2.0" license, see https://github.com/swagger-api/swagger-ui/blob/master/LICENSE + +For the file dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/redoc/index.html: + +Under a "MIT License" license, see https://github.com/Redocly/redoc/blob/main/LICENSE diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionAccessor.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionAccessor.java index 5abade6f709..fcfc023b131 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionAccessor.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionAccessor.java @@ -46,6 +46,14 @@ default T getDefaultExtension(Class type) { return extensionLoader != null ? extensionLoader.getDefaultExtension() : null; } + default T getDefaultExtensionOrNull(Class type) { + ExtensionLoader extensionLoader = getExtensionLoader(type); + if (extensionLoader == null) { + return null; + } + return extensionLoader.getExtension(extensionLoader.getDefaultExtensionName(), true); + } + default List getActivateExtensions(Class type) { ExtensionLoader extensionLoader = getExtensionLoader(type); return extensionLoader != null ? extensionLoader.getActivateExtensions() : Collections.emptyList(); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java index 8f64a3d0157..7cc994413fc 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/nested/RestConfig.java @@ -34,6 +34,18 @@ public class RestConfig implements Serializable { public static final boolean DEFAULT_CASE_SENSITIVE_MATCH = true; public static final String DEFAULT_FORMAT_PARAMETER_NAME = "format"; + /** + * Whether to enable rest support + *

The default value is 'true'. + */ + private Boolean enabled; + + /** + * Whether to enable the default mapping '/{interfaceName}/{methodName}'. + *

The default value is 'true'. + */ + private Boolean enableDefaultMapping; + /** * Whether path matching should be match paths with a trailing slash. * If enabled, a method mapped to "/users" also matches to "/users/". @@ -90,6 +102,22 @@ public class RestConfig implements Serializable { */ private Map openapis; + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Boolean getEnableDefaultMapping() { + return enableDefaultMapping; + } + + public void setEnableDefaultMapping(Boolean enableDefaultMapping) { + this.enableDefaultMapping = enableDefaultMapping; + } + public Boolean getTrailingSlashMatch() { return trailingSlashMatch; } diff --git a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml index c9728a77575..08eaf8e01a0 100644 --- a/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml +++ b/dubbo-demo/dubbo-demo-spring-boot/dubbo-demo-spring-boot-servlet/pom.xml @@ -32,6 +32,11 @@ dubbo-registry-zookeeper ${project.version} + + org.apache.dubbo + dubbo-qos + ${project.version} + org.apache.dubbo dubbo-rpc-triple @@ -54,7 +59,7 @@ org.apache.dubbo - dubbo-rest-swagger + dubbo-rest-openapi ${project.version} diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml index 5be1fde39d3..d747e88fbe8 100644 --- a/dubbo-dependencies-bom/pom.xml +++ b/dubbo-dependencies-bom/pom.xml @@ -106,6 +106,7 @@ 2.12.0 4.0.66 3.25.5 + 3.0.2 1.3.2 3.1.0 2.2.0 @@ -419,6 +420,11 @@ protobuf-java-util ${protobuf-java_version} + + com.google.code.findbugs + jsr305 + ${jsr305_version} + org.bouncycastle bcprov-jdk15on diff --git a/dubbo-distribution/dubbo-all-shaded/pom.xml b/dubbo-distribution/dubbo-all-shaded/pom.xml index 4c74741dcf7..993f681c231 100644 --- a/dubbo-distribution/dubbo-all-shaded/pom.xml +++ b/dubbo-distribution/dubbo-all-shaded/pom.xml @@ -278,7 +278,7 @@ org.apache.dubbo - dubbo-rest-swagger + dubbo-rest-openapi ${project.version} compile true @@ -531,7 +531,7 @@ org.apache.dubbo:dubbo-rpc-triple org.apache.dubbo:dubbo-rest-jaxrs org.apache.dubbo:dubbo-rest-spring - org.apache.dubbo:dubbo-rest-swagger + org.apache.dubbo:dubbo-rest-openapi org.apache.dubbo:dubbo-triple-servlet org.apache.dubbo:dubbo-triple-websocket org.apache.dubbo:dubbo-serialization-api @@ -889,6 +889,9 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver + + META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml index f518a387e44..b385f4a9af9 100644 --- a/dubbo-distribution/dubbo-all/pom.xml +++ b/dubbo-distribution/dubbo-all/pom.xml @@ -278,7 +278,7 @@ org.apache.dubbo - dubbo-rest-swagger + dubbo-rest-openapi ${project.version} compile true @@ -530,7 +530,7 @@ org.apache.dubbo:dubbo-rpc-triple org.apache.dubbo:dubbo-rest-jaxrs org.apache.dubbo:dubbo-rest-spring - org.apache.dubbo:dubbo-rest-swagger + org.apache.dubbo:dubbo-rest-openapi org.apache.dubbo:dubbo-triple-servlet org.apache.dubbo:dubbo-triple-websocket org.apache.dubbo:dubbo-serialization-api @@ -887,6 +887,9 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver + + META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension diff --git a/dubbo-distribution/dubbo-bom/pom.xml b/dubbo-distribution/dubbo-bom/pom.xml index 5003a7c7d45..fd057752bb1 100644 --- a/dubbo-distribution/dubbo-bom/pom.xml +++ b/dubbo-distribution/dubbo-bom/pom.xml @@ -303,7 +303,7 @@ org.apache.dubbo - dubbo-rest-swagger + dubbo-rest-openapi ${project.version} diff --git a/dubbo-distribution/dubbo-core-spi/pom.xml b/dubbo-distribution/dubbo-core-spi/pom.xml index 0c6c789847f..691d35c0c1e 100644 --- a/dubbo-distribution/dubbo-core-spi/pom.xml +++ b/dubbo-distribution/dubbo-core-spi/pom.xml @@ -483,6 +483,9 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver + + META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService + META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension diff --git a/dubbo-metadata/dubbo-metadata-api/pom.xml b/dubbo-metadata/dubbo-metadata-api/pom.xml index 44e01099bd0..abeee99db63 100644 --- a/dubbo-metadata/dubbo-metadata-api/pom.xml +++ b/dubbo-metadata/dubbo-metadata-api/pom.xml @@ -62,6 +62,10 @@ ${project.parent.version} compile + + com.google.protobuf + protobuf-java + org.apache.dubbo @@ -81,4 +85,13 @@ ${project.parent.version} + + + + + + diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java index dd64d86a38e..928583d12dd 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java @@ -62,6 +62,11 @@ public static MetadataServiceV2 newStub(Invoker invoker) { return new MetadataServiceV2Stub((Invoker) invoker); } + /** + *

+     *  Retrieves metadata information.
+     * 
+ */ private static final StubMethodDescriptor getMetadataInfoMethod = new StubMethodDescriptor( "GetMetadataInfo", MetadataRequest.class, @@ -91,10 +96,46 @@ public static MetadataServiceV2 newStub(Invoker invoker) { obj -> ((Message) obj).toByteArray(), MetadataRequest::parseFrom, MetadataInfoV2::parseFrom); + /** + *
+     *  Retrieves OpenAPI.
+     * 
+ */ + private static final StubMethodDescriptor getOpenAPIMethod = new StubMethodDescriptor( + "GetOpenAPI", + OpenAPIRequest.class, + OpenAPI.class, + MethodDescriptor.RpcType.UNARY, + obj -> ((Message) obj).toByteArray(), + obj -> ((Message) obj).toByteArray(), + OpenAPIRequest::parseFrom, + OpenAPI::parseFrom); + + private static final StubMethodDescriptor getOpenAPIAsyncMethod = new StubMethodDescriptor( + "GetOpenAPI", + OpenAPIRequest.class, + CompletableFuture.class, + MethodDescriptor.RpcType.UNARY, + obj -> ((Message) obj).toByteArray(), + obj -> ((Message) obj).toByteArray(), + OpenAPIRequest::parseFrom, + OpenAPI::parseFrom); + + private static final StubMethodDescriptor getOpenAPIProxyAsyncMethod = new StubMethodDescriptor( + "GetOpenAPIAsync", + OpenAPIRequest.class, + OpenAPI.class, + MethodDescriptor.RpcType.UNARY, + obj -> ((Message) obj).toByteArray(), + obj -> ((Message) obj).toByteArray(), + OpenAPIRequest::parseFrom, + OpenAPI::parseFrom); static { serviceDescriptor.addMethod(getMetadataInfoMethod); serviceDescriptor.addMethod(getMetadataInfoProxyAsyncMethod); + serviceDescriptor.addMethod(getOpenAPIMethod); + serviceDescriptor.addMethod(getOpenAPIProxyAsyncMethod); } public static class MetadataServiceV2Stub implements MetadataServiceV2, Destroyable { @@ -109,6 +150,11 @@ public MetadataServiceV2Stub(Invoker invoker) { invoker.destroy(); } + /** + *
+         *  Retrieves metadata information.
+         * 
+ */ @Override public MetadataInfoV2 getMetadataInfo(MetadataRequest request) { return StubInvocationUtil.unaryCall(invoker, getMetadataInfoMethod, request); @@ -118,9 +164,37 @@ public CompletableFuture getMetadataInfoAsync(MetadataRequest re return StubInvocationUtil.unaryCall(invoker, getMetadataInfoAsyncMethod, request); } + /** + *
+         *  Retrieves metadata information.
+         * 
+ */ public void getMetadataInfo(MetadataRequest request, StreamObserver responseObserver) { StubInvocationUtil.unaryCall(invoker, getMetadataInfoMethod, request, responseObserver); } + + /** + *
+         *  Retrieves OpenAPI.
+         * 
+ */ + @Override + public OpenAPI getOpenAPI(OpenAPIRequest request) { + return StubInvocationUtil.unaryCall(invoker, getOpenAPIMethod, request); + } + + public CompletableFuture getOpenAPIAsync(OpenAPIRequest request) { + return StubInvocationUtil.unaryCall(invoker, getOpenAPIAsyncMethod, request); + } + + /** + *
+         *  Retrieves OpenAPI.
+         * 
+ */ + public void getOpenAPI(OpenAPIRequest request, StreamObserver responseObserver) { + StubInvocationUtil.unaryCall(invoker, getOpenAPIMethod, request, responseObserver); + } } public abstract static class MetadataServiceV2ImplBase @@ -146,6 +220,11 @@ public CompletableFuture getMetadataInfoAsync(MetadataRequest re return CompletableFuture.completedFuture(getMetadataInfo(request)); } + @Override + public CompletableFuture getOpenAPIAsync(OpenAPIRequest request) { + return CompletableFuture.completedFuture(getOpenAPI(request)); + } + /** * This server stream type unary method is only used for generated stub to support async unary method. * It will not be called if you are NOT using Dubbo3 generated triple stub and DO NOT implement this method. @@ -161,6 +240,17 @@ public void getMetadataInfo(MetadataRequest request, StreamObserver responseObserver) { + getOpenAPIAsync(request).whenComplete((r, t) -> { + if (t != null) { + responseObserver.onError(t); + } else { + responseObserver.onNext(r); + responseObserver.onCompleted(); + } + }); + } + @Override public final Invoker getInvoker(URL url) { PathResolver pathResolver = url.getOrDefaultFrameworkModel() @@ -174,6 +264,12 @@ public final Invoker getInvoker(URL url) { pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetMetadataInfo"); pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetMetadataInfoAsync"); + pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetOpenAPI"); + pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetOpenAPIAsync"); + // for compatibility + pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetOpenAPI"); + pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetOpenAPIAsync"); + BiConsumer> getMetadataInfoFunc = this::getMetadataInfo; handlers.put(getMetadataInfoMethod.getMethodName(), new UnaryStubMethodHandler<>(getMetadataInfoFunc)); BiConsumer> getMetadataInfoAsyncFunc = @@ -181,6 +277,10 @@ public final Invoker getInvoker(URL url) { handlers.put( getMetadataInfoProxyAsyncMethod.getMethodName(), new UnaryStubMethodHandler<>(getMetadataInfoAsyncFunc)); + BiConsumer> getOpenAPIFunc = this::getOpenAPI; + handlers.put(getOpenAPIMethod.getMethodName(), new UnaryStubMethodHandler<>(getOpenAPIFunc)); + BiConsumer> getOpenAPIAsyncFunc = syncToAsync(this::getOpenAPI); + handlers.put(getOpenAPIProxyAsyncMethod.getMethodName(), new UnaryStubMethodHandler<>(getOpenAPIAsyncFunc)); return new StubInvoker<>(this, url, MetadataServiceV2.class, handlers); } @@ -190,6 +290,11 @@ public MetadataInfoV2 getMetadataInfo(MetadataRequest request) { throw unimplementedMethodException(getMetadataInfoMethod); } + @Override + public OpenAPI getOpenAPI(OpenAPIRequest request) { + throw unimplementedMethodException(getOpenAPIMethod); + } + @Override public final ServiceDescriptor getServiceDescriptor() { return serviceDescriptor; diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java index 520641396b3..82e375d7881 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java @@ -17,13 +17,19 @@ package org.apache.dubbo.metadata; /** + *
+ * Metadata information message.
+ * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.MetadataInfoV2} */ public final class MetadataInfoV2 extends com.google.protobuf.GeneratedMessageV3 implements // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.MetadataInfoV2) MetadataInfoV2OrBuilder { + private static final long serialVersionUID = 0L; + // Use MetadataInfoV2.newBuilder() to construct. private MetadataInfoV2(com.google.protobuf.GeneratedMessageV3.Builder builder) { super(builder); @@ -65,7 +71,12 @@ protected FieldAccessorTable internalGetFieldAccessorTable() { @SuppressWarnings("serial") private volatile Object app_ = ""; + /** + *
+     * The application name.
+     * 
+ * * string app = 1; * @return The app. */ @@ -81,7 +92,12 @@ public String getApp() { return s; } } + /** + *
+     * The application name.
+     * 
+ * * string app = 1; * @return The bytes for app. */ @@ -101,7 +117,12 @@ public com.google.protobuf.ByteString getAppBytes() { @SuppressWarnings("serial") private volatile Object version_ = ""; + /** + *
+     * The application version.
+     * 
+ * * string version = 2; * @return The version. */ @@ -117,7 +138,12 @@ public String getVersion() { return s; } } + /** + *
+     * The application version.
+     * 
+ * * string version = 2; * @return The bytes for version. */ @@ -136,6 +162,7 @@ public com.google.protobuf.ByteString getVersionBytes() { public static final int SERVICES_FIELD_NUMBER = 3; private static final class ServicesDefaultEntryHolder { + static final com.google.protobuf.MapEntry defaultEntry = com.google.protobuf.MapEntry.newDefaultInstance( MetadataServiceV2OuterClass @@ -159,7 +186,12 @@ private com.google.protobuf.MapField internalGetServices( public int getServicesCount() { return internalGetServices().getMap().size(); } + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -169,6 +201,7 @@ public boolean containsServices(String key) { } return internalGetServices().getMap().containsKey(key); } + /** * Use {@link #getServicesMap()} instead. */ @@ -177,14 +210,24 @@ public boolean containsServices(String key) { public java.util.Map getServices() { return getServicesMap(); } + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override public java.util.Map getServicesMap() { return internalGetServices().getMap(); } + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -198,7 +241,12 @@ public java.util.Map getServicesMap() { java.util.Map map = internalGetServices().getMap(); return map.containsKey(key) ? map.get(key) : defaultValue; } + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -218,8 +266,12 @@ public ServiceInfoV2 getServicesOrThrow(String key) { @Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } memoizedIsInitialized = 1; return true; @@ -241,7 +293,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io @Override public int getSerializedSize() { int size = memoizedSize; - if (size != -1) return size; + if (size != -1) { + return size; + } size = 0; if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(app_)) { @@ -274,10 +328,18 @@ public boolean equals(final Object obj) { } MetadataInfoV2 other = (MetadataInfoV2) obj; - if (!getApp().equals(other.getApp())) return false; - if (!getVersion().equals(other.getVersion())) return false; - if (!internalGetServices().equals(other.internalGetServices())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; + if (!getApp().equals(other.getApp())) { + return false; + } + if (!getVersion().equals(other.getVersion())) { + return false; + } + if (!internalGetServices().equals(other.internalGetServices())) { + return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) { + return false; + } return true; } @@ -385,13 +447,19 @@ protected Builder newBuilderForType(BuilderParent parent) { Builder builder = new Builder(parent); return builder; } + /** + *
+     * Metadata information message.
+     * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.MetadataInfoV2} */ public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder implements // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.MetadataInfoV2) MetadataInfoV2OrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataInfoV2_descriptor; } @@ -483,6 +551,37 @@ private void buildPartial0(MetadataInfoV2 result) { } } + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.addRepeatedField(field, value); + } + @Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof MetadataInfoV2) { @@ -494,7 +593,9 @@ public Builder mergeFrom(com.google.protobuf.Message other) { } public Builder mergeFrom(MetadataInfoV2 other) { - if (other == MetadataInfoV2.getDefaultInstance()) return this; + if (other == MetadataInfoV2.getDefaultInstance()) { + return this; + } if (!other.getApp().isEmpty()) { app_ = other.app_; bitField0_ |= 0x00000001; @@ -570,7 +671,12 @@ public Builder mergeFrom( private int bitField0_; private Object app_ = ""; + /** + *
+         * The application name.
+         * 
+ * * string app = 1; * @return The app. */ @@ -585,7 +691,12 @@ public String getApp() { return (String) ref; } } + /** + *
+         * The application name.
+         * 
+ * * string app = 1; * @return The bytes for app. */ @@ -599,7 +710,12 @@ public com.google.protobuf.ByteString getAppBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The application name.
+         * 
+ * * string app = 1; * @param value The app to set. * @return This builder for chaining. @@ -613,7 +729,12 @@ public Builder setApp(String value) { onChanged(); return this; } + /** + *
+         * The application name.
+         * 
+ * * string app = 1; * @return This builder for chaining. */ @@ -623,7 +744,12 @@ public Builder clearApp() { onChanged(); return this; } + /** + *
+         * The application name.
+         * 
+ * * string app = 1; * @param value The bytes for app to set. * @return This builder for chaining. @@ -640,7 +766,12 @@ public Builder setAppBytes(com.google.protobuf.ByteString value) { } private Object version_ = ""; + /** + *
+         * The application version.
+         * 
+ * * string version = 2; * @return The version. */ @@ -655,7 +786,12 @@ public String getVersion() { return (String) ref; } } + /** + *
+         * The application version.
+         * 
+ * * string version = 2; * @return The bytes for version. */ @@ -669,7 +805,12 @@ public com.google.protobuf.ByteString getVersionBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The application version.
+         * 
+ * * string version = 2; * @param value The version to set. * @return This builder for chaining. @@ -683,7 +824,12 @@ public Builder setVersion(String value) { onChanged(); return this; } + /** + *
+         * The application version.
+         * 
+ * * string version = 2; * @return This builder for chaining. */ @@ -693,7 +839,12 @@ public Builder clearVersion() { onChanged(); return this; } + /** + *
+         * The application version.
+         * 
+ * * string version = 2; * @param value The bytes for version to set. * @return This builder for chaining. @@ -733,7 +884,12 @@ private com.google.protobuf.MapField internalGetMutableSe public int getServicesCount() { return internalGetServices().getMap().size(); } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -743,6 +899,7 @@ public boolean containsServices(String key) { } return internalGetServices().getMap().containsKey(key); } + /** * Use {@link #getServicesMap()} instead. */ @@ -751,14 +908,24 @@ public boolean containsServices(String key) { public java.util.Map getServices() { return getServicesMap(); } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override public java.util.Map getServicesMap() { return internalGetServices().getMap(); } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -772,7 +939,12 @@ public java.util.Map getServicesMap() { java.util.Map map = internalGetServices().getMap(); return map.containsKey(key) ? map.get(key) : defaultValue; } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ @Override @@ -792,7 +964,12 @@ public Builder clearServices() { internalGetMutableServices().getMutableMap().clear(); return this; } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ public Builder removeServices(String key) { @@ -802,6 +979,7 @@ public Builder removeServices(String key) { internalGetMutableServices().getMutableMap().remove(key); return this; } + /** * Use alternate mutation accessors instead. */ @@ -810,7 +988,12 @@ public java.util.Map getMutableServices() { bitField0_ |= 0x00000004; return internalGetMutableServices().getMutableMap(); } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ public Builder putServices(String key, ServiceInfoV2 value) { @@ -824,7 +1007,12 @@ public Builder putServices(String key, ServiceInfoV2 value) { bitField0_ |= 0x00000004; return this; } + /** + *
+         * A map of service information.
+         * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ public Builder putAllServices(java.util.Map values) { diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2OrBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2OrBuilder.java index cab7cdc934e..adf6b4376fc 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2OrBuilder.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2OrBuilder.java @@ -22,45 +22,83 @@ public interface MetadataInfoV2OrBuilder com.google.protobuf.MessageOrBuilder { /** + *
+     * The application name.
+     * 
+ * * string app = 1; * @return The app. */ String getApp(); + /** + *
+     * The application name.
+     * 
+ * * string app = 1; * @return The bytes for app. */ com.google.protobuf.ByteString getAppBytes(); /** + *
+     * The application version.
+     * 
+ * * string version = 2; * @return The version. */ String getVersion(); + /** + *
+     * The application version.
+     * 
+ * * string version = 2; * @return The bytes for version. */ com.google.protobuf.ByteString getVersionBytes(); /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ int getServicesCount(); + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ boolean containsServices(String key); + /** * Use {@link #getServicesMap()} instead. */ @Deprecated java.util.Map getServices(); + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ java.util.Map getServicesMap(); + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ /* nullable */ @@ -68,7 +106,12 @@ ServiceInfoV2 getServicesOrDefault( String key, /* nullable */ ServiceInfoV2 defaultValue); + /** + *
+     * A map of service information.
+     * 
+ * * map<string, .org.apache.dubbo.metadata.ServiceInfoV2> services = 3; */ ServiceInfoV2 getServicesOrThrow(String key); diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java index c989693c43e..4e78f6f807e 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java @@ -17,13 +17,19 @@ package org.apache.dubbo.metadata; /** + *
+ * Metadata request message.
+ * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.MetadataRequest} */ public final class MetadataRequest extends com.google.protobuf.GeneratedMessageV3 implements // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.MetadataRequest) MetadataRequestOrBuilder { + private static final long serialVersionUID = 0L; + // Use MetadataRequest.newBuilder() to construct. private MetadataRequest(com.google.protobuf.GeneratedMessageV3.Builder builder) { super(builder); @@ -53,7 +59,12 @@ protected FieldAccessorTable internalGetFieldAccessorTable() { @SuppressWarnings("serial") private volatile Object revision_ = ""; + /** + *
+     * The revision of the metadata.
+     * 
+ * * string revision = 1; * @return The revision. */ @@ -69,7 +80,12 @@ public String getRevision() { return s; } } + /** + *
+     * The revision of the metadata.
+     * 
+ * * string revision = 1; * @return The bytes for revision. */ @@ -90,8 +106,12 @@ public com.google.protobuf.ByteString getRevisionBytes() { @Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } memoizedIsInitialized = 1; return true; @@ -108,7 +128,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io @Override public int getSerializedSize() { int size = memoizedSize; - if (size != -1) return size; + if (size != -1) { + return size; + } size = 0; if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(revision_)) { @@ -129,8 +151,12 @@ public boolean equals(final Object obj) { } MetadataRequest other = (MetadataRequest) obj; - if (!getRevision().equals(other.getRevision())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; + if (!getRevision().equals(other.getRevision())) { + return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) { + return false; + } return true; } @@ -232,13 +258,19 @@ protected Builder newBuilderForType(BuilderParent parent) { Builder builder = new Builder(parent); return builder; } + /** + *
+     * Metadata request message.
+     * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.MetadataRequest} */ public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder implements // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.MetadataRequest) MetadataRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataRequest_descriptor; } @@ -301,6 +333,37 @@ private void buildPartial0(MetadataRequest result) { } } + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.addRepeatedField(field, value); + } + @Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof MetadataRequest) { @@ -312,7 +375,9 @@ public Builder mergeFrom(com.google.protobuf.Message other) { } public Builder mergeFrom(MetadataRequest other) { - if (other == MetadataRequest.getDefaultInstance()) return this; + if (other == MetadataRequest.getDefaultInstance()) { + return this; + } if (!other.getRevision().isEmpty()) { revision_ = other.revision_; bitField0_ |= 0x00000001; @@ -367,7 +432,12 @@ public Builder mergeFrom( private int bitField0_; private Object revision_ = ""; + /** + *
+         * The revision of the metadata.
+         * 
+ * * string revision = 1; * @return The revision. */ @@ -382,7 +452,12 @@ public String getRevision() { return (String) ref; } } + /** + *
+         * The revision of the metadata.
+         * 
+ * * string revision = 1; * @return The bytes for revision. */ @@ -396,7 +471,12 @@ public com.google.protobuf.ByteString getRevisionBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The revision of the metadata.
+         * 
+ * * string revision = 1; * @param value The revision to set. * @return This builder for chaining. @@ -410,7 +490,12 @@ public Builder setRevision(String value) { onChanged(); return this; } + /** + *
+         * The revision of the metadata.
+         * 
+ * * string revision = 1; * @return This builder for chaining. */ @@ -420,7 +505,12 @@ public Builder clearRevision() { onChanged(); return this; } + /** + *
+         * The revision of the metadata.
+         * 
+ * * string revision = 1; * @param value The bytes for revision to set. * @return This builder for chaining. diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequestOrBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequestOrBuilder.java index 4099bb21cec..98c54262a1a 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequestOrBuilder.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequestOrBuilder.java @@ -22,11 +22,20 @@ public interface MetadataRequestOrBuilder com.google.protobuf.MessageOrBuilder { /** + *
+     * The revision of the metadata.
+     * 
+ * * string revision = 1; * @return The revision. */ String getRevision(); + /** + *
+     * The revision of the metadata.
+     * 
+ * * string revision = 1; * @return The bytes for revision. */ diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java index e938b3c2b15..a74d09f4d05 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java @@ -16,17 +16,28 @@ */ package org.apache.dubbo.metadata; -import org.apache.dubbo.remoting.http12.rest.Mapping; - import java.util.concurrent.CompletableFuture; -@Mapping(enabled = false) public interface MetadataServiceV2 extends org.apache.dubbo.rpc.model.DubboStub { String JAVA_SERVICE_NAME = "org.apache.dubbo.metadata.MetadataServiceV2"; String SERVICE_NAME = "org.apache.dubbo.metadata.MetadataServiceV2"; + /** + *
+     *  Retrieves metadata information.
+     * 
+ */ MetadataInfoV2 getMetadataInfo(MetadataRequest request); CompletableFuture getMetadataInfoAsync(MetadataRequest request); + + /** + *
+     *  Retrieves OpenAPI.
+     * 
+ */ + OpenAPI getOpenAPI(OpenAPIRequest request); + + CompletableFuture getOpenAPIAsync(OpenAPIRequest request); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java index 01c1362d70e..7c91790497d 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java @@ -17,6 +17,7 @@ package org.apache.dubbo.metadata; public final class MetadataServiceV2OuterClass { + private MetadataServiceV2OuterClass() {} public static void registerAllExtensions(com.google.protobuf.ExtensionRegistryLite registry) {} @@ -45,6 +46,14 @@ public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry r internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_descriptor; static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor; + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable; + static final com.google.protobuf.Descriptors.Descriptor + internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor; + static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_org_apache_dubbo_metadata_OpenAPI_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { return descriptor; @@ -67,12 +76,20 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "(\005\022\014\n\004path\030\006 \001(\t\022D\n\006params\030\007 \003(\01324.org.a" + "pache.dubbo.metadata.ServiceInfoV2.Param" + "sEntry\032-\n\013ParamsEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005va" - + "lue\030\002 \001(\t:\0028\0012}\n\021MetadataServiceV2\022h\n\017Ge" - + "tMetadataInfo\022*.org.apache.dubbo.metadat" - + "a.MetadataRequest\032).org.apache.dubbo.met" - + "adata.MetadataInfoV2BZ\n\031org.apache.dubbo" - + ".metadataP\001Z;dubbo.apache.org/dubbo-go/v" - + "3/metadata/triple_api;triple_apib\006proto3" + + "lue\030\002 \001(\t:\0028\001\"\372\001\n\016OpenAPIRequest\022\022\n\005grou" + + "p\030\001 \001(\tH\000\210\001\001\022\024\n\007version\030\002 \001(\tH\001\210\001\001\022\013\n\003ta" + + "g\030\003 \003(\t\022\017\n\007service\030\004 \003(\t\022\024\n\007openapi\030\005 \001(" + + "\tH\002\210\001\001\022=\n\006format\030\006 \001(\0162(.org.apache.dubb" + + "o.metadata.OpenAPIFormatH\003\210\001\001\022\023\n\006pretty\030" + + "\007 \001(\010H\004\210\001\001B\010\n\006_groupB\n\n\010_versionB\n\n\010_ope" + + "napiB\t\n\007_formatB\t\n\007_pretty\"\030\n\007OpenAPI\022\r\n" + + "\005value\030\001 \001(\t*.\n\rOpenAPIFormat\022\010\n\004JSON\020\000\022" + + "\010\n\004YAML\020\001\022\t\n\005PROTO\020\0022\332\001\n\021MetadataService" + + "V2\022h\n\017GetMetadataInfo\022*.org.apache.dubbo" + + ".metadata.MetadataRequest\032).org.apache.d" + + "ubbo.metadata.MetadataInfoV2\022[\n\nGetOpenA" + "PI\022).org.apache.dubbo.metadata.OpenAPIRe" + + "quest\032\".org.apache.dubbo.metadata.OpenAP" + "IBZ\n\031org.apache.dubbo.metadataP\001Z;dubbo." + + "apache.org/dubbo-go/v3/metadata/triple_a" + "pi;triple_apib\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] {}); @@ -116,6 +133,20 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { internal_static_org_apache_dubbo_metadata_ServiceInfoV2_ParamsEntry_descriptor, new String[] { "Key", "Value", }); + internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor = + getDescriptor().getMessageTypes().get(3); + internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable = + new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor, new String[] { + "Group", "Version", "Tag", "Service", "Openapi", "Format", "Pretty", + }); + internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor = + getDescriptor().getMessageTypes().get(4); + internal_static_org_apache_dubbo_metadata_OpenAPI_fieldAccessorTable = + new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor, new String[] { + "Value", + }); } // @@protoc_insertion_point(outer_class_scope) diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPI.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPI.java new file mode 100644 index 00000000000..b8ef1efe7d2 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPI.java @@ -0,0 +1,587 @@ +/* + * 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; + +/** + *
+ * OpenAPI message.
+ * 
+ * + * Protobuf type {@code org.apache.dubbo.metadata.OpenAPI} + */ +public final class OpenAPI extends com.google.protobuf.GeneratedMessageV3 + implements + // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.OpenAPI) + OpenAPIOrBuilder { + + private static final long serialVersionUID = 0L; + + // Use OpenAPI.newBuilder() to construct. + private OpenAPI(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private OpenAPI() { + value_ = ""; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance(UnusedPrivateParameter unused) { + return new OpenAPI(); + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPI_fieldAccessorTable + .ensureFieldAccessorsInitialized(OpenAPI.class, Builder.class); + } + + public static final int VALUE_FIELD_NUMBER = 1; + + @SuppressWarnings("serial") + private volatile Object value_ = ""; + + /** + *
+     * The value of the OpenAPI.
+     * 
+ * + * string value = 1; + * @return The value. + */ + @Override + public String getValue() { + Object ref = value_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + value_ = s; + return s; + } + } + + /** + *
+     * The value of the OpenAPI.
+     * 
+ * + * string value = 1; + * @return The bytes for value. + */ + @Override + public com.google.protobuf.ByteString getValueBytes() { + Object ref = value_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + value_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(value_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, value_); + } + getUnknownFields().writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + size = 0; + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(value_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, value_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof OpenAPI)) { + return super.equals(obj); + } + OpenAPI other = (OpenAPI) obj; + + if (!getValue().equals(other.getValue())) { + return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) { + return false; + } + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + VALUE_FIELD_NUMBER; + hash = (53 * hash) + getValue().hashCode(); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static OpenAPI parseFrom(java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPI parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPI parseFrom(com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPI parseFrom( + com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPI parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPI parseFrom(byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPI parseFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); + } + + public static OpenAPI parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry); + } + + public static OpenAPI parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input); + } + + public static OpenAPI parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static OpenAPI parseFrom(com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); + } + + public static OpenAPI parseFrom( + com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(OpenAPI prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType(BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + *
+     * OpenAPI message.
+     * 
+ * + * Protobuf type {@code org.apache.dubbo.metadata.OpenAPI} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder + implements + // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.OpenAPI) + OpenAPIOrBuilder { + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPI_fieldAccessorTable + .ensureFieldAccessorsInitialized(OpenAPI.class, Builder.class); + } + + // Construct using org.apache.dubbo.metadata.OpenAPI.newBuilder() + private Builder() {} + + private Builder(BuilderParent parent) { + super(parent); + } + + @Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + value_ = ""; + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor; + } + + @Override + public OpenAPI getDefaultInstanceForType() { + return OpenAPI.getDefaultInstance(); + } + + @Override + public OpenAPI build() { + OpenAPI result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public OpenAPI buildPartial() { + OpenAPI result = new OpenAPI(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + onBuilt(); + return result; + } + + private void buildPartial0(OpenAPI result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.value_ = value_; + } + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof OpenAPI) { + return mergeFrom((OpenAPI) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(OpenAPI other) { + if (other == OpenAPI.getDefaultInstance()) { + return this; + } + if (!other.getValue().isEmpty()) { + value_ = other.value_; + bitField0_ |= 0x00000001; + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + value_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int bitField0_; + + private Object value_ = ""; + + /** + *
+         * The value of the OpenAPI.
+         * 
+ * + * string value = 1; + * @return The value. + */ + public String getValue() { + Object ref = value_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + value_ = s; + return s; + } else { + return (String) ref; + } + } + + /** + *
+         * The value of the OpenAPI.
+         * 
+ * + * string value = 1; + * @return The bytes for value. + */ + public com.google.protobuf.ByteString getValueBytes() { + Object ref = value_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + value_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + *
+         * The value of the OpenAPI.
+         * 
+ * + * string value = 1; + * @param value The value to set. + * @return This builder for chaining. + */ + public Builder setValue(String value) { + if (value == null) { + throw new NullPointerException(); + } + value_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + *
+         * The value of the OpenAPI.
+         * 
+ * + * string value = 1; + * @return This builder for chaining. + */ + public Builder clearValue() { + value_ = getDefaultInstance().getValue(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + + /** + *
+         * The value of the OpenAPI.
+         * 
+ * + * string value = 1; + * @param value The bytes for value to set. + * @return This builder for chaining. + */ + public Builder setValueBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + value_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + @Override + public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.OpenAPI) + } + + // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.OpenAPI) + private static final OpenAPI DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new OpenAPI(); + } + + public static OpenAPI getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @Override + public OpenAPI parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public OpenAPI getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIFormat.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIFormat.java new file mode 100644 index 00000000000..f679ee9b7ab --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIFormat.java @@ -0,0 +1,158 @@ +/* + * 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; + +/** + *
+ * Response format enumeration.
+ * 
+ * + * Protobuf enum {@code org.apache.dubbo.metadata.OpenAPIFormat} + */ +public enum OpenAPIFormat implements com.google.protobuf.ProtocolMessageEnum { + /** + *
+     * JSON format.
+     * 
+ * + * JSON = 0; + */ + JSON(0), + /** + *
+     * YAML format.
+     * 
+ * + * YAML = 1; + */ + YAML(1), + /** + *
+     * PROTO format.
+     * 
+ * + * PROTO = 2; + */ + PROTO(2), + UNRECOGNIZED(-1), + ; + + /** + *
+     * JSON format.
+     * 
+ * + * JSON = 0; + */ + public static final int JSON_VALUE = 0; + /** + *
+     * YAML format.
+     * 
+ * + * YAML = 1; + */ + public static final int YAML_VALUE = 1; + /** + *
+     * PROTO format.
+     * 
+ * + * PROTO = 2; + */ + public static final int PROTO_VALUE = 2; + + public final int getNumber() { + if (this == UNRECOGNIZED) { + throw new IllegalArgumentException("Can't get the number of an unknown enum value."); + } + return value; + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + * @deprecated Use {@link #forNumber(int)} instead. + */ + @Deprecated + public static OpenAPIFormat valueOf(int value) { + return forNumber(value); + } + + /** + * @param value The numeric wire value of the corresponding enum entry. + * @return The enum associated with the given numeric wire value. + */ + public static OpenAPIFormat forNumber(int value) { + switch (value) { + case 0: + return JSON; + case 1: + return YAML; + case 2: + return PROTO; + default: + return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap internalGetValueMap() { + return internalValueMap; + } + + private static final com.google.protobuf.Internal.EnumLiteMap internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public OpenAPIFormat findValueByNumber(int number) { + return OpenAPIFormat.forNumber(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { + if (this == UNRECOGNIZED) { + throw new IllegalStateException("Can't get the descriptor of an unrecognized enum value."); + } + return getDescriptor().getValues().get(ordinal()); + } + + public final com.google.protobuf.Descriptors.EnumDescriptor getDescriptorForType() { + return getDescriptor(); + } + + public static final com.google.protobuf.Descriptors.EnumDescriptor getDescriptor() { + return MetadataServiceV2OuterClass.getDescriptor().getEnumTypes().get(0); + } + + private static final OpenAPIFormat[] VALUES = values(); + + public static OpenAPIFormat valueOf(com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new IllegalArgumentException("EnumValueDescriptor is not for this type."); + } + if (desc.getIndex() == -1) { + return UNRECOGNIZED; + } + return VALUES[desc.getIndex()]; + } + + private final int value; + + private OpenAPIFormat(int value) { + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:org.apache.dubbo.metadata.OpenAPIFormat) +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIOrBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIOrBuilder.java new file mode 100644 index 00000000000..a9578f728f2 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIOrBuilder.java @@ -0,0 +1,43 @@ +/* + * 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; + +public interface OpenAPIOrBuilder + extends + // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.OpenAPI) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * The value of the OpenAPI.
+     * 
+ * + * string value = 1; + * @return The value. + */ + String getValue(); + + /** + *
+     * The value of the OpenAPI.
+     * 
+ * + * string value = 1; + * @return The bytes for value. + */ + com.google.protobuf.ByteString getValueBytes(); +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java new file mode 100644 index 00000000000..e8393680b43 --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java @@ -0,0 +1,1748 @@ +/* + * 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; + +/** + *
+ * OpenAPI request message.
+ * 
+ * + * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIRequest} + */ +public final class OpenAPIRequest extends com.google.protobuf.GeneratedMessageV3 + implements + // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.OpenAPIRequest) + OpenAPIRequestOrBuilder { + + private static final long serialVersionUID = 0L; + + // Use OpenAPIRequest.newBuilder() to construct. + private OpenAPIRequest(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private OpenAPIRequest() { + group_ = ""; + version_ = ""; + tag_ = com.google.protobuf.LazyStringArrayList.emptyList(); + service_ = com.google.protobuf.LazyStringArrayList.emptyList(); + openapi_ = ""; + format_ = 0; + } + + @Override + @SuppressWarnings({"unused"}) + protected Object newInstance(UnusedPrivateParameter unused) { + return new OpenAPIRequest(); + } + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized(OpenAPIRequest.class, Builder.class); + } + + private int bitField0_; + public static final int GROUP_FIELD_NUMBER = 1; + + @SuppressWarnings("serial") + private volatile Object group_ = ""; + + /** + *
+     * The openAPI group.
+     * 
+ * + * string group = 1; + * @return The group. + */ + @Override + public String getGroup() { + Object ref = group_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + group_ = s; + return s; + } + } + + /** + *
+     * The openAPI group.
+     * 
+ * + * string group = 1; + * @return The bytes for group. + */ + @Override + public com.google.protobuf.ByteString getGroupBytes() { + Object ref = group_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + group_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int VERSION_FIELD_NUMBER = 2; + + @SuppressWarnings("serial") + private volatile Object version_ = ""; + + /** + *
+     * The openAPI version, using a major.minor.patch versioning scheme
+     * e.g. 1.0.1
+     * 
+ * + * string version = 2; + * @return The version. + */ + @Override + public String getVersion() { + Object ref = version_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + version_ = s; + return s; + } + } + + /** + *
+     * The openAPI version, using a major.minor.patch versioning scheme
+     * e.g. 1.0.1
+     * 
+ * + * string version = 2; + * @return The bytes for version. + */ + @Override + public com.google.protobuf.ByteString getVersionBytes() { + Object ref = version_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int TAG_FIELD_NUMBER = 3; + + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList tag_ = com.google.protobuf.LazyStringArrayList.emptyList(); + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @return A list containing the tag. + */ + public com.google.protobuf.ProtocolStringList getTagList() { + return tag_; + } + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @return The count of tag. + */ + public int getTagCount() { + return tag_.size(); + } + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @param index The index of the element to return. + * @return The tag at the given index. + */ + public String getTag(int index) { + return tag_.get(index); + } + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @param index The index of the value to return. + * @return The bytes of the tag at the given index. + */ + public com.google.protobuf.ByteString getTagBytes(int index) { + return tag_.getByteString(index); + } + + public static final int SERVICE_FIELD_NUMBER = 4; + + @SuppressWarnings("serial") + private com.google.protobuf.LazyStringArrayList service_ = com.google.protobuf.LazyStringArrayList.emptyList(); + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @return A list containing the service. + */ + public com.google.protobuf.ProtocolStringList getServiceList() { + return service_; + } + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @return The count of service. + */ + public int getServiceCount() { + return service_.size(); + } + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @param index The index of the element to return. + * @return The service at the given index. + */ + public String getService(int index) { + return service_.get(index); + } + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @param index The index of the value to return. + * @return The bytes of the service at the given index. + */ + public com.google.protobuf.ByteString getServiceBytes(int index) { + return service_.getByteString(index); + } + + public static final int OPENAPI_FIELD_NUMBER = 5; + + @SuppressWarnings("serial") + private volatile Object openapi_ = ""; + + /** + *
+     * The openAPI specification version, using a major.minor.patch versioning scheme
+     * e.g. 3.0.1, 3.1.0
+     * The default value is '3.0.1'.
+     * 
+ * + * string openapi = 5; + * @return The openapi. + */ + @Override + public String getOpenapi() { + Object ref = openapi_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + openapi_ = s; + return s; + } + } + + /** + *
+     * The openAPI specification version, using a major.minor.patch versioning scheme
+     * e.g. 3.0.1, 3.1.0
+     * The default value is '3.0.1'.
+     * 
+ * + * string openapi = 5; + * @return The bytes for openapi. + */ + @Override + public com.google.protobuf.ByteString getOpenapiBytes() { + Object ref = openapi_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + openapi_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int FORMAT_FIELD_NUMBER = 6; + private int format_ = 0; + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return Whether the format field is set. + */ + @Override + public boolean hasFormat() { + return ((bitField0_ & 0x00000001) != 0); + } + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The enum numeric value on the wire for format. + */ + @Override + public int getFormatValue() { + return format_; + } + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The format. + */ + @Override + public OpenAPIFormat getFormat() { + OpenAPIFormat result = OpenAPIFormat.forNumber(format_); + return result == null ? OpenAPIFormat.UNRECOGNIZED : result; + } + + public static final int PRETTY_FIELD_NUMBER = 7; + private boolean pretty_ = false; + + /** + *
+     * Whether to pretty print for json.
+     * The default value is 'false'.
+     * 
+ * + * optional bool pretty = 7; + * @return Whether the pretty field is set. + */ + @Override + public boolean hasPretty() { + return ((bitField0_ & 0x00000002) != 0); + } + + /** + *
+     * Whether to pretty print for json.
+     * The default value is 'false'.
+     * 
+ * + * optional bool pretty = 7; + * @return The pretty. + */ + @Override + public boolean getPretty() { + return pretty_; + } + + private byte memoizedIsInitialized = -1; + + @Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } + + memoizedIsInitialized = 1; + return true; + } + + @Override + public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(group_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, group_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(version_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, version_); + } + for (int i = 0; i < tag_.size(); i++) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, tag_.getRaw(i)); + } + for (int i = 0; i < service_.size(); i++) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 4, service_.getRaw(i)); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(openapi_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 5, openapi_); + } + if (((bitField0_ & 0x00000001) != 0)) { + output.writeEnum(6, format_); + } + if (((bitField0_ & 0x00000002) != 0)) { + output.writeBool(7, pretty_); + } + getUnknownFields().writeTo(output); + } + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + size = 0; + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(group_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, group_); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(version_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, version_); + } + { + int dataSize = 0; + for (int i = 0; i < tag_.size(); i++) { + dataSize += computeStringSizeNoTag(tag_.getRaw(i)); + } + size += dataSize; + size += 1 * getTagList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < service_.size(); i++) { + dataSize += computeStringSizeNoTag(service_.getRaw(i)); + } + size += dataSize; + size += 1 * getServiceList().size(); + } + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(openapi_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, openapi_); + } + if (((bitField0_ & 0x00000001) != 0)) { + size += com.google.protobuf.CodedOutputStream.computeEnumSize(6, format_); + } + if (((bitField0_ & 0x00000002) != 0)) { + size += com.google.protobuf.CodedOutputStream.computeBoolSize(7, pretty_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSize = size; + return size; + } + + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof OpenAPIRequest)) { + return super.equals(obj); + } + OpenAPIRequest other = (OpenAPIRequest) obj; + + if (!getGroup().equals(other.getGroup())) { + return false; + } + if (!getVersion().equals(other.getVersion())) { + return false; + } + if (!getTagList().equals(other.getTagList())) { + return false; + } + if (!getServiceList().equals(other.getServiceList())) { + return false; + } + if (!getOpenapi().equals(other.getOpenapi())) { + return false; + } + if (hasFormat() != other.hasFormat()) { + return false; + } + if (hasFormat()) { + if (format_ != other.format_) { + return false; + } + } + if (hasPretty() != other.hasPretty()) { + return false; + } + if (hasPretty()) { + if (getPretty() != other.getPretty()) { + return false; + } + } + if (!getUnknownFields().equals(other.getUnknownFields())) { + return false; + } + return true; + } + + @Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + GROUP_FIELD_NUMBER; + hash = (53 * hash) + getGroup().hashCode(); + hash = (37 * hash) + VERSION_FIELD_NUMBER; + hash = (53 * hash) + getVersion().hashCode(); + if (getTagCount() > 0) { + hash = (37 * hash) + TAG_FIELD_NUMBER; + hash = (53 * hash) + getTagList().hashCode(); + } + if (getServiceCount() > 0) { + hash = (37 * hash) + SERVICE_FIELD_NUMBER; + hash = (53 * hash) + getServiceList().hashCode(); + } + hash = (37 * hash) + OPENAPI_FIELD_NUMBER; + hash = (53 * hash) + getOpenapi().hashCode(); + if (hasFormat()) { + hash = (37 * hash) + FORMAT_FIELD_NUMBER; + hash = (53 * hash) + format_; + } + if (hasPretty()) { + hash = (37 * hash) + PRETTY_FIELD_NUMBER; + hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(getPretty()); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static OpenAPIRequest parseFrom(java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPIRequest parseFrom( + java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPIRequest parseFrom(com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPIRequest parseFrom( + com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPIRequest parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static OpenAPIRequest parseFrom(byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static OpenAPIRequest parseFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); + } + + public static OpenAPIRequest parseFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry); + } + + public static OpenAPIRequest parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input); + } + + public static OpenAPIRequest parseDelimitedFrom( + java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static OpenAPIRequest parseFrom(com.google.protobuf.CodedInputStream input) throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); + } + + public static OpenAPIRequest parseFrom( + com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry); + } + + @Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(OpenAPIRequest prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); + } + + @Override + protected Builder newBuilderForType(BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + *
+     * OpenAPI request message.
+     * 
+ * + * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIRequest} + */ + public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder + implements + // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.OpenAPIRequest) + OpenAPIRequestOrBuilder { + + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor; + } + + @Override + protected FieldAccessorTable internalGetFieldAccessorTable() { + return MetadataServiceV2OuterClass + .internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized(OpenAPIRequest.class, Builder.class); + } + + // Construct using org.apache.dubbo.metadata.OpenAPIRequest.newBuilder() + private Builder() {} + + private Builder(BuilderParent parent) { + super(parent); + } + + @Override + public Builder clear() { + super.clear(); + bitField0_ = 0; + group_ = ""; + version_ = ""; + tag_ = com.google.protobuf.LazyStringArrayList.emptyList(); + service_ = com.google.protobuf.LazyStringArrayList.emptyList(); + openapi_ = ""; + format_ = 0; + pretty_ = false; + return this; + } + + @Override + public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor; + } + + @Override + public OpenAPIRequest getDefaultInstanceForType() { + return OpenAPIRequest.getDefaultInstance(); + } + + @Override + public OpenAPIRequest build() { + OpenAPIRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @Override + public OpenAPIRequest buildPartial() { + OpenAPIRequest result = new OpenAPIRequest(this); + if (bitField0_ != 0) { + buildPartial0(result); + } + onBuilt(); + return result; + } + + private void buildPartial0(OpenAPIRequest result) { + int from_bitField0_ = bitField0_; + if (((from_bitField0_ & 0x00000001) != 0)) { + result.group_ = group_; + } + if (((from_bitField0_ & 0x00000002) != 0)) { + result.version_ = version_; + } + if (((from_bitField0_ & 0x00000004) != 0)) { + tag_.makeImmutable(); + result.tag_ = tag_; + } + if (((from_bitField0_ & 0x00000008) != 0)) { + service_.makeImmutable(); + result.service_ = service_; + } + if (((from_bitField0_ & 0x00000010) != 0)) { + result.openapi_ = openapi_; + } + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000020) != 0)) { + result.format_ = format_; + to_bitField0_ |= 0x00000001; + } + if (((from_bitField0_ & 0x00000040) != 0)) { + result.pretty_ = pretty_; + to_bitField0_ |= 0x00000002; + } + result.bitField0_ |= to_bitField0_; + } + + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.addRepeatedField(field, value); + } + + @Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof OpenAPIRequest) { + return mergeFrom((OpenAPIRequest) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(OpenAPIRequest other) { + if (other == OpenAPIRequest.getDefaultInstance()) { + return this; + } + if (!other.getGroup().isEmpty()) { + group_ = other.group_; + bitField0_ |= 0x00000001; + onChanged(); + } + if (!other.getVersion().isEmpty()) { + version_ = other.version_; + bitField0_ |= 0x00000002; + onChanged(); + } + if (!other.tag_.isEmpty()) { + if (tag_.isEmpty()) { + tag_ = other.tag_; + bitField0_ |= 0x00000004; + } else { + ensureTagIsMutable(); + tag_.addAll(other.tag_); + } + onChanged(); + } + if (!other.service_.isEmpty()) { + if (service_.isEmpty()) { + service_ = other.service_; + bitField0_ |= 0x00000008; + } else { + ensureServiceIsMutable(); + service_.addAll(other.service_); + } + onChanged(); + } + if (!other.getOpenapi().isEmpty()) { + openapi_ = other.openapi_; + bitField0_ |= 0x00000010; + onChanged(); + } + if (other.hasFormat()) { + setFormat(other.getFormat()); + } + if (other.hasPretty()) { + setPretty(other.getPretty()); + } + this.mergeUnknownFields(other.getUnknownFields()); + onChanged(); + return this; + } + + @Override + public final boolean isInitialized() { + return true; + } + + @Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + if (extensionRegistry == null) { + throw new NullPointerException(); + } + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + group_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000001; + break; + } // case 10 + case 18: { + version_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000002; + break; + } // case 18 + case 26: { + String s = input.readStringRequireUtf8(); + ensureTagIsMutable(); + tag_.add(s); + break; + } // case 26 + case 34: { + String s = input.readStringRequireUtf8(); + ensureServiceIsMutable(); + service_.add(s); + break; + } // case 34 + case 42: { + openapi_ = input.readStringRequireUtf8(); + bitField0_ |= 0x00000010; + break; + } // case 42 + case 48: { + format_ = input.readEnum(); + bitField0_ |= 0x00000020; + break; + } // case 48 + case 56: { + pretty_ = input.readBool(); + bitField0_ |= 0x00000040; + break; + } // case 56 + default: { + if (!super.parseUnknownField(input, extensionRegistry, tag)) { + done = true; // was an endgroup tag + } + break; + } // default: + } // switch (tag) + } // while (!done) + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.unwrapIOException(); + } finally { + onChanged(); + } // finally + return this; + } + + private int bitField0_; + + private Object group_ = ""; + + /** + *
+         * The openAPI group.
+         * 
+ * + * string group = 1; + * @return The group. + */ + public String getGroup() { + Object ref = group_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + group_ = s; + return s; + } else { + return (String) ref; + } + } + + /** + *
+         * The openAPI group.
+         * 
+ * + * string group = 1; + * @return The bytes for group. + */ + public com.google.protobuf.ByteString getGroupBytes() { + Object ref = group_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + group_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + *
+         * The openAPI group.
+         * 
+ * + * string group = 1; + * @param value The group to set. + * @return This builder for chaining. + */ + public Builder setGroup(String value) { + if (value == null) { + throw new NullPointerException(); + } + group_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + /** + *
+         * The openAPI group.
+         * 
+ * + * string group = 1; + * @return This builder for chaining. + */ + public Builder clearGroup() { + group_ = getDefaultInstance().getGroup(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + + /** + *
+         * The openAPI group.
+         * 
+ * + * string group = 1; + * @param value The bytes for group to set. + * @return This builder for chaining. + */ + public Builder setGroupBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + group_ = value; + bitField0_ |= 0x00000001; + onChanged(); + return this; + } + + private Object version_ = ""; + + /** + *
+         * The openAPI version, using a major.minor.patch versioning scheme
+         * e.g. 1.0.1
+         * 
+ * + * string version = 2; + * @return The version. + */ + public String getVersion() { + Object ref = version_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + version_ = s; + return s; + } else { + return (String) ref; + } + } + + /** + *
+         * The openAPI version, using a major.minor.patch versioning scheme
+         * e.g. 1.0.1
+         * 
+ * + * string version = 2; + * @return The bytes for version. + */ + public com.google.protobuf.ByteString getVersionBytes() { + Object ref = version_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + version_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + *
+         * The openAPI version, using a major.minor.patch versioning scheme
+         * e.g. 1.0.1
+         * 
+ * + * string version = 2; + * @param value The version to set. + * @return This builder for chaining. + */ + public Builder setVersion(String value) { + if (value == null) { + throw new NullPointerException(); + } + version_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + /** + *
+         * The openAPI version, using a major.minor.patch versioning scheme
+         * e.g. 1.0.1
+         * 
+ * + * string version = 2; + * @return This builder for chaining. + */ + public Builder clearVersion() { + version_ = getDefaultInstance().getVersion(); + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + + /** + *
+         * The openAPI version, using a major.minor.patch versioning scheme
+         * e.g. 1.0.1
+         * 
+ * + * string version = 2; + * @param value The bytes for version to set. + * @return This builder for chaining. + */ + public Builder setVersionBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + version_ = value; + bitField0_ |= 0x00000002; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList tag_ = com.google.protobuf.LazyStringArrayList.emptyList(); + + private void ensureTagIsMutable() { + if (!tag_.isModifiable()) { + tag_ = new com.google.protobuf.LazyStringArrayList(tag_); + } + bitField0_ |= 0x00000004; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @return A list containing the tag. + */ + public com.google.protobuf.ProtocolStringList getTagList() { + tag_.makeImmutable(); + return tag_; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @return The count of tag. + */ + public int getTagCount() { + return tag_.size(); + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param index The index of the element to return. + * @return The tag at the given index. + */ + public String getTag(int index) { + return tag_.get(index); + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param index The index of the value to return. + * @return The bytes of the tag at the given index. + */ + public com.google.protobuf.ByteString getTagBytes(int index) { + return tag_.getByteString(index); + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param index The index to set the value at. + * @param value The tag to set. + * @return This builder for chaining. + */ + public Builder setTag(int index, String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureTagIsMutable(); + tag_.set(index, value); + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param value The tag to add. + * @return This builder for chaining. + */ + public Builder addTag(String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureTagIsMutable(); + tag_.add(value); + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param values The tag to add. + * @return This builder for chaining. + */ + public Builder addAllTag(Iterable values) { + ensureTagIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll(values, tag_); + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @return This builder for chaining. + */ + public Builder clearTag() { + tag_ = com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000004); + ; + onChanged(); + return this; + } + + /** + *
+         * The openAPI tags. Each tag is an or condition.
+         * 
+ * + * repeated string tag = 3; + * @param value The bytes of the tag to add. + * @return This builder for chaining. + */ + public Builder addTagBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + ensureTagIsMutable(); + tag_.add(value); + bitField0_ |= 0x00000004; + onChanged(); + return this; + } + + private com.google.protobuf.LazyStringArrayList service_ = com.google.protobuf.LazyStringArrayList.emptyList(); + + private void ensureServiceIsMutable() { + if (!service_.isModifiable()) { + service_ = new com.google.protobuf.LazyStringArrayList(service_); + } + bitField0_ |= 0x00000008; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @return A list containing the service. + */ + public com.google.protobuf.ProtocolStringList getServiceList() { + service_.makeImmutable(); + return service_; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @return The count of service. + */ + public int getServiceCount() { + return service_.size(); + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param index The index of the element to return. + * @return The service at the given index. + */ + public String getService(int index) { + return service_.get(index); + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param index The index of the value to return. + * @return The bytes of the service at the given index. + */ + public com.google.protobuf.ByteString getServiceBytes(int index) { + return service_.getByteString(index); + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param index The index to set the value at. + * @param value The service to set. + * @return This builder for chaining. + */ + public Builder setService(int index, String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureServiceIsMutable(); + service_.set(index, value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param value The service to add. + * @return This builder for chaining. + */ + public Builder addService(String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureServiceIsMutable(); + service_.add(value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param values The service to add. + * @return This builder for chaining. + */ + public Builder addAllService(Iterable values) { + ensureServiceIsMutable(); + com.google.protobuf.AbstractMessageLite.Builder.addAll(values, service_); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @return This builder for chaining. + */ + public Builder clearService() { + service_ = com.google.protobuf.LazyStringArrayList.emptyList(); + bitField0_ = (bitField0_ & ~0x00000008); + ; + onChanged(); + return this; + } + + /** + *
+         * The openAPI services. Each service is an or condition.
+         * 
+ * + * repeated string service = 4; + * @param value The bytes of the service to add. + * @return This builder for chaining. + */ + public Builder addServiceBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + ensureServiceIsMutable(); + service_.add(value); + bitField0_ |= 0x00000008; + onChanged(); + return this; + } + + private Object openapi_ = ""; + + /** + *
+         * The openAPI specification version, using a major.minor.patch versioning scheme
+         * e.g. 3.0.1, 3.1.0
+         * The default value is '3.0.1'.
+         * 
+ * + * string openapi = 5; + * @return The openapi. + */ + public String getOpenapi() { + Object ref = openapi_; + if (!(ref instanceof String)) { + com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + openapi_ = s; + return s; + } else { + return (String) ref; + } + } + + /** + *
+         * The openAPI specification version, using a major.minor.patch versioning scheme
+         * e.g. 3.0.1, 3.1.0
+         * The default value is '3.0.1'.
+         * 
+ * + * string openapi = 5; + * @return The bytes for openapi. + */ + public com.google.protobuf.ByteString getOpenapiBytes() { + Object ref = openapi_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); + openapi_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + *
+         * The openAPI specification version, using a major.minor.patch versioning scheme
+         * e.g. 3.0.1, 3.1.0
+         * The default value is '3.0.1'.
+         * 
+ * + * string openapi = 5; + * @param value The openapi to set. + * @return This builder for chaining. + */ + public Builder setOpenapi(String value) { + if (value == null) { + throw new NullPointerException(); + } + openapi_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + /** + *
+         * The openAPI specification version, using a major.minor.patch versioning scheme
+         * e.g. 3.0.1, 3.1.0
+         * The default value is '3.0.1'.
+         * 
+ * + * string openapi = 5; + * @return This builder for chaining. + */ + public Builder clearOpenapi() { + openapi_ = getDefaultInstance().getOpenapi(); + bitField0_ = (bitField0_ & ~0x00000010); + onChanged(); + return this; + } + + /** + *
+         * The openAPI specification version, using a major.minor.patch versioning scheme
+         * e.g. 3.0.1, 3.1.0
+         * The default value is '3.0.1'.
+         * 
+ * + * string openapi = 5; + * @param value The bytes for openapi to set. + * @return This builder for chaining. + */ + public Builder setOpenapiBytes(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + openapi_ = value; + bitField0_ |= 0x00000010; + onChanged(); + return this; + } + + private int format_ = 0; + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return Whether the format field is set. + */ + @Override + public boolean hasFormat() { + return ((bitField0_ & 0x00000020) != 0); + } + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The enum numeric value on the wire for format. + */ + @Override + public int getFormatValue() { + return format_; + } + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @param value The enum numeric value on the wire for format to set. + * @return This builder for chaining. + */ + public Builder setFormatValue(int value) { + format_ = value; + bitField0_ |= 0x00000020; + onChanged(); + return this; + } + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The format. + */ + @Override + public OpenAPIFormat getFormat() { + OpenAPIFormat result = OpenAPIFormat.forNumber(format_); + return result == null ? OpenAPIFormat.UNRECOGNIZED : result; + } + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @param value The format to set. + * @return This builder for chaining. + */ + public Builder setFormat(OpenAPIFormat value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + format_ = value.getNumber(); + onChanged(); + return this; + } + + /** + *
+         * The format of the response.
+         * The default value is 'JSON'.
+         * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return This builder for chaining. + */ + public Builder clearFormat() { + bitField0_ = (bitField0_ & ~0x00000020); + format_ = 0; + onChanged(); + return this; + } + + private boolean pretty_; + + /** + *
+         * Whether to pretty print for json.
+         * The default value is 'false'.
+         * 
+ * + * optional bool pretty = 7; + * @return Whether the pretty field is set. + */ + @Override + public boolean hasPretty() { + return ((bitField0_ & 0x00000040) != 0); + } + + /** + *
+         * Whether to pretty print for json.
+         * The default value is 'false'.
+         * 
+ * + * optional bool pretty = 7; + * @return The pretty. + */ + @Override + public boolean getPretty() { + return pretty_; + } + + /** + *
+         * Whether to pretty print for json.
+         * The default value is 'false'.
+         * 
+ * + * optional bool pretty = 7; + * @param value The pretty to set. + * @return This builder for chaining. + */ + public Builder setPretty(boolean value) { + + pretty_ = value; + bitField0_ |= 0x00000040; + onChanged(); + return this; + } + + /** + *
+         * Whether to pretty print for json.
+         * The default value is 'false'.
+         * 
+ * + * optional bool pretty = 7; + * @return This builder for chaining. + */ + public Builder clearPretty() { + bitField0_ = (bitField0_ & ~0x00000040); + pretty_ = false; + onChanged(); + return this; + } + + @Override + public final Builder setUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFields(unknownFields); + } + + @Override + public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.OpenAPIRequest) + } + + // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.OpenAPIRequest) + private static final OpenAPIRequest DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new OpenAPIRequest(); + } + + public static OpenAPIRequest getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + @Override + public OpenAPIRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + Builder builder = newBuilder(); + try { + builder.mergeFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(builder.buildPartial()); + } catch (com.google.protobuf.UninitializedMessageException e) { + throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException(e) + .setUnfinishedMessage(builder.buildPartial()); + } + return builder.buildPartial(); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @Override + public OpenAPIRequest getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequestOrBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequestOrBuilder.java new file mode 100644 index 00000000000..00e03f260cd --- /dev/null +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequestOrBuilder.java @@ -0,0 +1,228 @@ +/* + * 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; + +public interface OpenAPIRequestOrBuilder + extends + // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.OpenAPIRequest) + com.google.protobuf.MessageOrBuilder { + + /** + *
+     * The openAPI group.
+     * 
+ * + * string group = 1; + * @return The group. + */ + String getGroup(); + + /** + *
+     * The openAPI group.
+     * 
+ * + * string group = 1; + * @return The bytes for group. + */ + com.google.protobuf.ByteString getGroupBytes(); + + /** + *
+     * The openAPI version, using a major.minor.patch versioning scheme
+     * e.g. 1.0.1
+     * 
+ * + * string version = 2; + * @return The version. + */ + String getVersion(); + + /** + *
+     * The openAPI version, using a major.minor.patch versioning scheme
+     * e.g. 1.0.1
+     * 
+ * + * string version = 2; + * @return The bytes for version. + */ + com.google.protobuf.ByteString getVersionBytes(); + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @return A list containing the tag. + */ + java.util.List getTagList(); + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @return The count of tag. + */ + int getTagCount(); + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @param index The index of the element to return. + * @return The tag at the given index. + */ + String getTag(int index); + + /** + *
+     * The openAPI tags. Each tag is an or condition.
+     * 
+ * + * repeated string tag = 3; + * @param index The index of the value to return. + * @return The bytes of the tag at the given index. + */ + com.google.protobuf.ByteString getTagBytes(int index); + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @return A list containing the service. + */ + java.util.List getServiceList(); + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @return The count of service. + */ + int getServiceCount(); + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @param index The index of the element to return. + * @return The service at the given index. + */ + String getService(int index); + + /** + *
+     * The openAPI services. Each service is an or condition.
+     * 
+ * + * repeated string service = 4; + * @param index The index of the value to return. + * @return The bytes of the service at the given index. + */ + com.google.protobuf.ByteString getServiceBytes(int index); + + /** + *
+     * The openAPI specification version, using a major.minor.patch versioning scheme
+     * e.g. 3.0.1, 3.1.0
+     * The default value is '3.0.1'.
+     * 
+ * + * string openapi = 5; + * @return The openapi. + */ + String getOpenapi(); + + /** + *
+     * The openAPI specification version, using a major.minor.patch versioning scheme
+     * e.g. 3.0.1, 3.1.0
+     * The default value is '3.0.1'.
+     * 
+ * + * string openapi = 5; + * @return The bytes for openapi. + */ + com.google.protobuf.ByteString getOpenapiBytes(); + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return Whether the format field is set. + */ + boolean hasFormat(); + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The enum numeric value on the wire for format. + */ + int getFormatValue(); + + /** + *
+     * The format of the response.
+     * The default value is 'JSON'.
+     * 
+ * + * optional .org.apache.dubbo.metadata.OpenAPIFormat format = 6; + * @return The format. + */ + OpenAPIFormat getFormat(); + + /** + *
+     * Whether to pretty print for json.
+     * The default value is 'false'.
+     * 
+ * + * optional bool pretty = 7; + * @return Whether the pretty field is set. + */ + boolean hasPretty(); + + /** + *
+     * Whether to pretty print for json.
+     * The default value is 'false'.
+     * 
+ * + * optional bool pretty = 7; + * @return The pretty. + */ + boolean getPretty(); +} diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java index 8da76533c0c..7292671d56c 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java @@ -17,13 +17,19 @@ package org.apache.dubbo.metadata; /** + *
+ * Service information message.
+ * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.ServiceInfoV2} */ public final class ServiceInfoV2 extends com.google.protobuf.GeneratedMessageV3 implements // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.ServiceInfoV2) ServiceInfoV2OrBuilder { + private static final long serialVersionUID = 0L; + // Use ServiceInfoV2.newBuilder() to construct. private ServiceInfoV2(com.google.protobuf.GeneratedMessageV3.Builder builder) { super(builder); @@ -68,7 +74,12 @@ protected FieldAccessorTable internalGetFieldAccessorTable() { @SuppressWarnings("serial") private volatile Object name_ = ""; + /** + *
+     * The service name.
+     * 
+ * * string name = 1; * @return The name. */ @@ -84,7 +95,12 @@ public String getName() { return s; } } + /** + *
+     * The service name.
+     * 
+ * * string name = 1; * @return The bytes for name. */ @@ -104,7 +120,12 @@ public com.google.protobuf.ByteString getNameBytes() { @SuppressWarnings("serial") private volatile Object group_ = ""; + /** + *
+     * The service group.
+     * 
+ * * string group = 2; * @return The group. */ @@ -120,7 +141,12 @@ public String getGroup() { return s; } } + /** + *
+     * The service group.
+     * 
+ * * string group = 2; * @return The bytes for group. */ @@ -140,7 +166,12 @@ public com.google.protobuf.ByteString getGroupBytes() { @SuppressWarnings("serial") private volatile Object version_ = ""; + /** + *
+     * The service version.
+     * 
+ * * string version = 3; * @return The version. */ @@ -156,7 +187,12 @@ public String getVersion() { return s; } } + /** + *
+     * The service version.
+     * 
+ * * string version = 3; * @return The bytes for version. */ @@ -176,7 +212,12 @@ public com.google.protobuf.ByteString getVersionBytes() { @SuppressWarnings("serial") private volatile Object protocol_ = ""; + /** + *
+     * The service protocol.
+     * 
+ * * string protocol = 4; * @return The protocol. */ @@ -192,7 +233,12 @@ public String getProtocol() { return s; } } + /** + *
+     * The service protocol.
+     * 
+ * * string protocol = 4; * @return The bytes for protocol. */ @@ -210,7 +256,12 @@ public com.google.protobuf.ByteString getProtocolBytes() { public static final int PORT_FIELD_NUMBER = 5; private int port_ = 0; + /** + *
+     * The service port.
+     * 
+ * * int32 port = 5; * @return The port. */ @@ -223,7 +274,12 @@ public int getPort() { @SuppressWarnings("serial") private volatile Object path_ = ""; + /** + *
+     * The service path.
+     * 
+ * * string path = 6; * @return The path. */ @@ -239,7 +295,12 @@ public String getPath() { return s; } } + /** + *
+     * The service path.
+     * 
+ * * string path = 6; * @return The bytes for path. */ @@ -258,6 +319,7 @@ public com.google.protobuf.ByteString getPathBytes() { public static final int PARAMS_FIELD_NUMBER = 7; private static final class ParamsDefaultEntryHolder { + static final com.google.protobuf.MapEntry defaultEntry = com.google.protobuf.MapEntry.newDefaultInstance( MetadataServiceV2OuterClass @@ -281,7 +343,12 @@ private com.google.protobuf.MapField internalGetParams() { public int getParamsCount() { return internalGetParams().getMap().size(); } + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ @Override @@ -291,6 +358,7 @@ public boolean containsParams(String key) { } return internalGetParams().getMap().containsKey(key); } + /** * Use {@link #getParamsMap()} instead. */ @@ -299,14 +367,24 @@ public boolean containsParams(String key) { public java.util.Map getParams() { return getParamsMap(); } + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ @Override public java.util.Map getParamsMap() { return internalGetParams().getMap(); } + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ @Override @@ -320,7 +398,12 @@ public java.util.Map getParamsMap() { java.util.Map map = internalGetParams().getMap(); return map.containsKey(key) ? map.get(key) : defaultValue; } + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ @Override @@ -340,8 +423,12 @@ public String getParamsOrThrow(String key) { @Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; - if (isInitialized == 1) return true; - if (isInitialized == 0) return false; + if (isInitialized == 1) { + return true; + } + if (isInitialized == 0) { + return false; + } memoizedIsInitialized = 1; return true; @@ -375,7 +462,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io @Override public int getSerializedSize() { int size = memoizedSize; - if (size != -1) return size; + if (size != -1) { + return size; + } size = 0; if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) { @@ -420,14 +509,30 @@ public boolean equals(final Object obj) { } ServiceInfoV2 other = (ServiceInfoV2) obj; - if (!getName().equals(other.getName())) return false; - if (!getGroup().equals(other.getGroup())) return false; - if (!getVersion().equals(other.getVersion())) return false; - if (!getProtocol().equals(other.getProtocol())) return false; - if (getPort() != other.getPort()) return false; - if (!getPath().equals(other.getPath())) return false; - if (!internalGetParams().equals(other.internalGetParams())) return false; - if (!getUnknownFields().equals(other.getUnknownFields())) return false; + if (!getName().equals(other.getName())) { + return false; + } + if (!getGroup().equals(other.getGroup())) { + return false; + } + if (!getVersion().equals(other.getVersion())) { + return false; + } + if (!getProtocol().equals(other.getProtocol())) { + return false; + } + if (getPort() != other.getPort()) { + return false; + } + if (!getPath().equals(other.getPath())) { + return false; + } + if (!internalGetParams().equals(other.internalGetParams())) { + return false; + } + if (!getUnknownFields().equals(other.getUnknownFields())) { + return false; + } return true; } @@ -543,13 +648,19 @@ protected Builder newBuilderForType(BuilderParent parent) { Builder builder = new Builder(parent); return builder; } + /** + *
+     * Service information message.
+     * 
+ * * Protobuf type {@code org.apache.dubbo.metadata.ServiceInfoV2} */ public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder implements // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.ServiceInfoV2) ServiceInfoV2OrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_ServiceInfoV2_descriptor; } @@ -657,6 +768,37 @@ private void buildPartial0(ServiceInfoV2 result) { } } + @Override + public Builder clone() { + return super.clone(); + } + + @Override + public Builder setField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.setField(field, value); + } + + @Override + public Builder clearField(com.google.protobuf.Descriptors.FieldDescriptor field) { + return super.clearField(field); + } + + @Override + public Builder clearOneof(com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return super.clearOneof(oneof); + } + + @Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, int index, Object value) { + return super.setRepeatedField(field, index, value); + } + + @Override + public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor field, Object value) { + return super.addRepeatedField(field, value); + } + @Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof ServiceInfoV2) { @@ -668,7 +810,9 @@ public Builder mergeFrom(com.google.protobuf.Message other) { } public Builder mergeFrom(ServiceInfoV2 other) { - if (other == ServiceInfoV2.getDefaultInstance()) return this; + if (other == ServiceInfoV2.getDefaultInstance()) { + return this; + } if (!other.getName().isEmpty()) { name_ = other.name_; bitField0_ |= 0x00000001; @@ -780,7 +924,12 @@ public Builder mergeFrom( private int bitField0_; private Object name_ = ""; + /** + *
+         * The service name.
+         * 
+ * * string name = 1; * @return The name. */ @@ -795,7 +944,12 @@ public String getName() { return (String) ref; } } + /** + *
+         * The service name.
+         * 
+ * * string name = 1; * @return The bytes for name. */ @@ -809,7 +963,12 @@ public com.google.protobuf.ByteString getNameBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The service name.
+         * 
+ * * string name = 1; * @param value The name to set. * @return This builder for chaining. @@ -823,7 +982,12 @@ public Builder setName(String value) { onChanged(); return this; } + /** + *
+         * The service name.
+         * 
+ * * string name = 1; * @return This builder for chaining. */ @@ -833,7 +997,12 @@ public Builder clearName() { onChanged(); return this; } + /** + *
+         * The service name.
+         * 
+ * * string name = 1; * @param value The bytes for name to set. * @return This builder for chaining. @@ -850,7 +1019,12 @@ public Builder setNameBytes(com.google.protobuf.ByteString value) { } private Object group_ = ""; + /** + *
+         * The service group.
+         * 
+ * * string group = 2; * @return The group. */ @@ -865,7 +1039,12 @@ public String getGroup() { return (String) ref; } } + /** + *
+         * The service group.
+         * 
+ * * string group = 2; * @return The bytes for group. */ @@ -879,7 +1058,12 @@ public com.google.protobuf.ByteString getGroupBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The service group.
+         * 
+ * * string group = 2; * @param value The group to set. * @return This builder for chaining. @@ -893,7 +1077,12 @@ public Builder setGroup(String value) { onChanged(); return this; } + /** + *
+         * The service group.
+         * 
+ * * string group = 2; * @return This builder for chaining. */ @@ -903,7 +1092,12 @@ public Builder clearGroup() { onChanged(); return this; } + /** + *
+         * The service group.
+         * 
+ * * string group = 2; * @param value The bytes for group to set. * @return This builder for chaining. @@ -920,7 +1114,12 @@ public Builder setGroupBytes(com.google.protobuf.ByteString value) { } private Object version_ = ""; + /** + *
+         * The service version.
+         * 
+ * * string version = 3; * @return The version. */ @@ -935,7 +1134,12 @@ public String getVersion() { return (String) ref; } } + /** + *
+         * The service version.
+         * 
+ * * string version = 3; * @return The bytes for version. */ @@ -949,7 +1153,12 @@ public com.google.protobuf.ByteString getVersionBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The service version.
+         * 
+ * * string version = 3; * @param value The version to set. * @return This builder for chaining. @@ -963,7 +1172,12 @@ public Builder setVersion(String value) { onChanged(); return this; } + /** + *
+         * The service version.
+         * 
+ * * string version = 3; * @return This builder for chaining. */ @@ -973,7 +1187,12 @@ public Builder clearVersion() { onChanged(); return this; } + /** + *
+         * The service version.
+         * 
+ * * string version = 3; * @param value The bytes for version to set. * @return This builder for chaining. @@ -990,7 +1209,12 @@ public Builder setVersionBytes(com.google.protobuf.ByteString value) { } private Object protocol_ = ""; + /** + *
+         * The service protocol.
+         * 
+ * * string protocol = 4; * @return The protocol. */ @@ -1005,7 +1229,12 @@ public String getProtocol() { return (String) ref; } } + /** + *
+         * The service protocol.
+         * 
+ * * string protocol = 4; * @return The bytes for protocol. */ @@ -1019,7 +1248,12 @@ public com.google.protobuf.ByteString getProtocolBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The service protocol.
+         * 
+ * * string protocol = 4; * @param value The protocol to set. * @return This builder for chaining. @@ -1033,7 +1267,12 @@ public Builder setProtocol(String value) { onChanged(); return this; } + /** + *
+         * The service protocol.
+         * 
+ * * string protocol = 4; * @return This builder for chaining. */ @@ -1043,7 +1282,12 @@ public Builder clearProtocol() { onChanged(); return this; } + /** + *
+         * The service protocol.
+         * 
+ * * string protocol = 4; * @param value The bytes for protocol to set. * @return This builder for chaining. @@ -1060,7 +1304,12 @@ public Builder setProtocolBytes(com.google.protobuf.ByteString value) { } private int port_; + /** + *
+         * The service port.
+         * 
+ * * int32 port = 5; * @return The port. */ @@ -1068,7 +1317,12 @@ public Builder setProtocolBytes(com.google.protobuf.ByteString value) { public int getPort() { return port_; } + /** + *
+         * The service port.
+         * 
+ * * int32 port = 5; * @param value The port to set. * @return This builder for chaining. @@ -1080,7 +1334,12 @@ public Builder setPort(int value) { onChanged(); return this; } + /** + *
+         * The service port.
+         * 
+ * * int32 port = 5; * @return This builder for chaining. */ @@ -1092,7 +1351,12 @@ public Builder clearPort() { } private Object path_ = ""; + /** + *
+         * The service path.
+         * 
+ * * string path = 6; * @return The path. */ @@ -1107,7 +1371,12 @@ public String getPath() { return (String) ref; } } + /** + *
+         * The service path.
+         * 
+ * * string path = 6; * @return The bytes for path. */ @@ -1121,7 +1390,12 @@ public com.google.protobuf.ByteString getPathBytes() { return (com.google.protobuf.ByteString) ref; } } + /** + *
+         * The service path.
+         * 
+ * * string path = 6; * @param value The path to set. * @return This builder for chaining. @@ -1135,7 +1409,12 @@ public Builder setPath(String value) { onChanged(); return this; } + /** + *
+         * The service path.
+         * 
+ * * string path = 6; * @return This builder for chaining. */ @@ -1145,7 +1424,12 @@ public Builder clearPath() { onChanged(); return this; } + /** + *
+         * The service path.
+         * 
+ * * string path = 6; * @param value The bytes for path to set. * @return This builder for chaining. @@ -1185,7 +1469,12 @@ private com.google.protobuf.MapField internalGetMutableParams() public int getParamsCount() { return internalGetParams().getMap().size(); } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ @Override @@ -1195,6 +1484,7 @@ public boolean containsParams(String key) { } return internalGetParams().getMap().containsKey(key); } + /** * Use {@link #getParamsMap()} instead. */ @@ -1203,14 +1493,24 @@ public boolean containsParams(String key) { public java.util.Map getParams() { return getParamsMap(); } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ @Override public java.util.Map getParamsMap() { return internalGetParams().getMap(); } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ @Override @@ -1224,7 +1524,12 @@ public java.util.Map getParamsMap() { java.util.Map map = internalGetParams().getMap(); return map.containsKey(key) ? map.get(key) : defaultValue; } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ @Override @@ -1244,7 +1549,12 @@ public Builder clearParams() { internalGetMutableParams().getMutableMap().clear(); return this; } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ public Builder removeParams(String key) { @@ -1254,6 +1564,7 @@ public Builder removeParams(String key) { internalGetMutableParams().getMutableMap().remove(key); return this; } + /** * Use alternate mutation accessors instead. */ @@ -1262,7 +1573,12 @@ public java.util.Map getMutableParams() { bitField0_ |= 0x00000040; return internalGetMutableParams().getMutableMap(); } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ public Builder putParams(String key, String value) { @@ -1276,7 +1592,12 @@ public Builder putParams(String key, String value) { bitField0_ |= 0x00000040; return this; } + /** + *
+         * A map of service parameters.
+         * 
+ * * map<string, string> params = 7; */ public Builder putAllParams(java.util.Map values) { diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2OrBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2OrBuilder.java index 6c39dd594fc..3daacf0d100 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2OrBuilder.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2OrBuilder.java @@ -22,84 +22,153 @@ public interface ServiceInfoV2OrBuilder com.google.protobuf.MessageOrBuilder { /** + *
+     * The service name.
+     * 
+ * * string name = 1; * @return The name. */ String getName(); + /** + *
+     * The service name.
+     * 
+ * * string name = 1; * @return The bytes for name. */ com.google.protobuf.ByteString getNameBytes(); /** + *
+     * The service group.
+     * 
+ * * string group = 2; * @return The group. */ String getGroup(); + /** + *
+     * The service group.
+     * 
+ * * string group = 2; * @return The bytes for group. */ com.google.protobuf.ByteString getGroupBytes(); /** + *
+     * The service version.
+     * 
+ * * string version = 3; * @return The version. */ String getVersion(); + /** + *
+     * The service version.
+     * 
+ * * string version = 3; * @return The bytes for version. */ com.google.protobuf.ByteString getVersionBytes(); /** + *
+     * The service protocol.
+     * 
+ * * string protocol = 4; * @return The protocol. */ String getProtocol(); + /** + *
+     * The service protocol.
+     * 
+ * * string protocol = 4; * @return The bytes for protocol. */ com.google.protobuf.ByteString getProtocolBytes(); /** + *
+     * The service port.
+     * 
+ * * int32 port = 5; * @return The port. */ int getPort(); /** + *
+     * The service path.
+     * 
+ * * string path = 6; * @return The path. */ String getPath(); + /** + *
+     * The service path.
+     * 
+ * * string path = 6; * @return The bytes for path. */ com.google.protobuf.ByteString getPathBytes(); /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ int getParamsCount(); + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ boolean containsParams(String key); + /** * Use {@link #getParamsMap()} instead. */ @Deprecated java.util.Map getParams(); + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ java.util.Map getParamsMap(); + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ /* nullable */ @@ -107,7 +176,12 @@ String getParamsOrDefault( String key, /* nullable */ String defaultValue); + /** + *
+     * A map of service parameters.
+     * 
+ * * map<string, string> params = 7; */ String getParamsOrThrow(String key); diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto b/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto index 77c49d1021e..b47678d21d5 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto +++ b/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto @@ -22,26 +22,85 @@ option go_package = "dubbo.apache.org/dubbo-go/v3/metadata/triple_api;triple_api option java_package = "org.apache.dubbo.metadata"; option java_multiple_files = true; +// Metadata service V2. service MetadataServiceV2{ + + // Retrieves metadata information. rpc GetMetadataInfo(MetadataRequest) returns (MetadataInfoV2); + + // Retrieves OpenAPI. + rpc GetOpenAPI(OpenAPIRequest) returns (OpenAPI); } +// Metadata request message. message MetadataRequest{ + // The revision of the metadata. string revision = 1; } +// Metadata information message. message MetadataInfoV2{ + // The application name. string app = 1; + // The application version. string version = 2; + // A map of service information. map services = 3; } +// Service information message. message ServiceInfoV2{ + // The service name. string name = 1; + // The service group. string group = 2; + // The service version. string version = 3; + // The service protocol. string protocol = 4; + // The service port. int32 port = 5; + // The service path. string path = 6; + // A map of service parameters. map params = 7; } + +// OpenAPI request message. +message OpenAPIRequest { + // The openAPI group. + string group = 1; + // The openAPI version, using a major.minor.patch versioning scheme + // e.g. 1.0.1 + string version = 2; + // The openAPI tags. Each tag is an or condition. + repeated string tag = 3; + // The openAPI services. Each service is an or condition. + repeated string service = 4; + // The openAPI specification version, using a major.minor.patch versioning scheme + // e.g. 3.0.1, 3.1.0 + // The default value is '3.0.1'. + string openapi = 5; + // The format of the response. + // The default value is 'JSON'. + optional OpenAPIFormat format = 6; + // Whether to pretty print for json. + // The default value is 'false'. + optional bool pretty = 7; +} + +// Response format enumeration. +enum OpenAPIFormat { + // JSON format. + JSON = 0; + // YAML format. + YAML = 1; + // PROTO format. + PROTO = 2; +} + +// OpenAPI message. +message OpenAPI { + // The value of the OpenAPI. + string value = 1; +} diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.java new file mode 100644 index 00000000000..e8938d0d839 --- /dev/null +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.java @@ -0,0 +1,95 @@ +/* + * 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.qos.command.impl; + +import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.qos.api.BaseCommand; +import org.apache.dubbo.qos.api.Cmd; +import org.apache.dubbo.qos.api.CommandContext; +import org.apache.dubbo.qos.api.PermissionLevel; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; +import org.apache.dubbo.rpc.model.FrameworkModel; + +@Cmd( + name = "getOpenAPI", + summary = "Get the openapi descriptor for specified services.", + example = { + "getOpenAPI", + "getOpenAPI groupA", + "getOpenAPI com.example.DemoService", + "getOpenAPI --group groupA --version 1.1.0 --tag tagA --service com.example. --openapi 3.0.0 --format yaml", + }, + requiredPermissionLevel = PermissionLevel.PRIVATE) +public class GetOpenAPI implements BaseCommand { + + private final FrameworkModel frameworkModel; + + public GetOpenAPI(FrameworkModel frameworkModel) { + this.frameworkModel = frameworkModel; + } + + @Override + public String execute(CommandContext commandContext, String[] args) { + OpenAPIService openAPIService = frameworkModel.getDefaultExtensionOrNull(OpenAPIService.class); + if (openAPIService == null) { + return "OpenAPI is not available"; + } + + OpenAPIRequest request = new OpenAPIRequest(); + + int len = args.length; + if (len > 0) { + if (len == 1) { + String arg0 = args[0]; + if (arg0.indexOf('.') > 0) { + request.setService(new String[] {arg0}); + } else { + request.setGroup(arg0); + } + } else { + for (int i = 0; i < len; i += 2) { + String value = args[i + 1]; + switch (StringUtils.substringAfterLast(args[i], '-')) { + case "group": + request.setGroup(value); + break; + case "version": + request.setVersion(value); + break; + case "tag": + request.setTag(StringUtils.tokenize(value)); + break; + case "service": + request.setService(StringUtils.tokenize(value)); + break; + case "openapi": + request.setOpenapi(value); + break; + case "format": + request.setFormat(value); + break; + default: + break; + } + } + } + } + + return openAPIService.getDocument(request); + } +} diff --git a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand index a837d2b7024..9a336915e1b 100644 --- a/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand +++ b/dubbo-plugin/dubbo-qos/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.qos.api.BaseCommand @@ -38,3 +38,4 @@ getConfig=org.apache.dubbo.qos.command.impl.GetConfig getAddress=org.apache.dubbo.qos.command.impl.GetAddress gracefulShutdown=org.apache.dubbo.qos.command.impl.GracefulShutdown metrics_default=org.apache.dubbo.qos.command.impl.DefaultMetricsReporterCmd +getOpenAPI=org.apache.dubbo.qos.command.impl.GetOpenAPI diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java index b2443ec9bfb..238b1421dd0 100644 --- a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/command/util/CommandHelperTest.java @@ -29,6 +29,7 @@ import org.apache.dubbo.qos.command.impl.GetAddress; import org.apache.dubbo.qos.command.impl.GetConfig; import org.apache.dubbo.qos.command.impl.GetEnabledRouterSnapshot; +import org.apache.dubbo.qos.command.impl.GetOpenAPI; import org.apache.dubbo.qos.command.impl.GetRecentRouterSnapshot; import org.apache.dubbo.qos.command.impl.GetRouterSnapshot; import org.apache.dubbo.qos.command.impl.GracefulShutdown; @@ -127,6 +128,7 @@ void testGetAllCommandClass() { expectedClasses.add(GetAddress.class); expectedClasses.add(GracefulShutdown.class); expectedClasses.add(DefaultMetricsReporterCmd.class); + expectedClasses.add(GetOpenAPI.class); assertThat(classes, containsInAnyOrder(expectedClasses.toArray(new Class[0]))); } diff --git a/dubbo-plugin/dubbo-rest-jaxrs/pom.xml b/dubbo-plugin/dubbo-rest-jaxrs/pom.xml index fcfc57ba658..4f9f31e70d5 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/pom.xml +++ b/dubbo-plugin/dubbo-rest-jaxrs/pom.xml @@ -74,6 +74,11 @@ test-jar test
+ + com.google.protobuf + protobuf-java-util + test + org.spockframework spock-core diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRequestMappingResolver.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRequestMappingResolver.java index acf619d7b2a..e2ee07c12e9 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRequestMappingResolver.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRequestMappingResolver.java @@ -17,6 +17,7 @@ package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs; import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.config.nested.RestConfig; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.cors.CorsUtils; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; @@ -32,12 +33,11 @@ @Activate(onClass = {"javax.ws.rs.Path", "javax.ws.rs.container.ContainerRequestContext"}) public class JaxrsRequestMappingResolver implements RequestMappingResolver { - private final FrameworkModel frameworkModel; private final RestToolKit toolKit; + private RestConfig restConfig; private CorsMeta globalCorsMeta; public JaxrsRequestMappingResolver(FrameworkModel frameworkModel) { - this.frameworkModel = frameworkModel; toolKit = new JaxrsRestToolKit(frameworkModel); } @@ -46,6 +46,11 @@ public RestToolKit getRestToolKit() { return toolKit; } + @Override + public void setRestConfig(RestConfig restConfig) { + this.restConfig = restConfig; + } + @Override public RequestMapping resolve(ServiceMeta serviceMeta) { AnnotationMeta path = serviceMeta.findAnnotation(Annotations.Path); @@ -70,7 +75,7 @@ public RequestMapping resolve(MethodMeta methodMeta) { } ServiceMeta serviceMeta = methodMeta.getServiceMeta(); if (globalCorsMeta == null) { - globalCorsMeta = CorsUtils.getGlobalCorsMeta(frameworkModel); + globalCorsMeta = CorsUtils.getGlobalCorsMeta(restConfig); } return builder(methodMeta, path, httpMethod) .name(methodMeta.getMethod().getName()) diff --git a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/ParamConverterFactory.java b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/ParamConverterFactory.java index 15cf8dc36c6..f9686a3e586 100644 --- a/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/ParamConverterFactory.java +++ b/dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/ParamConverterFactory.java @@ -16,7 +16,6 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.support.jaxrs; -import org.apache.dubbo.common.lang.Nullable; import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.utils.CollectionUtils; @@ -54,7 +53,6 @@ final class ParamConverterFactory { } } - @Nullable @SuppressWarnings("unchecked") public ParamConverter getParamConverter(Class type, Type genericType, Annotation[] annotations) { if (providers.isEmpty()) { diff --git a/dubbo-plugin/dubbo-rest-swagger/pom.xml b/dubbo-plugin/dubbo-rest-openapi/pom.xml similarity index 98% rename from dubbo-plugin/dubbo-rest-swagger/pom.xml rename to dubbo-plugin/dubbo-rest-openapi/pom.xml index 472b75feda6..f3199369f92 100644 --- a/dubbo-plugin/dubbo-rest-swagger/pom.xml +++ b/dubbo-plugin/dubbo-rest-openapi/pom.xml @@ -24,7 +24,7 @@ ../../pom.xml - dubbo-rest-swagger + dubbo-rest-openapi 2.2.25 diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/AbstractContext.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java similarity index 96% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java index 9d8a54687f1..8786e334fb8 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ConfigFactory.java @@ -44,11 +44,6 @@ public ConfigFactory(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; } - public static boolean isOpenAPIEnabled(FrameworkModel frameworkModel) { - Environment environment = getEnvironment(frameworkModel); - return environment.getConfiguration().getBoolean(H2_SETTINGS_OPENAPI_PREFIX + ".enabled", false); - } - private static Environment getEnvironment(FrameworkModel frameworkModel) { return frameworkModel.defaultApplication().modelEnvironment(); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Constants.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Context.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ContextImpl.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPINamingStrategy.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java similarity index 97% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java index a7c4538fc5d..a991562a957 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefaultOpenAPIService.java @@ -28,6 +28,7 @@ import org.apache.dubbo.remoting.http12.exception.HttpResultPayloadException; import org.apache.dubbo.remoting.http12.message.MediaType; import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.ExceptionUtils; @@ -72,7 +73,6 @@ public class DefaultOpenAPIService implements OpenAPIRequestHandler, OpenAPIServ private final DefinitionFilter definitionFilter; private final DefinitionEncoder definitionEncoder; private final RadixTree tree; - private RequestMappingRegistry requestMappingRegistry; private volatile List openAPIs; private boolean exported; @@ -89,10 +89,6 @@ public DefaultOpenAPIService(FrameworkModel frameworkModel) { tree = initRequestHandlers(); } - public void setRequestMappingRegistry(RequestMappingRegistry requestMappingRegistry) { - this.requestMappingRegistry = requestMappingRegistry; - } - private RadixTree initRequestHandlers() { RadixTree tree = new RadixTree<>(false); for (OpenAPIRequestHandler handler : extensionFactory.getExtensions(OpenAPIRequestHandler.class)) { @@ -133,7 +129,6 @@ public Collection getOpenAPIGroups() { return groups; } - @Override public OpenAPI getOpenAPI(OpenAPIRequest request) { return definitionFilter.filter(definitionMerger.merge(getOpenAPIs(), request), request); } @@ -150,8 +145,13 @@ private List getOpenAPIs() { } private List resolveOpenAPIs() { + RequestMappingRegistry registry = frameworkModel.getBean(RequestMappingRegistry.class); + if (registry == null) { + return Collections.emptyList(); + } + Map>> byClassMap = new HashMap<>(); - for (Registration registration : requestMappingRegistry.getRegistrations()) { + for (Registration registration : registry.getRegistrations()) { HandlerMeta meta = registration.getMeta(); byClassMap .computeIfAbsent(new Key(meta.getService()), k -> new IdentityHashMap<>()) diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionEncoder.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionFilter.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java similarity index 98% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index f8be87a0165..e2814aed4fb 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -415,8 +415,12 @@ private void mergeTags(OpenAPI target, OpenAPI source) { } private void addSchemas(OpenAPI target, String version, String group) { + Map paths = target.getPaths(); + if (paths == null) { + return; + } Map schemas = new IdentityHashMap<>(); - for (PathItem pathItem : target.getPaths().values()) { + for (PathItem pathItem : paths.values()) { Map operations = pathItem.getOperations(); if (operations == null) { continue; @@ -624,6 +628,9 @@ private void completeModel(OpenAPI target) { if (info.getVersion() == null) { info.setVersion("v1"); } + if (CollectionUtils.isEmptyMap(target.getPaths())) { + return; + } ExternalDocs docs = target.getExternalDocs(); if (docs.getUrl() == null && docs.getDescription() == null) { docs.setUrl("../redoc/index.html?group=" + target.getGroup()).setDescription("ReDoc"); diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ExtensionFactory.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java similarity index 93% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java index 729b3205d07..1a17514acad 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/Helper.java @@ -33,7 +33,10 @@ import java.util.List; import java.util.Map; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.apache.dubbo.remoting.http12.HttpMethods.DELETE; import static org.apache.dubbo.remoting.http12.HttpMethods.GET; @@ -75,6 +78,8 @@ public final class Helper { {DELETE.name(), "delete", "remove", "erase", "destroy", "drop"} }; + private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{\\{([\\w.-]+)}}"); + private Helper() {} public static Collection guessHttpMethod(MethodMeta method) { @@ -170,7 +175,7 @@ public static OpenAPIRequest formatRequest(OpenAPIRequest request) { } request.setService(service); - request.setVersion(trim(request.getVersion())); + request.setOpenapi(trim(request.getOpenapi())); request.setFormat(trim(request.getFormat())); return request; } @@ -326,4 +331,18 @@ public static boolean isVersionGreaterOrEqual(String version1, String version2) } return true; } + + public static String render(String text, Function fn) { + if (text == null) { + return null; + } + Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); + StringBuffer result = new StringBuffer(text.length()); + while (matcher.find()) { + String value = fn.apply(matcher.group(1)); + matcher.appendReplacement(result, value == null ? StringUtils.EMPTY_STRING : value); + } + matcher.appendTail(result); + return result.toString(); + } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDocumentPublisher.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIExtension.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIFilter.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPINamingStrategy.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIRequestHandler.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaPredicate.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPISchemaResolver.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/PrimitiveSchema.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/ProtoEncoder.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/SchemaResolver.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ApiResponse.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Components.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Contact.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Discriminator.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Encoding.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Example.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ExternalDocs.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Header.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Info.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/License.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/MediaType.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlow.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OAuthFlows.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/OpenAPI.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Operation.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Parameter.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/PathItem.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/RequestBody.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Schema.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityRequirement.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/SecurityScheme.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Server.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/ServerVariable.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Tag.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/XML.java diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java similarity index 100% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java similarity index 100% rename from dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java similarity index 98% rename from dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java index 0469ab8e202..3407a94bab4 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/RedocRequestHandler.java @@ -28,6 +28,7 @@ import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ConfigFactory; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Constants; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequestHandler; import org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java similarity index 100% rename from dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java similarity index 93% rename from dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java index 67cd6f25652..37010f92fe6 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java @@ -26,10 +26,11 @@ import org.apache.dubbo.remoting.http12.HttpResult; import org.apache.dubbo.remoting.http12.HttpStatus; import org.apache.dubbo.remoting.http12.exception.HttpStatusException; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ConfigFactory; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.Helper; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIRequestHandler; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIService; import org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils; import org.apache.dubbo.rpc.protocol.tri.rest.util.RequestUtils; @@ -131,7 +132,11 @@ private HttpResult handleIndex() { } private HttpResult handleSwaggerConfig() { - Collection groups = frameworkModel.getBean(OpenAPIService.class).getOpenAPIGroups(); + OpenAPIService openAPIService = frameworkModel.getDefaultExtensionOrNull(OpenAPIService.class); + if (openAPIService == null) { + return HttpResult.notFound(); + } + Collection groups = openAPIService.getOpenAPIGroups(); List> urls = new ArrayList<>(); for (String group : groups) { Map url = new LinkedHashMap<>(4); diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java similarity index 100% rename from dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java rename to dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/WebjarHelper.java diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService new file mode 100644 index 00000000000..b98343397d1 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService @@ -0,0 +1 @@ +default=org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPIService diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension similarity index 66% rename from dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension rename to dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension index 68c769ce618..74eb520bcad 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension @@ -1,4 +1,6 @@ +resolver-basic=org.apache.dubbo.rpc.protocol.tri.rest.support.basic.BasicOpenAPIDefinitionResolver resolver-swagger=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerOpenAPIDefinitionResolver resolver-javadoc=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.JavadocOpenAPIDefinitionResolver +naming-strategy-default=org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPINamingStrategy handler-swagger-ui=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.SwaggerUIRequestHandler handler-redoc=org.apache.dubbo.rpc.protocol.tri.rest.support.swagger.RedocRequestHandler diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/redoc/index.html b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/redoc/index.html similarity index 84% rename from dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/redoc/index.html rename to dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/redoc/index.html index 7fa9aab01d5..68fd09cef73 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/redoc/index.html +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/redoc/index.html @@ -1,3 +1,4 @@ + diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/swagger-ui/index.html b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/swagger-ui/index.html similarity index 93% rename from dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/swagger-ui/index.html rename to dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/swagger-ui/index.html index e0675341b44..bf226824c91 100644 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/resources/META-INF/resources/swagger-ui/index.html +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/resources/swagger-ui/index.html @@ -1,3 +1,4 @@ + diff --git a/dubbo-plugin/dubbo-rest-spring/pom.xml b/dubbo-plugin/dubbo-rest-spring/pom.xml index 86f9ed0ab2e..16619482aa1 100644 --- a/dubbo-plugin/dubbo-rest-spring/pom.xml +++ b/dubbo-plugin/dubbo-rest-spring/pom.xml @@ -83,6 +83,11 @@ test-jar test + + com.google.protobuf + protobuf-java-util + test + org.spockframework spock-core diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringMvcRequestMappingResolver.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringMvcRequestMappingResolver.java index 428f4f9d18f..b80de0d00a2 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringMvcRequestMappingResolver.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringMvcRequestMappingResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.RestConfig; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.cors.CorsUtils; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; @@ -35,15 +36,19 @@ @Activate(onClass = "org.springframework.web.bind.annotation.RequestMapping") public class SpringMvcRequestMappingResolver implements RequestMappingResolver { - private final FrameworkModel frameworkModel; private final RestToolKit toolKit; + private RestConfig restConfig; private CorsMeta globalCorsMeta; public SpringMvcRequestMappingResolver(FrameworkModel frameworkModel) { - this.frameworkModel = frameworkModel; toolKit = new SpringRestToolKit(frameworkModel); } + @Override + public void setRestConfig(RestConfig restConfig) { + this.restConfig = restConfig; + } + @Override public RestToolKit getRestToolKit() { return toolKit; @@ -125,7 +130,7 @@ private Builder builder( private CorsMeta buildCorsMeta(AnnotationMeta crossOrigin, String[] methods) { if (globalCorsMeta == null) { - globalCorsMeta = CorsUtils.getGlobalCorsMeta(frameworkModel); + globalCorsMeta = CorsUtils.getGlobalCorsMeta(restConfig); } if (crossOrigin == null) { return globalCorsMeta; diff --git a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java index e544ba083f4..38b20df5459 100644 --- a/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java +++ b/dubbo-plugin/dubbo-rest-spring/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/spring/SpringRestToolKit.java @@ -38,8 +38,6 @@ import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestUtils; -import javax.annotation.Nullable; - import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; @@ -166,7 +164,6 @@ public String[] getParameterNames(Method method) { return parameterNameReader.readParameterNames(method); } - @Nullable @Override public String[] getParameterNames(Constructor ctor) { return parameterNameReader.readParameterNames(ctor); diff --git a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/Helper.java b/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/Helper.java deleted file mode 100644 index 766029b71c6..00000000000 --- a/dubbo-plugin/dubbo-rest-swagger/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/Helper.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.protocol.tri.rest.support.swagger; - -import org.apache.dubbo.common.utils.StringUtils; - -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -final class Helper { - - private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\{\\{([\\w.-]+)}}"); - - private Helper() {} - - public static String render(String text, Function fn) { - if (text == null) { - return null; - } - Matcher matcher = PLACEHOLDER_PATTERN.matcher(text); - StringBuffer result = new StringBuffer(text.length()); - while (matcher.find()) { - String value = fn.apply(matcher.group(1)); - matcher.appendReplacement(result, value == null ? StringUtils.EMPTY_STRING : value); - } - matcher.appendTail(result); - return result.toString(); - } -} diff --git a/dubbo-plugin/dubbo-triple-websocket/pom.xml b/dubbo-plugin/dubbo-triple-websocket/pom.xml index 6c7533f6508..447074ccc97 100644 --- a/dubbo-plugin/dubbo-triple-websocket/pom.xml +++ b/dubbo-plugin/dubbo-triple-websocket/pom.xml @@ -38,6 +38,11 @@ dubbo-rpc-triple ${project.version} + + org.apache.dubbo + dubbo-remoting-websocket + ${project.parent.version} + javax.servlet javax.servlet-api diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java index ab3ba7cec0a..c69fdeb9ef3 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java @@ -29,8 +29,9 @@ import org.apache.dubbo.remoting.http12.HttpStatus; import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIService; +import org.apache.dubbo.rpc.protocol.tri.TripleProtocol; import java.util.ArrayList; import java.util.Comparator; @@ -220,11 +221,15 @@ public String getAndListenInstanceMetadata(String consumerId, InstanceMetadataCh @Override public String getOpenAPI(OpenAPIRequest request) { - OpenAPIService openAPIService = applicationModel.getBean(OpenAPIService.class); - if (openAPIService == null) { - throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode(), "OpenAPI is not available"); + if (TripleProtocol.OPENAPI_ENABLED) { + OpenAPIService openAPIService = + applicationModel.getFrameworkModel().getDefaultExtensionOrNull(OpenAPIService.class); + if (openAPIService != null) { + return openAPIService.getDocument(request); + } } - return openAPIService.getDocument(request); + + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode(), "OpenAPI is not available"); } private SortedSet getServiceURLs( diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java index 10878cce00d..1f8d3f2056c 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java @@ -23,9 +23,17 @@ import org.apache.dubbo.metadata.DubboMetadataServiceV2Triple.MetadataServiceV2ImplBase; import org.apache.dubbo.metadata.MetadataInfo; import org.apache.dubbo.metadata.MetadataRequest; +import org.apache.dubbo.metadata.OpenAPI; +import org.apache.dubbo.metadata.OpenAPIFormat; import org.apache.dubbo.registry.client.ServiceDiscovery; import org.apache.dubbo.registry.support.RegistryManager; +import org.apache.dubbo.remoting.http12.HttpStatus; +import org.apache.dubbo.remoting.http12.exception.HttpStatusException; +import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.protocol.tri.TripleProtocol; import static org.apache.dubbo.common.constants.LoggerCodeConstants.REGISTRY_FAILED_LOAD_METADATA; import static org.apache.dubbo.metadata.util.MetadataServiceVersionUtils.toV2; @@ -34,8 +42,7 @@ public class MetadataServiceDelegationV2 extends MetadataServiceV2ImplBase { ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(getClass()); - private final ApplicationModel applicationModel; - + private final FrameworkModel frameworkModel; private final RegistryManager registryManager; private URL metadataUrl; @@ -43,8 +50,8 @@ public class MetadataServiceDelegationV2 extends MetadataServiceV2ImplBase { public static final String VERSION = "2.0.0"; public MetadataServiceDelegationV2(ApplicationModel applicationModel) { - this.applicationModel = applicationModel; - this.registryManager = RegistryManager.getInstance(applicationModel); + frameworkModel = applicationModel.getFrameworkModel(); + registryManager = RegistryManager.getInstance(applicationModel); } @Override @@ -70,6 +77,32 @@ public org.apache.dubbo.metadata.MetadataInfoV2 getMetadataInfo(MetadataRequest return null; } + @Override + public OpenAPI getOpenAPI(org.apache.dubbo.metadata.OpenAPIRequest request) { + if (TripleProtocol.OPENAPI_ENABLED) { + OpenAPIService openAPIService = frameworkModel.getDefaultExtensionOrNull(OpenAPIService.class); + if (openAPIService != null) { + OpenAPIRequest oRequest = new OpenAPIRequest(); + oRequest.setGroup(request.getGroup()); + oRequest.setVersion(request.getVersion()); + oRequest.setTag(request.getTagList().toArray(StringUtils.EMPTY_STRING_ARRAY)); + oRequest.setService(request.getServiceList().toArray(StringUtils.EMPTY_STRING_ARRAY)); + oRequest.setOpenapi(request.getOpenapi()); + OpenAPIFormat format = request.getFormat(); + if (request.hasFormat()) { + oRequest.setFormat(format.name()); + } + if (request.hasPretty()) { + oRequest.setPretty(request.getPretty()); + } + String document = openAPIService.getDocument(oRequest); + return OpenAPI.newBuilder().setValue(document).build(); + } + } + + throw new HttpStatusException(HttpStatus.NOT_FOUND.getCode(), "OpenAPI is not available"); + } + public URL getMetadataUrl() { return metadataUrl; } diff --git a/dubbo-remoting/dubbo-remoting-http12/pom.xml b/dubbo-remoting/dubbo-remoting-http12/pom.xml index c81f5ae601a..4d16603471c 100644 --- a/dubbo-remoting/dubbo-remoting-http12/pom.xml +++ b/dubbo-remoting/dubbo-remoting-http12/pom.xml @@ -46,10 +46,6 @@ dubbo-remoting-api ${project.parent.version} - - com.google.protobuf - protobuf-java-util - io.netty @@ -60,6 +56,12 @@ netty-codec-http2 + + com.google.protobuf + protobuf-java-util + provided + + javax.xml.bind jaxb-api diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIService.java similarity index 77% rename from dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java rename to dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIService.java index 01d9d97d612..18b4ac45d7b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIService.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIService.java @@ -14,19 +14,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +package org.apache.dubbo.remoting.http12.rest; -import org.apache.dubbo.remoting.http12.rest.OpenAPIRequest; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; +import org.apache.dubbo.common.constants.CommonConstants; +import org.apache.dubbo.common.extension.ExtensionScope; +import org.apache.dubbo.common.extension.SPI; import java.util.Collection; +@SPI(value = CommonConstants.DEFAULT_KEY, scope = ExtensionScope.FRAMEWORK) public interface OpenAPIService { Collection getOpenAPIGroups(); - OpenAPI getOpenAPI(OpenAPIRequest request); - String getDocument(OpenAPIRequest request); void refresh(); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java index 7abc0aa40a6..bf64a3578f4 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/Constants.java @@ -113,6 +113,8 @@ public interface Constants { String H2_SETTINGS_OPENAPI_PREFIX = "dubbo.protocol.triple.rest.openapi"; String H2_SETTINGS_VERBOSE_ENABLED = "dubbo.protocol.triple.verbose"; + String H2_SETTINGS_REST_ENABLED = "dubbo.protocol.triple.rest.enabled"; + String H2_SETTINGS_OPENAPI_ENABLED = "dubbo.protocol.triple.rest.openapi.enabled"; String H2_SETTINGS_SERVLET_ENABLED = "dubbo.protocol.triple.servlet.enabled"; String H3_SETTINGS_HTTP3_ENABLED = "dubbo.protocol.triple.http3.enabled"; String H3_SETTINGS_HTTP3_NEGOTIATION = "dubbo.protocol.triple.http3.negotiation"; diff --git a/dubbo-rpc/dubbo-rpc-triple/pom.xml b/dubbo-rpc/dubbo-rpc-triple/pom.xml index a516e70137f..1b4bebf035c 100644 --- a/dubbo-rpc/dubbo-rpc-triple/pom.xml +++ b/dubbo-rpc/dubbo-rpc-triple/pom.xml @@ -51,6 +51,7 @@ org.apache.dubbo dubbo-remoting-websocket ${project.parent.version} + true org.apache.dubbo @@ -60,23 +61,36 @@ org.apache.dubbo - dubbo-cluster + dubbo-native ${project.parent.version} - test - io.netty - netty-codec-http2 + com.google.protobuf + protobuf-java-util + true - com.google.protobuf - protobuf-java + org.apache.commons + commons-compress + true + + org.xerial.snappy + snappy-java + true + + org.springframework spring-test test + + org.apache.dubbo + dubbo-cluster + ${project.parent.version} + test + org.apache.dubbo dubbo-serialization-hessian2 @@ -94,19 +108,11 @@ log4j-slf4j-impl test - - org.apache.commons - commons-compress - io.reactivex.rxjava2 rxjava test - - org.xerial.snappy - snappy-java - io.projectreactor reactor-core @@ -117,18 +123,6 @@ spock-core test - - org.apache.dubbo - dubbo-native - ${project.parent.version} - - - - org.apache.dubbo - dubbo-compiler - ${project.parent.version} - provided -
diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java index f3e53b25980..19412dd0109 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleProtocol.java @@ -50,7 +50,9 @@ import static org.apache.dubbo.config.Constants.CLIENT_THREAD_POOL_NAME; import static org.apache.dubbo.config.Constants.SERVER_THREAD_POOL_NAME; import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_IGNORE_1_0_0_KEY; +import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_OPENAPI_ENABLED; import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_RESOLVE_FALLBACK_TO_DEFAULT_KEY; +import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_REST_ENABLED; import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_SUPPORT_NO_LOWER_HEADER_KEY; import static org.apache.dubbo.rpc.Constants.H2_SETTINGS_VERBOSE_ENABLED; @@ -65,6 +67,8 @@ public class TripleProtocol extends AbstractProtocol { public static boolean IGNORE_1_0_0_VERSION = false; public static boolean RESOLVE_FALLBACK_TO_DEFAULT = true; public static boolean VERBOSE_ENABLED = false; + public static boolean REST_ENABLED = true; + public static boolean OPENAPI_ENABLED = false; public TripleProtocol(FrameworkModel frameworkModel) { this.frameworkModel = frameworkModel; @@ -82,6 +86,9 @@ public TripleProtocol(FrameworkModel frameworkModel) { // init global settings Configuration globalConf = ConfigurationUtils.getGlobalConfiguration(frameworkModel.defaultApplication()); VERBOSE_ENABLED = globalConf.getBoolean(H2_SETTINGS_VERBOSE_ENABLED, false); + REST_ENABLED = globalConf.getBoolean(H2_SETTINGS_REST_ENABLED, true); + OPENAPI_ENABLED = globalConf.getBoolean(H2_SETTINGS_OPENAPI_ENABLED, false); + ServletExchanger.init(globalConf); Http3Exchanger.init(globalConf); } @@ -104,7 +111,9 @@ public void afterUnExport() { pathResolver.unregister(invoker); // unregister rest request mapping - mappingRegistry.unregister(invoker); + if (REST_ENABLED) { + mappingRegistry.unregister(invoker); + } // set service status to NOT_SERVING setServiceStatus(url, false); @@ -121,7 +130,9 @@ public void afterUnExport() { pathResolver.register(invoker); // register rest request mapping - mappingRegistry.register(invoker); + if (REST_ENABLED) { + mappingRegistry.register(invoker); + } // set service status to SERVING setServiceStatus(url, true); @@ -205,7 +216,9 @@ public void destroy() { PortUnificationExchanger.close(); Http3Exchanger.close(); pathResolver.destroy(); - mappingRegistry.destroy(); + if (REST_ENABLED) { + mappingRegistry.destroy(); + } super.destroy(); } } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/cors/CorsUtils.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/cors/CorsUtils.java index a71cf9ec00e..b6f31cc0984 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/cors/CorsUtils.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/cors/CorsUtils.java @@ -16,23 +16,16 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.cors; -import org.apache.dubbo.common.config.Configuration; -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.utils.StringUtils; -import org.apache.dubbo.config.context.ConfigManager; import org.apache.dubbo.config.nested.CorsConfig; -import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.config.nested.RestConfig; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.CorsMeta; public class CorsUtils { private CorsUtils() {} - public static CorsMeta getGlobalCorsMeta(FrameworkModel frameworkModel) { - CorsConfig config = ConfigManager.getProtocolOrDefault(CommonConstants.TRIPLE) - .getTripleOrDefault() - .getRestOrDefault() - .getCorsOrDefault(); + public static CorsMeta getGlobalCorsMeta(RestConfig restConfig) { + CorsConfig config = restConfig.getCorsOrDefault(); return CorsMeta.builder() .allowedOrigins(config.getAllowedOrigins()) .allowedMethods(config.getAllowedMethods()) @@ -43,10 +36,6 @@ public static CorsMeta getGlobalCorsMeta(FrameworkModel frameworkModel) { .build(); } - private static String[] getValues(Configuration config, String key) { - return StringUtils.tokenize(config.getString(key), ','); - } - public static String formatOrigin(String value) { value = value.trim(); int last = value.length() - 1; diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java index 30b3ca199e1..6535f827399 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java @@ -24,6 +24,7 @@ import org.apache.dubbo.remoting.http12.HttpRequest; import org.apache.dubbo.remoting.http12.exception.HttpStatusException; import org.apache.dubbo.remoting.http12.message.MethodMetadata; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.model.MethodDescriptor; @@ -31,6 +32,7 @@ import org.apache.dubbo.rpc.model.ReflectionServiceDescriptor; import org.apache.dubbo.rpc.model.ServiceDescriptor; import org.apache.dubbo.rpc.protocol.tri.DescriptorUtils; +import org.apache.dubbo.rpc.protocol.tri.TripleProtocol; import org.apache.dubbo.rpc.protocol.tri.rest.Messages; import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants; import org.apache.dubbo.rpc.protocol.tri.rest.RestMappingException; @@ -40,8 +42,6 @@ import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.HandlerMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.ConfigFactory; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPIService; import org.apache.dubbo.rpc.protocol.tri.rest.util.KeyString; import org.apache.dubbo.rpc.protocol.tri.rest.util.MethodWalker; import org.apache.dubbo.rpc.protocol.tri.rest.util.PathUtils; @@ -67,7 +67,7 @@ public final class DefaultRequestMappingRegistry implements RequestMappingRegist private final AtomicBoolean initialized = new AtomicBoolean(); private ContentNegotiator contentNegotiator; - private DefaultOpenAPIService openAPIService; + private OpenAPIService openAPIService; private List resolvers; private RestConfig restConfig; private RadixTree tree; @@ -78,14 +78,16 @@ public DefaultRequestMappingRegistry(FrameworkModel frameworkModel) { private void init(Invoker invoker) { contentNegotiator = frameworkModel.getOrRegisterBean(ContentNegotiator.class); - if (ConfigFactory.isOpenAPIEnabled(frameworkModel)) { - openAPIService = frameworkModel.getOrRegisterBean(DefaultOpenAPIService.class); - openAPIService.setRequestMappingRegistry(this); + if (TripleProtocol.OPENAPI_ENABLED) { + openAPIService = frameworkModel.getDefaultExtensionOrNull(OpenAPIService.class); } resolvers = frameworkModel.getActivateExtensions(RequestMappingResolver.class); restConfig = ConfigManager.getProtocolOrDefault(invoker.getUrl()) .getTripleOrDefault() .getRestOrDefault(); + for (RequestMappingResolver resolver : resolvers) { + resolver.setRestConfig(restConfig); + } tree = new RadixTree<>(restConfig.getCaseSensitiveMatchOrDefault()); } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingResolver.java index 803792f1a4d..25e34620b0b 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/RequestMappingResolver.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.extension.ExtensionScope; import org.apache.dubbo.common.extension.SPI; +import org.apache.dubbo.config.nested.RestConfig; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit; @@ -27,6 +28,8 @@ public interface RequestMappingResolver { RestToolKit getRestToolKit(); + default void setRestConfig(RestConfig restConfig) {} + default boolean accept(ServiceMeta serviceMeta) { return true; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java index bddaadefc9a..533d2b155d4 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicRequestMappingResolver.java @@ -18,6 +18,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.config.nested.RestConfig; import org.apache.dubbo.remoting.http12.rest.Mapping; import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.protocol.tri.rest.cors.CorsUtils; @@ -36,12 +37,11 @@ @Activate public class BasicRequestMappingResolver implements RequestMappingResolver { - private final FrameworkModel frameworkModel; private final RestToolKit toolKit; + private RestConfig restConfig; private CorsMeta globalCorsMeta; public BasicRequestMappingResolver(FrameworkModel frameworkModel) { - this.frameworkModel = frameworkModel; toolKit = new BasicRestToolKit(frameworkModel); } @@ -50,6 +50,11 @@ public RestToolKit getRestToolKit() { return toolKit; } + @Override + public void setRestConfig(RestConfig restConfig) { + this.restConfig = restConfig; + } + @Override public boolean accept(MethodMeta methodMeta) { AnnotationMeta mapping = methodMeta.findAnnotation(Mapping.class); @@ -77,8 +82,15 @@ public RequestMapping resolve(ServiceMeta serviceMeta) { public RequestMapping resolve(MethodMeta methodMeta) { Method method = methodMeta.getMethod(); AnnotationMeta mapping = methodMeta.findAnnotation(Mapping.class); - if (mapping != null && !mapping.getAnnotation().enabled()) { - return null; + if (mapping != null) { + if (!mapping.getAnnotation().enabled()) { + return null; + } + } else { + Boolean enabled = restConfig.getEnableDefaultMapping(); + if (enabled != null && !enabled) { + return null; + } } Builder builder = builder(mapping); @@ -92,7 +104,7 @@ public RequestMapping resolve(MethodMeta methodMeta) { ServiceMeta serviceMeta = methodMeta.getServiceMeta(); if (globalCorsMeta == null) { - globalCorsMeta = CorsUtils.getGlobalCorsMeta(frameworkModel); + globalCorsMeta = CorsUtils.getGlobalCorsMeta(restConfig); } return builder.name(method.getName()) .service(serviceMeta.getServiceGroup(), serviceMeta.getServiceVersion()) diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension deleted file mode 100644 index c2f29afc12b..00000000000 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension +++ /dev/null @@ -1,2 +0,0 @@ -resolver-basic=org.apache.dubbo.rpc.protocol.tri.rest.support.basic.BasicOpenAPIDefinitionResolver -naming-strategy-default=org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPINamingStrategy diff --git a/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java index 73a0f347a6e..511aeadcfd2 100644 --- a/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java @@ -17,8 +17,8 @@ package org.apache.dubbo.spring.boot.context.event; import org.apache.dubbo.config.spring.util.DubboBeanUtils; +import org.apache.dubbo.remoting.http12.rest.OpenAPIService; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIService; import java.util.concurrent.atomic.AtomicBoolean; @@ -41,7 +41,11 @@ public void onApplicationEvent(ApplicationReadyEvent event) { return; } ApplicationModel applicationModel = DubboBeanUtils.getApplicationModel(event.getApplicationContext()); - OpenAPIService openAPIService = applicationModel.getBean(OpenAPIService.class); + if (applicationModel == null) { + return; + } + OpenAPIService openAPIService = + applicationModel.getFrameworkModel().getDefaultExtensionOrNull(OpenAPIService.class); if (openAPIService != null) { openAPIService.export(); } diff --git a/dubbo-test/dubbo-dependencies-all/pom.xml b/dubbo-test/dubbo-dependencies-all/pom.xml index 554c6cb50a1..69889f8f9aa 100644 --- a/dubbo-test/dubbo-dependencies-all/pom.xml +++ b/dubbo-test/dubbo-dependencies-all/pom.xml @@ -253,7 +253,7 @@ org.apache.dubbo - dubbo-rest-swagger + dubbo-rest-openapi ${project.version} diff --git a/pom.xml b/pom.xml index 6fc69afbfd0..c0bebb4e4a2 100644 --- a/pom.xml +++ b/pom.xml @@ -106,7 +106,7 @@ dubbo-plugin/dubbo-filter-validation dubbo-plugin/dubbo-rest-jaxrs dubbo-plugin/dubbo-rest-spring - dubbo-plugin/dubbo-rest-swagger + dubbo-plugin/dubbo-rest-openapi dubbo-plugin/dubbo-triple-servlet dubbo-plugin/dubbo-triple-websocket dubbo-demo/dubbo-demo-api From e47aff3eca969d340e9d07726f9a1fae0154f8be Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Sun, 1 Dec 2024 17:34:49 +0800 Subject: [PATCH 21/23] Refine bean get --- .../cluster/ClusterScopeModelInitializer.java | 5 +- ...MergeableClusterScopeModelInitializer.java | 7 - .../mesh/MeshScopeModelInitializer.java | 7 - .../beans/factory/ScopeBeanFactory.java | 127 +++++++++++++++--- .../common/extension/ExtensionAccessor.java | 8 -- .../dubbo/common/resource/Initializable.java | 31 +++++ .../rpc/model/ScopeModelInitializer.java | 6 +- dubbo-distribution/dubbo-all-shaded/pom.xml | 3 - dubbo-distribution/dubbo-all/pom.xml | 3 - dubbo-distribution/dubbo-core-spi/pom.xml | 3 - .../report/MetadataScopeModelInitializer.java | 7 - .../metrics/MetricsScopeModelInitializer.java | 8 -- .../dubbo/qos/QosScopeModelInitializer.java | 5 +- .../dubbo/qos/command/impl/GetOpenAPI.java | 2 +- .../tri/rest/openapi/DefinitionResolver.java | 85 +++++++----- .../openapi/OpenAPIDefinitionResolver.java | 6 + .../openapi/OpenAPIScopeModelInitializer.java | 30 +++++ .../basic/BasicOpenAPIDefinitionResolver.java | 21 ++- .../JavadocOpenAPIDefinitionResolver.java | 24 +++- .../SwaggerOpenAPIDefinitionResolver.java | 17 +++ .../swagger/SwaggerUIRequestHandler.java | 2 +- ....dubbo.remoting.http12.rest.OpenAPIService | 1 - ...ache.dubbo.rpc.model.ScopeModelInitializer | 1 + .../model/SecurityScopeModelInitializer.java | 8 -- .../RegistryScopeModelInitializer.java | 5 +- .../metadata/MetadataServiceDelegation.java | 3 +- .../metadata/MetadataServiceDelegationV2.java | 2 +- .../remoting/http12/rest/OpenAPIService.java | 5 - .../rpc/AdaptiveScopeModelInitializer.java | 7 - .../dubbo/rpc/RpcScopeModelInitializer.java | 9 +- .../DefaultRequestMappingRegistry.java | 2 +- .../tri/rest/mapping/meta/BeanMeta.java | 17 +++ .../SerializationScopeModelInitializer.java | 8 -- .../Fastjson2ScopeModelInitializer.java | 8 -- .../Hessian2ScopeModelInitializer.java | 8 -- .../event/DubboOpenAPIExportListener.java | 3 +- 36 files changed, 310 insertions(+), 184 deletions(-) create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/resource/Initializable.java create mode 100644 dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIScopeModelInitializer.java delete mode 100644 dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService create mode 100644 dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterScopeModelInitializer.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterScopeModelInitializer.java index fb9d23b0c3f..52548da6c0b 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterScopeModelInitializer.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ClusterScopeModelInitializer.java @@ -21,10 +21,10 @@ import org.apache.dubbo.rpc.cluster.support.ClusterUtils; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class ClusterScopeModelInitializer implements ScopeModelInitializer { + @Override public void initializeFrameworkModel(FrameworkModel frameworkModel) { ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); @@ -36,7 +36,4 @@ public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); beanFactory.registerBean(ClusterUtils.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/MergeableClusterScopeModelInitializer.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/MergeableClusterScopeModelInitializer.java index 1788e4d4ed8..288ea4a6117 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/MergeableClusterScopeModelInitializer.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/MergeableClusterScopeModelInitializer.java @@ -19,20 +19,13 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.rpc.cluster.merger.MergerFactory; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class MergeableClusterScopeModelInitializer implements ScopeModelInitializer { - @Override - public void initializeFrameworkModel(FrameworkModel frameworkModel) {} @Override public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); beanFactory.registerBean(MergerFactory.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/MeshScopeModelInitializer.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/MeshScopeModelInitializer.java index 6753f9b8e42..12bbc7dcf23 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/MeshScopeModelInitializer.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/mesh/MeshScopeModelInitializer.java @@ -18,17 +18,10 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleManager; -import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.FrameworkModel; import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class MeshScopeModelInitializer implements ScopeModelInitializer { - @Override - public void initializeFrameworkModel(FrameworkModel frameworkModel) {} - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} public void initializeModuleModel(ModuleModel moduleModel) { ScopeBeanFactory beanFactory = moduleModel.getBeanFactory(); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java index b02d4c97fe4..db766dd0607 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java @@ -24,10 +24,12 @@ import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.resource.Disposable; +import org.apache.dubbo.common.resource.Initializable; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.ConcurrentHashSet; import org.apache.dubbo.common.utils.Pair; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.common.utils.TypeUtils; import org.apache.dubbo.rpc.model.ScopeModelAccessor; import java.util.ArrayList; @@ -39,6 +41,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.Collectors; import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_DESTROY_INVOKER; @@ -55,6 +58,7 @@ public final class ScopeBeanFactory { private final List extensionPostProcessors; private final Map, AtomicInteger> beanNameIdCounterMap = CollectionUtils.newConcurrentHashMap(); private final List registeredBeanInfos = new CopyOnWriteArrayList<>(); + private final List> registeredBeanDefinitions = new CopyOnWriteArrayList<>(); private InstantiationStrategy instantiationStrategy; private final AtomicBoolean destroyed = new AtomicBoolean(); private final Set> registeredClasses = new ConcurrentHashSet<>(); @@ -79,14 +83,35 @@ private void initInstantiationStrategy() { } } - public T registerBean(Class bean) throws ScopeBeanException { - return getOrRegisterBean(null, bean); + public T registerBean(Class clazz) throws ScopeBeanException { + return getOrRegisterBean(null, clazz); } public T registerBean(String name, Class clazz) throws ScopeBeanException { return getOrRegisterBean(name, clazz); } + public void registerBeanDefinition(Class clazz) { + registerBeanDefinition(null, clazz); + } + + public void registerBeanDefinition(String name, Class clazz) { + registeredBeanDefinitions.add(new BeanDefinition<>(name, clazz)); + } + + public void registerBeanFactory(Supplier factory) { + registerBeanFactory(null, factory); + } + + @SuppressWarnings("unchecked") + public void registerBeanFactory(String name, Supplier factory) { + Class clazz = (Class) TypeUtils.getSuperGenericType(factory.getClass(), 0); + if (clazz == null) { + throw new ScopeBeanException("unable to determine bean class from factory's superclass or interface"); + } + registeredBeanDefinitions.add(new BeanDefinition<>(name, clazz, factory)); + } + private T createAndRegisterBean(String name, Class clazz) { checkDestroyed(); T instance = getBean(name, clazz); @@ -174,6 +199,9 @@ private void initializeBean(String name, Object bean) { for (ExtensionPostProcessor processor : extensionPostProcessors) { processor.postProcessAfterInitialization(bean, name); } + if (bean instanceof Initializable) { + ((Initializable) bean).initialize(extensionAccessor); + } } catch (Exception e) { throw new ScopeBeanException( "register bean failed! name=" + name + ", type=" @@ -182,9 +210,48 @@ private void initializeBean(String name, Object bean) { } } + @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") + private void initializeBeanDefinitions(Class type) { + for (int i = 0, size = registeredBeanDefinitions.size(); i < size; i++) { + BeanDefinition definition = registeredBeanDefinitions.get(i); + if (definition.initialized) { + continue; + } + + Class beanClass = definition.beanClass; + if (!type.isAssignableFrom(beanClass)) { + continue; + } + synchronized (type) { + if (definition.initialized) { + continue; + } + + Object bean; + Supplier factory = definition.beanFactory; + if (factory == null) { + try { + bean = instantiationStrategy.instantiate(beanClass); + } catch (Throwable e) { + throw new ScopeBeanException("create bean instance failed, type=" + beanClass.getName(), e); + } + } else { + initializeBean(definition.name, factory); + try { + bean = factory.get(); + } catch (Exception e) { + throw new ScopeBeanException("create bean instance failed, type=" + beanClass.getName(), e); + } + } + registerBean(definition.name, bean); + definition.initialized = true; + } + } + } + private boolean containsBean(String name, Object bean) { for (BeanInfo beanInfo : registeredBeanInfos) { - if (beanInfo.instance == bean && (name == null || StringUtils.isEquals(name, beanInfo.name))) { + if (beanInfo.instance == bean && (name == null || name.equals(beanInfo.name))) { return true; } } @@ -199,6 +266,7 @@ private int getNextId(Class beanClass) { @SuppressWarnings("unchecked") public List getBeansOfType(Class type) { + initializeBeanDefinitions(type); List currentBeans = (List) registeredBeanInfos.stream() .filter(beanInfo -> type.isInstance(beanInfo.instance)) .map(beanInfo -> beanInfo.instance) @@ -223,19 +291,23 @@ public T getBean(String name, Class type) { @SuppressWarnings("unchecked") private T getBeanFromCache(String name, Class type) { - Object value = beanCache - .computeIfAbsent(Pair.of(type, name), k -> { - try { - return Optional.ofNullable(getBeanInternal(name, type)); - } catch (ScopeBeanException e) { - return Optional.of(e); - } - }) - .orElse(null); - if (value instanceof ScopeBeanException) { - throw (ScopeBeanException) value; + Pair, String> key = Pair.of(type, name); + Optional value = beanCache.get(key); + if (value == null) { + initializeBeanDefinitions(type); + value = beanCache.computeIfAbsent(key, k -> { + try { + return Optional.ofNullable(getBeanInternal(name, type)); + } catch (ScopeBeanException e) { + return Optional.of(e); + } + }); + } + Object bean = value.orElse(null); + if (bean instanceof ScopeBeanException) { + throw (ScopeBeanException) bean; } - return (T) value; + return (T) bean; } @SuppressWarnings("unchecked") @@ -301,6 +373,7 @@ public void destroy() { } } registeredBeanInfos.clear(); + registeredBeanDefinitions.clear(); beanCache.clear(); } } @@ -315,16 +388,36 @@ private void checkDestroyed() { } } - static class BeanInfo { + static final class BeanInfo { private final String name; private final Object instance; - public BeanInfo(String name, Object instance) { + BeanInfo(String name, Object instance) { this.name = name; this.instance = instance; } } + static final class BeanDefinition { + + private final String name; + private final Class beanClass; + private final Supplier beanFactory; + private volatile boolean initialized; + + BeanDefinition(String name, Class beanClass) { + this.name = name; + this.beanClass = beanClass; + beanFactory = null; + } + + BeanDefinition(String name, Class beanClass, Supplier beanFactory) { + this.name = name; + this.beanClass = beanClass; + this.beanFactory = beanFactory; + } + } + public Set> getRegisteredClasses() { return registeredClasses; } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionAccessor.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionAccessor.java index fcfc023b131..5abade6f709 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionAccessor.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionAccessor.java @@ -46,14 +46,6 @@ default T getDefaultExtension(Class type) { return extensionLoader != null ? extensionLoader.getDefaultExtension() : null; } - default T getDefaultExtensionOrNull(Class type) { - ExtensionLoader extensionLoader = getExtensionLoader(type); - if (extensionLoader == null) { - return null; - } - return extensionLoader.getExtension(extensionLoader.getDefaultExtensionName(), true); - } - default List getActivateExtensions(Class type) { ExtensionLoader extensionLoader = getExtensionLoader(type); return extensionLoader != null ? extensionLoader.getActivateExtensions() : Collections.emptyList(); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/resource/Initializable.java b/dubbo-common/src/main/java/org/apache/dubbo/common/resource/Initializable.java new file mode 100644 index 00000000000..6ba121f88ac --- /dev/null +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/resource/Initializable.java @@ -0,0 +1,31 @@ +/* + * 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.common.resource; + +import org.apache.dubbo.common.extension.ExtensionAccessor; + +/** + * An interface for Initializing resources + */ +public interface Initializable { + + default void initialize(ExtensionAccessor accessor) { + initialize(); + } + + default void initialize() {} +} diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelInitializer.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelInitializer.java index 26c70ee0e85..ffcd867cbef 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelInitializer.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModelInitializer.java @@ -22,9 +22,9 @@ @SPI(scope = ExtensionScope.SELF) public interface ScopeModelInitializer { - void initializeFrameworkModel(FrameworkModel frameworkModel); + default void initializeFrameworkModel(FrameworkModel frameworkModel) {} - void initializeApplicationModel(ApplicationModel applicationModel); + default void initializeApplicationModel(ApplicationModel applicationModel) {} - void initializeModuleModel(ModuleModel moduleModel); + default void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-distribution/dubbo-all-shaded/pom.xml b/dubbo-distribution/dubbo-all-shaded/pom.xml index 993f681c231..a945581ddac 100644 --- a/dubbo-distribution/dubbo-all-shaded/pom.xml +++ b/dubbo-distribution/dubbo-all-shaded/pom.xml @@ -889,9 +889,6 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver - - META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService - META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension diff --git a/dubbo-distribution/dubbo-all/pom.xml b/dubbo-distribution/dubbo-all/pom.xml index b385f4a9af9..8df563097d9 100644 --- a/dubbo-distribution/dubbo-all/pom.xml +++ b/dubbo-distribution/dubbo-all/pom.xml @@ -887,9 +887,6 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver - - META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService - META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension diff --git a/dubbo-distribution/dubbo-core-spi/pom.xml b/dubbo-distribution/dubbo-core-spi/pom.xml index 691d35c0c1e..0c6c789847f 100644 --- a/dubbo-distribution/dubbo-core-spi/pom.xml +++ b/dubbo-distribution/dubbo-core-spi/pom.xml @@ -483,9 +483,6 @@ META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMappingResolver - - META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService - META-INF/dubbo/internal/org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIExtension diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataScopeModelInitializer.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataScopeModelInitializer.java index ce16b2b95fc..dc34aea41be 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataScopeModelInitializer.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataScopeModelInitializer.java @@ -18,20 +18,13 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class MetadataScopeModelInitializer implements ScopeModelInitializer { - @Override - public void initializeFrameworkModel(FrameworkModel frameworkModel) {} @Override public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); beanFactory.registerBean(MetadataReportInstance.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java index 01e174ad0b3..b398777d06b 100644 --- a/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java +++ b/dubbo-metrics/dubbo-metrics-default/src/main/java/org/apache/dubbo/metrics/MetricsScopeModelInitializer.java @@ -19,21 +19,13 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.metrics.event.MetricsDispatcher; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class MetricsScopeModelInitializer implements ScopeModelInitializer { - @Override - public void initializeFrameworkModel(FrameworkModel frameworkModel) {} - @Override public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); beanFactory.registerBean(MetricsDispatcher.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java index cf2679c36a1..0da5c8352c3 100644 --- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/QosScopeModelInitializer.java @@ -22,10 +22,10 @@ import org.apache.dubbo.qos.server.Server; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class QosScopeModelInitializer implements ScopeModelInitializer { + @Override public void initializeFrameworkModel(FrameworkModel frameworkModel) { ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); @@ -38,7 +38,4 @@ public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); beanFactory.registerBean(ActuatorCommandExecutor.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.java index e8938d0d839..8482ea06b03 100644 --- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.java +++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/GetOpenAPI.java @@ -45,7 +45,7 @@ public GetOpenAPI(FrameworkModel frameworkModel) { @Override public String execute(CommandContext commandContext, String[] args) { - OpenAPIService openAPIService = frameworkModel.getDefaultExtensionOrNull(OpenAPIService.class); + OpenAPIService openAPIService = frameworkModel.getBean(OpenAPIService.class); if (openAPIService == null) { return "OpenAPI is not available"; } diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java index e873bc00cb0..34e60c3d5d5 100644 --- a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionResolver.java @@ -30,6 +30,7 @@ import org.apache.dubbo.rpc.protocol.tri.TripleHeaderEnum; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.Registration; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.RequestMapping; +import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.MethodsCondition; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathCondition; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.condition.PathExpression; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta; @@ -56,6 +57,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; @@ -144,53 +146,61 @@ private boolean resolvePath( MethodMeta methodMeta, RequestMapping mapping, OperationContext context) { - return new OperationChainImpl(resolvers, operation -> { - for (String method : determineHttpMethods(openAPI, methodMeta, mapping, operation)) { - HttpMethods httpMethod = HttpMethods.of(method.toUpperCase()); - Operation existingOperation = pathItem.getOperation(httpMethod); - if (existingOperation == null) { - pathItem.addOperation(httpMethod, operation); - } else { - if (existingOperation.getMeta() != null) { - LOG.internalWarn( - "Operation already exists, path='{}', httpMethod='{}', method={}", - path, - method, - methodMeta); - } - continue; - } - resolveOperation(path, httpMethod, operation, openAPI, methodMeta, mapping); - } - return operation; - }) - .resolve(new Operation().setMeta(methodMeta), methodMeta, context) - != null; + Collection httpMethods = null; + for (OpenAPIDefinitionResolver resolver : resolvers) { + httpMethods = resolver.resolve(pathItem, methodMeta, context); + if (httpMethods != null) { + break; + } + } + if (httpMethods == null) { + httpMethods = new LinkedList<>(); + for (String method : determineHttpMethods(openAPI, methodMeta, mapping)) { + httpMethods.add(HttpMethods.of(method.toUpperCase())); + } + } + + boolean added = false; + for (HttpMethods httpMethod : httpMethods) { + Operation operation = new Operation().setMeta(methodMeta); + Operation existingOperation = pathItem.getOperation(httpMethod); + if (existingOperation != null && existingOperation.getMeta() != null) { + LOG.internalWarn( + "Operation already exists, path='{}', httpMethod='{}', method={}", + path, + httpMethod, + methodMeta); + continue; + } + operation = new OperationChainImpl( + resolvers, op -> resolveOperation(path, httpMethod, op, openAPI, methodMeta, mapping)) + .resolve(operation, methodMeta, context); + if (operation != null) { + pathItem.addOperation(httpMethod, operation); + added = true; + } + } + return added; } - private Collection determineHttpMethods( - OpenAPI openAPI, MethodMeta meta, RequestMapping mapping, Operation operation) { + private Collection determineHttpMethods(OpenAPI openAPI, MethodMeta meta, RequestMapping mapping) { Collection httpMethods = null; - if (operation.getHttpMethod() != null) { - httpMethods = Collections.singletonList(operation.getHttpMethod().name()); + MethodsCondition condition = mapping.getMethodsCondition(); + if (condition != null) { + httpMethods = condition.getMethods(); } if (httpMethods == null) { - if (mapping.getMethodsCondition() != null) { - httpMethods = mapping.getMethodsCondition().getMethods(); - } - if (httpMethods == null) { - String[] defaultHttpMethods = openAPI.getConfigValue(OpenAPIConfig::getDefaultHttpMethods); - if (defaultHttpMethods == null) { - httpMethods = Helper.guessHttpMethod(meta); - } else { - httpMethods = Arrays.asList(defaultHttpMethods); - } + String[] defaultHttpMethods = openAPI.getConfigValue(OpenAPIConfig::getDefaultHttpMethods); + if (defaultHttpMethods == null) { + httpMethods = Helper.guessHttpMethod(meta); + } else { + httpMethods = Arrays.asList(defaultHttpMethods); } } return httpMethods; } - private void resolveOperation( + private Operation resolveOperation( String path, HttpMethods httpMethod, Operation operation, @@ -257,6 +267,7 @@ private void resolveOperation( resolveResponse(httpStatusCode, response, openAPI, meta, mapping); } } + return operation; } private void resolveParameter(HttpMethods httpMethod, Operation operation, ParameterMeta meta, boolean traverse) { diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java index 14f55eaba3f..19a3de71605 100644 --- a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIDefinitionResolver.java @@ -16,15 +16,21 @@ */ package org.apache.dubbo.rpc.protocol.tri.rest.openapi; +import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ServiceMeta; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; + +import java.util.Collection; public interface OpenAPIDefinitionResolver extends OpenAPIExtension { OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain chain); + Collection resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context); + Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext context, OperationChain chain); interface OpenAPIChain { diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIScopeModelInitializer.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIScopeModelInitializer.java new file mode 100644 index 00000000000..2f6b7481357 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/OpenAPIScopeModelInitializer.java @@ -0,0 +1,30 @@ +/* + * 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.protocol.tri.rest.openapi; + +import org.apache.dubbo.common.extension.Activate; +import org.apache.dubbo.rpc.model.FrameworkModel; +import org.apache.dubbo.rpc.model.ScopeModelInitializer; + +@Activate +public class OpenAPIScopeModelInitializer implements ScopeModelInitializer { + + @Override + public void initializeFrameworkModel(FrameworkModel frameworkModel) { + frameworkModel.getBeanFactory().registerBeanDefinition(DefaultOpenAPIService.class); + } +} diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java index 7ec64728724..0a5dd03e42c 100644 --- a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java @@ -32,11 +32,14 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Info; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.LinkedHashSet; import java.util.Map; @@ -100,6 +103,19 @@ public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain ch return chain.resolve(openAPI, serviceMeta); } + @Override + public Collection resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context) { + AnnotationMeta annoMeta = methodMeta.findAnnotation(Annotations.Operation); + if (annoMeta == null) { + return null; + } + String method = trim(annoMeta.getString("method")); + if (method == null) { + return null; + } + return Collections.singletonList(HttpMethods.of(method.toUpperCase())); + } + @Override public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) { AnnotationMeta annoMeta = methodMeta.findAnnotation(Annotations.Operation); @@ -110,11 +126,6 @@ public Operation resolve(Operation operation, MethodMeta methodMeta, OperationCo return null; } - String method = trim(annoMeta.getString("method")); - if (method != null) { - operation.setHttpMethod(HttpMethods.of(method.toUpperCase())); - } - String[] tags = trim(annoMeta.getStringArray("tags")); if (tags != null) { operation.setTags(new LinkedHashSet<>(Arrays.asList(tags))); diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java index f8d3dc8c32a..e1c5b81712f 100644 --- a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/JavadocOpenAPIDefinitionResolver.java @@ -19,6 +19,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.utils.LRUCache; import org.apache.dubbo.common.utils.StringUtils; +import org.apache.dubbo.remoting.http12.HttpMethods; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodMeta.ReturnParameterMeta; import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.MethodParameterMeta; @@ -30,12 +31,14 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Parameter; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import java.lang.ref.WeakReference; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -82,6 +85,11 @@ public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain ch return openAPI; } + @Override + public Collection resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context) { + return null; + } + @Override public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) { operation = chain.resolve(operation, methodMeta, ctx); @@ -152,18 +160,28 @@ public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChai } else if (element instanceof Field) { Field field = (Field) element; - ClassJavadocWrapper classJavadoc = getClassJavadoc(field.getDeclaringClass()); - FieldJavadoc fieldJavadoc = classJavadoc.getField(field); + ClassJavadocWrapper javadoc = getClassJavadoc(field.getDeclaringClass()); + FieldJavadoc fieldJavadoc = javadoc.getField(field); if (fieldJavadoc != null) { comment = fieldJavadoc.getComment(); break; } - ParamJavadoc paramJavadoc = classJavadoc.getRecordComponent(field.getName()); + ParamJavadoc paramJavadoc = javadoc.getRecordComponent(field.getName()); if (paramJavadoc != null) { comment = paramJavadoc.getComment(); break; } + } else if (element instanceof Method) { + Method method = (Method) element; + + ClassJavadocWrapper javadoc = getClassJavadoc(method.getDeclaringClass()); + MethodJavadoc methodJavadoc = javadoc.getMethod(method); + + if (methodJavadoc != null) { + comment = methodJavadoc.getReturns(); + break; + } } } } diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java index e34c1c98712..c17ddd487ad 100644 --- a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java @@ -35,11 +35,14 @@ import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.License; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.OpenAPI; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Operation; +import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.PathItem; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Schema.Type; import org.apache.dubbo.rpc.protocol.tri.rest.openapi.model.Tag; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.Map; import io.swagger.v3.oas.annotations.ExternalDocumentation; @@ -136,6 +139,20 @@ private static ExternalDocs toExternalDocs(ExternalDocumentation anno) { .setExtensions(toProperties(anno.extensions())); } + @Override + public Collection resolve(PathItem pathItem, MethodMeta methodMeta, OperationContext context) { + AnnotationMeta annoMeta = + methodMeta.findAnnotation(io.swagger.v3.oas.annotations.Operation.class); + if (annoMeta == null) { + return null; + } + String method = trim(annoMeta.getAnnotation().method()); + if (method == null) { + return null; + } + return Collections.singletonList(HttpMethods.of(method.toUpperCase())); + } + @Override public Operation resolve(Operation operation, MethodMeta methodMeta, OperationContext ctx, OperationChain chain) { AnnotationMeta annoMeta = diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java index 37010f92fe6..f8b8e921ea3 100644 --- a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerUIRequestHandler.java @@ -132,7 +132,7 @@ private HttpResult handleIndex() { } private HttpResult handleSwaggerConfig() { - OpenAPIService openAPIService = frameworkModel.getDefaultExtensionOrNull(OpenAPIService.class); + OpenAPIService openAPIService = frameworkModel.getBean(OpenAPIService.class); if (openAPIService == null) { return HttpResult.notFound(); } diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService deleted file mode 100644 index b98343397d1..00000000000 --- a/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.rest.OpenAPIService +++ /dev/null @@ -1 +0,0 @@ -default=org.apache.dubbo.rpc.protocol.tri.rest.openapi.DefaultOpenAPIService diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer new file mode 100644 index 00000000000..ba3f5a02c45 --- /dev/null +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.model.ScopeModelInitializer @@ -0,0 +1 @@ +openapi=org.apache.dubbo.rpc.protocol.tri.rest.openapi.OpenAPIScopeModelInitializer diff --git a/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/model/SecurityScopeModelInitializer.java b/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/model/SecurityScopeModelInitializer.java index 1a9531d5631..3fcd611038a 100644 --- a/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/model/SecurityScopeModelInitializer.java +++ b/dubbo-plugin/dubbo-spring-security/src/main/java/org/apache/dubbo/spring/security/model/SecurityScopeModelInitializer.java @@ -20,9 +20,7 @@ import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; import org.apache.dubbo.spring.security.jackson.ObjectMapperCodec; import org.apache.dubbo.spring.security.jackson.ObjectMapperCodecCustomer; @@ -69,10 +67,4 @@ public void initializeFrameworkModel(FrameworkModel frameworkModel) { t); } } - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java index 3c60a08cba7..9cb22fa8a53 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/RegistryScopeModelInitializer.java @@ -22,10 +22,10 @@ import org.apache.dubbo.registry.support.RegistryManager; import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class RegistryScopeModelInitializer implements ScopeModelInitializer { + @Override public void initializeFrameworkModel(FrameworkModel frameworkModel) { ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); @@ -38,7 +38,4 @@ public void initializeApplicationModel(ApplicationModel applicationModel) { beanFactory.registerBean(RegistryManager.class); beanFactory.registerBean(MetadataServiceDelegation.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java index c69fdeb9ef3..eae0eb90e58 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegation.java @@ -222,8 +222,7 @@ public String getAndListenInstanceMetadata(String consumerId, InstanceMetadataCh @Override public String getOpenAPI(OpenAPIRequest request) { if (TripleProtocol.OPENAPI_ENABLED) { - OpenAPIService openAPIService = - applicationModel.getFrameworkModel().getDefaultExtensionOrNull(OpenAPIService.class); + OpenAPIService openAPIService = applicationModel.getBean(OpenAPIService.class); if (openAPIService != null) { return openAPIService.getDocument(request); } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java index 1f8d3f2056c..c97c0691c71 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java @@ -80,7 +80,7 @@ public org.apache.dubbo.metadata.MetadataInfoV2 getMetadataInfo(MetadataRequest @Override public OpenAPI getOpenAPI(org.apache.dubbo.metadata.OpenAPIRequest request) { if (TripleProtocol.OPENAPI_ENABLED) { - OpenAPIService openAPIService = frameworkModel.getDefaultExtensionOrNull(OpenAPIService.class); + OpenAPIService openAPIService = frameworkModel.getBean(OpenAPIService.class); if (openAPIService != null) { OpenAPIRequest oRequest = new OpenAPIRequest(); oRequest.setGroup(request.getGroup()); diff --git a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIService.java b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIService.java index 18b4ac45d7b..45494e76b3a 100644 --- a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIService.java +++ b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/rest/OpenAPIService.java @@ -16,13 +16,8 @@ */ package org.apache.dubbo.remoting.http12.rest; -import org.apache.dubbo.common.constants.CommonConstants; -import org.apache.dubbo.common.extension.ExtensionScope; -import org.apache.dubbo.common.extension.SPI; - import java.util.Collection; -@SPI(value = CommonConstants.DEFAULT_KEY, scope = ExtensionScope.FRAMEWORK) public interface OpenAPIService { Collection getOpenAPIGroups(); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AdaptiveScopeModelInitializer.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AdaptiveScopeModelInitializer.java index 2d7c0f3c1c9..24860c7cb7c 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AdaptiveScopeModelInitializer.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/AdaptiveScopeModelInitializer.java @@ -18,20 +18,13 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.rpc.model.ApplicationModel; -import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class AdaptiveScopeModelInitializer implements ScopeModelInitializer { - @Override - public void initializeFrameworkModel(FrameworkModel frameworkModel) {} @Override public void initializeApplicationModel(ApplicationModel applicationModel) { ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); beanFactory.registerBean(AdaptiveMetrics.class); } - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcScopeModelInitializer.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcScopeModelInitializer.java index cfde6bc9cc1..e863a654d1a 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcScopeModelInitializer.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcScopeModelInitializer.java @@ -18,23 +18,16 @@ import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.rpc.listener.InjvmExporterListener; -import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; import org.apache.dubbo.rpc.protocol.PermittedSerializationKeeper; public class RpcScopeModelInitializer implements ScopeModelInitializer { + @Override public void initializeFrameworkModel(FrameworkModel frameworkModel) { ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory(); beanFactory.registerBean(InjvmExporterListener.class); beanFactory.registerBean(PermittedSerializationKeeper.class); } - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java index 6535f827399..ee38269b505 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/DefaultRequestMappingRegistry.java @@ -79,7 +79,7 @@ public DefaultRequestMappingRegistry(FrameworkModel frameworkModel) { private void init(Invoker invoker) { contentNegotiator = frameworkModel.getOrRegisterBean(ContentNegotiator.class); if (TripleProtocol.OPENAPI_ENABLED) { - openAPIService = frameworkModel.getDefaultExtensionOrNull(OpenAPIService.class); + openAPIService = frameworkModel.getBean(OpenAPIService.class); } resolvers = frameworkModel.getActivateExtensions(RequestMappingResolver.class); restConfig = ConfigManager.getProtocolOrDefault(invoker.getUrl()) diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java index 9d74e4ec6b1..60635c0b3f1 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/mapping/meta/BeanMeta.java @@ -32,9 +32,11 @@ import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; import java.lang.reflect.Type; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -419,6 +421,21 @@ protected AnnotatedElement getAnnotatedElement() { return getMethod; } + @Override + public List getAnnotatedElements() { + List elements = new ArrayList<>(3); + if (field != null) { + elements.add(field); + } + if (parameter != null) { + elements.add(parameter); + } + if (getMethod != null) { + elements.add(getMethod); + } + return elements; + } + public Object getValue(Object bean) { if (getMethod != null) { try { diff --git a/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/SerializationScopeModelInitializer.java b/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/SerializationScopeModelInitializer.java index 184bdb7df89..7f382c43ced 100644 --- a/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/SerializationScopeModelInitializer.java +++ b/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/SerializationScopeModelInitializer.java @@ -17,9 +17,7 @@ package org.apache.dubbo.common.serialize; import org.apache.dubbo.common.serialize.support.PreferSerializationProviderImpl; -import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class SerializationScopeModelInitializer implements ScopeModelInitializer { @@ -27,10 +25,4 @@ public class SerializationScopeModelInitializer implements ScopeModelInitializer public void initializeFrameworkModel(FrameworkModel frameworkModel) { frameworkModel.getBeanFactory().registerBean(PreferSerializationProviderImpl.class); } - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2ScopeModelInitializer.java b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2ScopeModelInitializer.java index 029839fa75e..fad45c6e996 100644 --- a/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2ScopeModelInitializer.java +++ b/dubbo-serialization/dubbo-serialization-fastjson2/src/main/java/org/apache/dubbo/common/serialize/fastjson2/Fastjson2ScopeModelInitializer.java @@ -17,9 +17,7 @@ package org.apache.dubbo.common.serialize.fastjson2; import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; -import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class Fastjson2ScopeModelInitializer implements ScopeModelInitializer { @@ -38,10 +36,4 @@ public void initializeFrameworkModel(FrameworkModel frameworkModel) { beanFactory.registerBean(Fastjson2SecurityManager.class); } } - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2ScopeModelInitializer.java b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2ScopeModelInitializer.java index 2ca838cb074..71fa7738de8 100644 --- a/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2ScopeModelInitializer.java +++ b/dubbo-serialization/dubbo-serialization-hessian2/src/main/java/org/apache/dubbo/common/serialize/hessian2/Hessian2ScopeModelInitializer.java @@ -17,9 +17,7 @@ package org.apache.dubbo.common.serialize.hessian2; import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; -import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.FrameworkModel; -import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModelInitializer; public class Hessian2ScopeModelInitializer implements ScopeModelInitializer { @@ -38,10 +36,4 @@ public void initializeFrameworkModel(FrameworkModel frameworkModel) { frameworkModel.addClassLoaderListener(new Hessian2ClassLoaderListener()); } } - - @Override - public void initializeApplicationModel(ApplicationModel applicationModel) {} - - @Override - public void initializeModuleModel(ModuleModel moduleModel) {} } diff --git a/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java index 511aeadcfd2..4c3d6c2da21 100644 --- a/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java +++ b/dubbo-spring-boot-project/dubbo-spring-boot/src/main/java/org/apache/dubbo/spring/boot/context/event/DubboOpenAPIExportListener.java @@ -44,8 +44,7 @@ public void onApplicationEvent(ApplicationReadyEvent event) { if (applicationModel == null) { return; } - OpenAPIService openAPIService = - applicationModel.getFrameworkModel().getDefaultExtensionOrNull(OpenAPIService.class); + OpenAPIService openAPIService = applicationModel.getBean(OpenAPIService.class); if (openAPIService != null) { openAPIService.export(); } From f0749affafc46d4505db81a1219b0cd25dab3c32 Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Mon, 2 Dec 2024 11:52:57 +0800 Subject: [PATCH 22/23] Fix missing chain call --- .../basic/BasicOpenAPIDefinitionResolver.java | 25 ++++++++++++------- .../SwaggerOpenAPIDefinitionResolver.java | 9 ++++--- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java index 0a5dd03e42c..7afa1326992 100644 --- a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/basic/BasicOpenAPIDefinitionResolver.java @@ -100,6 +100,7 @@ public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain ch openAPI.setPriority(annoMeta.getNumber("order")); openAPI.setExtensions(Helper.toProperties(annoMeta.getStringArray("extensions"))); + return chain.resolve(openAPI, serviceMeta); } @@ -131,15 +132,20 @@ public Operation resolve(Operation operation, MethodMeta methodMeta, OperationCo operation.setTags(new LinkedHashSet<>(Arrays.asList(tags))); } - operation.setGroup(trim(annoMeta.getString("group"))); - operation.setVersion(trim(annoMeta.getString("version"))); - operation.setOperationId(trim(annoMeta.getString("id"))); String summary = trim(annoMeta.getValue()); - operation.setSummary(summary == null ? trim(annoMeta.getString("summary")) : summary); - operation.setDescription(trim(annoMeta.getString("description"))); - operation.setDeprecated(annoMeta.getBoolean("deprecated")); - operation.setExtensions(Helper.toProperties(annoMeta.getStringArray("extensions"))); - return operation; + if (summary == null) { + summary = trim(annoMeta.getString("summary")); + } + operation + .setGroup(trim(annoMeta.getString("group"))) + .setVersion(trim(annoMeta.getString("version"))) + .setOperationId(trim(annoMeta.getString("id"))) + .setSummary(summary) + .setDescription(trim(annoMeta.getString("description"))) + .setDeprecated(annoMeta.getBoolean("deprecated")) + .setExtensions(Helper.toProperties(annoMeta.getStringArray("extensions"))); + + return chain.resolve(operation, methodMeta, ctx); } @Override @@ -178,7 +184,8 @@ public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChai setBoolValue(annoMeta, "nullable", schema::setNullable); setBoolValue(annoMeta, "deprecated", schema::setDeprecated); schema.setExtensions(Helper.toProperties(annoMeta.getStringArray("extensions"))); - return schema; + + return chain.resolve(parameter, context); } @Override diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java index c17ddd487ad..0f3446d33ca 100644 --- a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/swagger/SwaggerOpenAPIDefinitionResolver.java @@ -115,7 +115,8 @@ public OpenAPI resolve(OpenAPI openAPI, ServiceMeta serviceMeta, OpenAPIChain ch } openAPI.setExtensions(properties); } - return openAPI; + + return chain.resolve(openAPI, serviceMeta); } private static Map toProperties(io.swagger.v3.oas.annotations.extensions.Extension[] extensions) { @@ -184,12 +185,14 @@ public Operation resolve(Operation operation, MethodMeta methodMeta, OperationCo } operation.setExtensions(properties); } - return operation + operation .setSummary(trim(anno.summary())) .setDescription(trim(anno.description())) .setExternalDocs(toExternalDocs(anno.externalDocs())) .setOperationId(trim(anno.operationId())) .setDeprecated(anno.deprecated() ? Boolean.TRUE : null); + + return chain.resolve(operation, methodMeta, ctx); } @Override @@ -239,7 +242,7 @@ public Schema resolve(ParameterMeta parameter, SchemaContext context, SchemaChai schema.setNullable(anno.nullable() ? Boolean.TRUE : null); schema.setDeprecated(anno.deprecated() ? Boolean.TRUE : null); - return schema; + return chain.resolve(parameter, context); } @Override From 7a9f62c8223675247a87648cadc906eac06cdecc Mon Sep 17 00:00:00 2001 From: Sean Yang Date: Tue, 10 Dec 2024 09:44:50 +0800 Subject: [PATCH 23/23] Rename stub --- dubbo-maven-plugin/pom.xml | 1 + .../DubboMetadataServiceV2Triple.java | 114 ++++----- .../apache/dubbo/metadata/MetadataInfo.java | 4 +- .../apache/dubbo/metadata/MetadataInfoV2.java | 3 - .../dubbo/metadata/MetadataRequest.java | 2 - .../dubbo/metadata/MetadataServiceV2.java | 6 +- .../metadata/MetadataServiceV2OuterClass.java | 41 ++-- .../{OpenAPI.java => OpenAPIInfo.java} | 226 +++++++++--------- ...Builder.java => OpenAPIInfoOrBuilder.java} | 20 +- .../apache/dubbo/metadata/OpenAPIRequest.java | 2 - .../apache/dubbo/metadata/ServiceInfoV2.java | 3 - .../src/main/proto/metadata_service_v2.proto | 25 +- .../Dubbo3TripleInterfaceStub.mustache | 5 + .../main/resources/Dubbo3TripleStub.mustache | 36 +-- .../ReactorDubbo3TripleStub.mustache | 6 +- .../tri/rest/openapi/DefinitionMerger.java | 3 + .../protocol/tri/rest/openapi/model/Node.java | 4 +- .../metadata/MetadataServiceDelegationV2.java | 8 +- pom.xml | 5 +- 19 files changed, 245 insertions(+), 269 deletions(-) rename dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/{OpenAPI.java => OpenAPIInfo.java} (72%) rename dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/{OpenAPIOrBuilder.java => OpenAPIInfoOrBuilder.java} (74%) diff --git a/dubbo-maven-plugin/pom.xml b/dubbo-maven-plugin/pom.xml index bf7c74afd07..a25e21f04de 100644 --- a/dubbo-maven-plugin/pom.xml +++ b/dubbo-maven-plugin/pom.xml @@ -30,6 +30,7 @@ ${revision} 3.25.5 + diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java index 928583d12dd..cf77598c991 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/DubboMetadataServiceV2Triple.java @@ -57,16 +57,11 @@ public final class DubboMetadataServiceV2Triple { StubSuppliers.addDescriptor(MetadataServiceV2.JAVA_SERVICE_NAME, serviceDescriptor); } - @SuppressWarnings("all") + @SuppressWarnings("unchecked") public static MetadataServiceV2 newStub(Invoker invoker) { return new MetadataServiceV2Stub((Invoker) invoker); } - /** - *
-     *  Retrieves metadata information.
-     * 
- */ private static final StubMethodDescriptor getMetadataInfoMethod = new StubMethodDescriptor( "GetMetadataInfo", MetadataRequest.class, @@ -96,46 +91,42 @@ public static MetadataServiceV2 newStub(Invoker invoker) { obj -> ((Message) obj).toByteArray(), MetadataRequest::parseFrom, MetadataInfoV2::parseFrom); - /** - *
-     *  Retrieves OpenAPI.
-     * 
- */ - private static final StubMethodDescriptor getOpenAPIMethod = new StubMethodDescriptor( - "GetOpenAPI", + + private static final StubMethodDescriptor getOpenAPIInfoMethod = new StubMethodDescriptor( + "GetOpenAPIInfo", OpenAPIRequest.class, - OpenAPI.class, + OpenAPIInfo.class, MethodDescriptor.RpcType.UNARY, obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), OpenAPIRequest::parseFrom, - OpenAPI::parseFrom); + OpenAPIInfo::parseFrom); - private static final StubMethodDescriptor getOpenAPIAsyncMethod = new StubMethodDescriptor( - "GetOpenAPI", + private static final StubMethodDescriptor getOpenAPIInfoAsyncMethod = new StubMethodDescriptor( + "GetOpenAPIInfo", OpenAPIRequest.class, CompletableFuture.class, MethodDescriptor.RpcType.UNARY, obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), OpenAPIRequest::parseFrom, - OpenAPI::parseFrom); + OpenAPIInfo::parseFrom); - private static final StubMethodDescriptor getOpenAPIProxyAsyncMethod = new StubMethodDescriptor( - "GetOpenAPIAsync", + private static final StubMethodDescriptor getOpenAPIInfoProxyAsyncMethod = new StubMethodDescriptor( + "GetOpenAPIInfoAsync", OpenAPIRequest.class, - OpenAPI.class, + OpenAPIInfo.class, MethodDescriptor.RpcType.UNARY, obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), OpenAPIRequest::parseFrom, - OpenAPI::parseFrom); + OpenAPIInfo::parseFrom); static { serviceDescriptor.addMethod(getMetadataInfoMethod); serviceDescriptor.addMethod(getMetadataInfoProxyAsyncMethod); - serviceDescriptor.addMethod(getOpenAPIMethod); - serviceDescriptor.addMethod(getOpenAPIProxyAsyncMethod); + serviceDescriptor.addMethod(getOpenAPIInfoMethod); + serviceDescriptor.addMethod(getOpenAPIInfoProxyAsyncMethod); } public static class MetadataServiceV2Stub implements MetadataServiceV2, Destroyable { @@ -150,11 +141,6 @@ public MetadataServiceV2Stub(Invoker invoker) { invoker.destroy(); } - /** - *
-         *  Retrieves metadata information.
-         * 
- */ @Override public MetadataInfoV2 getMetadataInfo(MetadataRequest request) { return StubInvocationUtil.unaryCall(invoker, getMetadataInfoMethod, request); @@ -164,42 +150,26 @@ public CompletableFuture getMetadataInfoAsync(MetadataRequest re return StubInvocationUtil.unaryCall(invoker, getMetadataInfoAsyncMethod, request); } - /** - *
-         *  Retrieves metadata information.
-         * 
- */ public void getMetadataInfo(MetadataRequest request, StreamObserver responseObserver) { StubInvocationUtil.unaryCall(invoker, getMetadataInfoMethod, request, responseObserver); } - /** - *
-         *  Retrieves OpenAPI.
-         * 
- */ @Override - public OpenAPI getOpenAPI(OpenAPIRequest request) { - return StubInvocationUtil.unaryCall(invoker, getOpenAPIMethod, request); + public OpenAPIInfo getOpenAPIInfo(OpenAPIRequest request) { + return StubInvocationUtil.unaryCall(invoker, getOpenAPIInfoMethod, request); } - public CompletableFuture getOpenAPIAsync(OpenAPIRequest request) { - return StubInvocationUtil.unaryCall(invoker, getOpenAPIAsyncMethod, request); + public CompletableFuture getOpenAPIInfoAsync(OpenAPIRequest request) { + return StubInvocationUtil.unaryCall(invoker, getOpenAPIInfoAsyncMethod, request); } - /** - *
-         *  Retrieves OpenAPI.
-         * 
- */ - public void getOpenAPI(OpenAPIRequest request, StreamObserver responseObserver) { - StubInvocationUtil.unaryCall(invoker, getOpenAPIMethod, request, responseObserver); + public void getOpenAPIInfo(OpenAPIRequest request, StreamObserver responseObserver) { + StubInvocationUtil.unaryCall(invoker, getOpenAPIInfoMethod, request, responseObserver); } } public abstract static class MetadataServiceV2ImplBase implements MetadataServiceV2, ServerService { - private BiConsumer> syncToAsync(java.util.function.Function syncFun) { return new BiConsumer>() { @Override @@ -221,14 +191,14 @@ public CompletableFuture getMetadataInfoAsync(MetadataRequest re } @Override - public CompletableFuture getOpenAPIAsync(OpenAPIRequest request) { - return CompletableFuture.completedFuture(getOpenAPI(request)); + public CompletableFuture getOpenAPIInfoAsync(OpenAPIRequest request) { + return CompletableFuture.completedFuture(getOpenAPIInfo(request)); } - /** - * This server stream type unary method is only used for generated stub to support async unary method. - * It will not be called if you are NOT using Dubbo3 generated triple stub and DO NOT implement this method. - */ + // This server stream type unary method is only used for generated stub to support async unary method. + // It will not be called if you are NOT using Dubbo3 generated triple stub and DO NOT implement this + // method. + public void getMetadataInfo(MetadataRequest request, StreamObserver responseObserver) { getMetadataInfoAsync(request).whenComplete((r, t) -> { if (t != null) { @@ -240,8 +210,8 @@ public void getMetadataInfo(MetadataRequest request, StreamObserver responseObserver) { - getOpenAPIAsync(request).whenComplete((r, t) -> { + public void getOpenAPIInfo(OpenAPIRequest request, StreamObserver responseObserver) { + getOpenAPIInfoAsync(request).whenComplete((r, t) -> { if (t != null) { responseObserver.onError(t); } else { @@ -257,19 +227,16 @@ public final Invoker getInvoker(URL url) { .getExtensionLoader(PathResolver.class) .getDefaultExtension(); Map> handlers = new HashMap<>(); - pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetMetadataInfo"); pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetMetadataInfoAsync"); // for compatibility pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetMetadataInfo"); pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetMetadataInfoAsync"); - - pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetOpenAPI"); - pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetOpenAPIAsync"); + pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetOpenAPIInfo"); + pathResolver.addNativeStub("/" + SERVICE_NAME + "/GetOpenAPIInfoAsync"); // for compatibility - pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetOpenAPI"); - pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetOpenAPIAsync"); - + pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetOpenAPIInfo"); + pathResolver.addNativeStub("/" + JAVA_SERVICE_NAME + "/GetOpenAPIInfoAsync"); BiConsumer> getMetadataInfoFunc = this::getMetadataInfo; handlers.put(getMetadataInfoMethod.getMethodName(), new UnaryStubMethodHandler<>(getMetadataInfoFunc)); BiConsumer> getMetadataInfoAsyncFunc = @@ -277,10 +244,13 @@ public final Invoker getInvoker(URL url) { handlers.put( getMetadataInfoProxyAsyncMethod.getMethodName(), new UnaryStubMethodHandler<>(getMetadataInfoAsyncFunc)); - BiConsumer> getOpenAPIFunc = this::getOpenAPI; - handlers.put(getOpenAPIMethod.getMethodName(), new UnaryStubMethodHandler<>(getOpenAPIFunc)); - BiConsumer> getOpenAPIAsyncFunc = syncToAsync(this::getOpenAPI); - handlers.put(getOpenAPIProxyAsyncMethod.getMethodName(), new UnaryStubMethodHandler<>(getOpenAPIAsyncFunc)); + BiConsumer> getOpenAPIInfoFunc = this::getOpenAPIInfo; + handlers.put(getOpenAPIInfoMethod.getMethodName(), new UnaryStubMethodHandler<>(getOpenAPIInfoFunc)); + BiConsumer> getOpenAPIInfoAsyncFunc = + syncToAsync(this::getOpenAPIInfo); + handlers.put( + getOpenAPIInfoProxyAsyncMethod.getMethodName(), + new UnaryStubMethodHandler<>(getOpenAPIInfoAsyncFunc)); return new StubInvoker<>(this, url, MetadataServiceV2.class, handlers); } @@ -291,8 +261,8 @@ public MetadataInfoV2 getMetadataInfo(MetadataRequest request) { } @Override - public OpenAPI getOpenAPI(OpenAPIRequest request) { - throw unimplementedMethodException(getOpenAPIMethod); + public OpenAPIInfo getOpenAPIInfo(OpenAPIRequest request) { + throw unimplementedMethodException(getOpenAPIInfoMethod); } @Override diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java index 0a2f8c698be..d7dccf8df1c 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfo.java @@ -294,7 +294,9 @@ public Map getInstanceParams() { public String getParameter(String key, String serviceKey) { ServiceInfo serviceInfo = getValidServiceInfo(serviceKey); - if (serviceInfo == null) return null; + if (serviceInfo == null) { + return null; + } return serviceInfo.getParameter(key); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java index 82e375d7881..039940c3d61 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataInfoV2.java @@ -27,7 +27,6 @@ public final class MetadataInfoV2 extends com.google.protobuf.GeneratedMessageV3 implements // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.MetadataInfoV2) MetadataInfoV2OrBuilder { - private static final long serialVersionUID = 0L; // Use MetadataInfoV2.newBuilder() to construct. @@ -162,7 +161,6 @@ public com.google.protobuf.ByteString getVersionBytes() { public static final int SERVICES_FIELD_NUMBER = 3; private static final class ServicesDefaultEntryHolder { - static final com.google.protobuf.MapEntry defaultEntry = com.google.protobuf.MapEntry.newDefaultInstance( MetadataServiceV2OuterClass @@ -459,7 +457,6 @@ public static final class Builder extends com.google.protobuf.GeneratedMessageV3 implements // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.MetadataInfoV2) MetadataInfoV2OrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataInfoV2_descriptor; } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java index 4e78f6f807e..64f191ec087 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataRequest.java @@ -27,7 +27,6 @@ public final class MetadataRequest extends com.google.protobuf.GeneratedMessageV implements // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.MetadataRequest) MetadataRequestOrBuilder { - private static final long serialVersionUID = 0L; // Use MetadataRequest.newBuilder() to construct. @@ -270,7 +269,6 @@ public static final class Builder extends com.google.protobuf.GeneratedMessageV3 implements // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.MetadataRequest) MetadataRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_MetadataRequest_descriptor; } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java index a74d09f4d05..54278b165b8 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2.java @@ -34,10 +34,10 @@ public interface MetadataServiceV2 extends org.apache.dubbo.rpc.model.DubboStub /** *
-     *  Retrieves OpenAPI.
+     *  Retrieves OpenAPI information.
      * 
*/ - OpenAPI getOpenAPI(OpenAPIRequest request); + OpenAPIInfo getOpenAPIInfo(OpenAPIRequest request); - CompletableFuture getOpenAPIAsync(OpenAPIRequest request); + CompletableFuture getOpenAPIInfoAsync(OpenAPIRequest request); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java index 7c91790497d..fd1635a6ec1 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/MetadataServiceV2OuterClass.java @@ -17,7 +17,6 @@ package org.apache.dubbo.metadata; public final class MetadataServiceV2OuterClass { - private MetadataServiceV2OuterClass() {} public static void registerAllExtensions(com.google.protobuf.ExtensionRegistryLite registry) {} @@ -51,9 +50,9 @@ public static void registerAllExtensions(com.google.protobuf.ExtensionRegistry r static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable; static final com.google.protobuf.Descriptors.Descriptor - internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor; + internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor; static final com.google.protobuf.GeneratedMessageV3.FieldAccessorTable - internal_static_org_apache_dubbo_metadata_OpenAPI_fieldAccessorTable; + internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { return descriptor; @@ -76,20 +75,22 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { + "(\005\022\014\n\004path\030\006 \001(\t\022D\n\006params\030\007 \003(\01324.org.a" + "pache.dubbo.metadata.ServiceInfoV2.Param" + "sEntry\032-\n\013ParamsEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005va" - + "lue\030\002 \001(\t:\0028\001\"\372\001\n\016OpenAPIRequest\022\022\n\005grou" - + "p\030\001 \001(\tH\000\210\001\001\022\024\n\007version\030\002 \001(\tH\001\210\001\001\022\013\n\003ta" - + "g\030\003 \003(\t\022\017\n\007service\030\004 \003(\t\022\024\n\007openapi\030\005 \001(" - + "\tH\002\210\001\001\022=\n\006format\030\006 \001(\0162(.org.apache.dubb" - + "o.metadata.OpenAPIFormatH\003\210\001\001\022\023\n\006pretty\030" - + "\007 \001(\010H\004\210\001\001B\010\n\006_groupB\n\n\010_versionB\n\n\010_ope" - + "napiB\t\n\007_formatB\t\n\007_pretty\"\030\n\007OpenAPI\022\r\n" - + "\005value\030\001 \001(\t*.\n\rOpenAPIFormat\022\010\n\004JSON\020\000\022" - + "\010\n\004YAML\020\001\022\t\n\005PROTO\020\0022\332\001\n\021MetadataService" + + "lue\030\002 \001(\t:\0028\001\"\311\001\n\016OpenAPIRequest\022\r\n\005grou" + + "p\030\001 \001(\t\022\017\n\007version\030\002 \001(\t\022\013\n\003tag\030\003 \003(\t\022\017\n" + + "\007service\030\004 \003(\t\022\017\n\007openapi\030\005 \001(\t\022=\n\006forma" + + "t\030\006 \001(\0162(.org.apache.dubbo.metadata.Open" + + "APIFormatH\000\210\001\001\022\023\n\006pretty\030\007 \001(\010H\001\210\001\001B\t\n\007_" + + "formatB\t\n\007_pretty\"!\n\013OpenAPIInfo\022\022\n\ndefi" + + "nition\030\001 \001(\t*.\n\rOpenAPIFormat\022\010\n\004JSON\020\000\022" + + "\010\n\004YAML\020\001\022\t\n\005PROTO\020\0022\342\001\n\021MetadataService" + "V2\022h\n\017GetMetadataInfo\022*.org.apache.dubbo" + ".metadata.MetadataRequest\032).org.apache.d" - + "ubbo.metadata.MetadataInfoV2\022[\n\nGetOpenA" + "PI\022).org.apache.dubbo.metadata.OpenAPIRe" - + "quest\032\".org.apache.dubbo.metadata.OpenAP" + "IBZ\n\031org.apache.dubbo.metadataP\001Z;dubbo." - + "apache.org/dubbo-go/v3/metadata/triple_a" + "pi;triple_apib\006proto3" + + "ubbo.metadata.MetadataInfoV2\022c\n\016GetOpenA" + + "PIInfo\022).org.apache.dubbo.metadata.OpenA" + + "PIRequest\032&.org.apache.dubbo.metadata.Op" + + "enAPIInfoBZ\n\031org.apache.dubbo.metadataP\001" + + "Z;dubbo.apache.org/dubbo-go/v3/metadata/" + + "triple_api;triple_apib\006proto3" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor.internalBuildGeneratedFileFrom( descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] {}); @@ -138,14 +139,14 @@ public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { internal_static_org_apache_dubbo_metadata_OpenAPIRequest_fieldAccessorTable = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor, new String[] { - "Group", "Version", "Tag", "Service", "Openapi", "Format", "Pretty", + "Group", "Version", "Tag", "Service", "Openapi", "Format", "Pretty", "Format", "Pretty", }); - internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor = + internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor = getDescriptor().getMessageTypes().get(4); - internal_static_org_apache_dubbo_metadata_OpenAPI_fieldAccessorTable = + internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable = new com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( - internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor, new String[] { - "Value", + internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor, new String[] { + "Definition", }); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPI.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfo.java similarity index 72% rename from dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPI.java rename to dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfo.java index b8ef1efe7d2..03d25d30b38 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPI.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfo.java @@ -18,83 +18,82 @@ /** *
- * OpenAPI message.
+ * OpenAPI information message.
  * 
* - * Protobuf type {@code org.apache.dubbo.metadata.OpenAPI} + * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIInfo} */ -public final class OpenAPI extends com.google.protobuf.GeneratedMessageV3 +public final class OpenAPIInfo extends com.google.protobuf.GeneratedMessageV3 implements - // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.OpenAPI) - OpenAPIOrBuilder { - + // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.OpenAPIInfo) + OpenAPIInfoOrBuilder { private static final long serialVersionUID = 0L; - // Use OpenAPI.newBuilder() to construct. - private OpenAPI(com.google.protobuf.GeneratedMessageV3.Builder builder) { + // Use OpenAPIInfo.newBuilder() to construct. + private OpenAPIInfo(com.google.protobuf.GeneratedMessageV3.Builder builder) { super(builder); } - private OpenAPI() { - value_ = ""; + private OpenAPIInfo() { + definition_ = ""; } @Override @SuppressWarnings({"unused"}) protected Object newInstance(UnusedPrivateParameter unused) { - return new OpenAPI(); + return new OpenAPIInfo(); } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor; + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor; } @Override protected FieldAccessorTable internalGetFieldAccessorTable() { - return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPI_fieldAccessorTable - .ensureFieldAccessorsInitialized(OpenAPI.class, Builder.class); + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized(OpenAPIInfo.class, Builder.class); } - public static final int VALUE_FIELD_NUMBER = 1; + public static final int DEFINITION_FIELD_NUMBER = 1; @SuppressWarnings("serial") - private volatile Object value_ = ""; + private volatile Object definition_ = ""; /** *
-     * The value of the OpenAPI.
+     * The OpenAPI definition.
      * 
* - * string value = 1; - * @return The value. + * string definition = 1; + * @return The definition. */ @Override - public String getValue() { - Object ref = value_; + public String getDefinition() { + Object ref = definition_; if (ref instanceof String) { return (String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; String s = bs.toStringUtf8(); - value_ = s; + definition_ = s; return s; } } /** *
-     * The value of the OpenAPI.
+     * The OpenAPI definition.
      * 
* - * string value = 1; - * @return The bytes for value. + * string definition = 1; + * @return The bytes for definition. */ @Override - public com.google.protobuf.ByteString getValueBytes() { - Object ref = value_; + public com.google.protobuf.ByteString getDefinitionBytes() { + Object ref = definition_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); - value_ = b; + definition_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; @@ -119,8 +118,8 @@ public final boolean isInitialized() { @Override public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { - if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(value_)) { - com.google.protobuf.GeneratedMessageV3.writeString(output, 1, value_); + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(definition_)) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, definition_); } getUnknownFields().writeTo(output); } @@ -133,8 +132,8 @@ public int getSerializedSize() { } size = 0; - if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(value_)) { - size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, value_); + if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(definition_)) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, definition_); } size += getUnknownFields().getSerializedSize(); memoizedSize = size; @@ -146,12 +145,12 @@ public boolean equals(final Object obj) { if (obj == this) { return true; } - if (!(obj instanceof OpenAPI)) { + if (!(obj instanceof OpenAPIInfo)) { return super.equals(obj); } - OpenAPI other = (OpenAPI) obj; + OpenAPIInfo other = (OpenAPIInfo) obj; - if (!getValue().equals(other.getValue())) { + if (!getDefinition().equals(other.getDefinition())) { return false; } if (!getUnknownFields().equals(other.getUnknownFields())) { @@ -167,69 +166,69 @@ public int hashCode() { } int hash = 41; hash = (19 * hash) + getDescriptor().hashCode(); - hash = (37 * hash) + VALUE_FIELD_NUMBER; - hash = (53 * hash) + getValue().hashCode(); + hash = (37 * hash) + DEFINITION_FIELD_NUMBER; + hash = (53 * hash) + getDefinition().hashCode(); hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; } - public static OpenAPI parseFrom(java.nio.ByteBuffer data) + public static OpenAPIInfo parseFrom(java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } - public static OpenAPI parseFrom( + public static OpenAPIInfo parseFrom( java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } - public static OpenAPI parseFrom(com.google.protobuf.ByteString data) + public static OpenAPIInfo parseFrom(com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } - public static OpenAPI parseFrom( + public static OpenAPIInfo parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } - public static OpenAPI parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { + public static OpenAPIInfo parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } - public static OpenAPI parseFrom(byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) + public static OpenAPIInfo parseFrom(byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } - public static OpenAPI parseFrom(java.io.InputStream input) throws java.io.IOException { + public static OpenAPIInfo parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); } - public static OpenAPI parseFrom( + public static OpenAPIInfo parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry); } - public static OpenAPI parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { + public static OpenAPIInfo parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input); } - public static OpenAPI parseDelimitedFrom( + public static OpenAPIInfo parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3.parseDelimitedWithIOException(PARSER, input, extensionRegistry); } - public static OpenAPI parseFrom(com.google.protobuf.CodedInputStream input) throws java.io.IOException { + public static OpenAPIInfo parseFrom(com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input); } - public static OpenAPI parseFrom( + public static OpenAPIInfo parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessageV3.parseWithIOException(PARSER, input, extensionRegistry); @@ -244,7 +243,7 @@ public static Builder newBuilder() { return DEFAULT_INSTANCE.toBuilder(); } - public static Builder newBuilder(OpenAPI prototype) { + public static Builder newBuilder(OpenAPIInfo prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @@ -261,27 +260,26 @@ protected Builder newBuilderForType(BuilderParent parent) { /** *
-     * OpenAPI message.
+     * OpenAPI information message.
      * 
* - * Protobuf type {@code org.apache.dubbo.metadata.OpenAPI} + * Protobuf type {@code org.apache.dubbo.metadata.OpenAPIInfo} */ public static final class Builder extends com.google.protobuf.GeneratedMessageV3.Builder implements - // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.OpenAPI) - OpenAPIOrBuilder { - + // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.OpenAPIInfo) + OpenAPIInfoOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { - return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor; + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor; } @Override protected FieldAccessorTable internalGetFieldAccessorTable() { - return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPI_fieldAccessorTable - .ensureFieldAccessorsInitialized(OpenAPI.class, Builder.class); + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized(OpenAPIInfo.class, Builder.class); } - // Construct using org.apache.dubbo.metadata.OpenAPI.newBuilder() + // Construct using org.apache.dubbo.metadata.OpenAPIInfo.newBuilder() private Builder() {} private Builder(BuilderParent parent) { @@ -292,23 +290,23 @@ private Builder(BuilderParent parent) { public Builder clear() { super.clear(); bitField0_ = 0; - value_ = ""; + definition_ = ""; return this; } @Override public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { - return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPI_descriptor; + return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIInfo_descriptor; } @Override - public OpenAPI getDefaultInstanceForType() { - return OpenAPI.getDefaultInstance(); + public OpenAPIInfo getDefaultInstanceForType() { + return OpenAPIInfo.getDefaultInstance(); } @Override - public OpenAPI build() { - OpenAPI result = buildPartial(); + public OpenAPIInfo build() { + OpenAPIInfo result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } @@ -316,8 +314,8 @@ public OpenAPI build() { } @Override - public OpenAPI buildPartial() { - OpenAPI result = new OpenAPI(this); + public OpenAPIInfo buildPartial() { + OpenAPIInfo result = new OpenAPIInfo(this); if (bitField0_ != 0) { buildPartial0(result); } @@ -325,10 +323,10 @@ public OpenAPI buildPartial() { return result; } - private void buildPartial0(OpenAPI result) { + private void buildPartial0(OpenAPIInfo result) { int from_bitField0_ = bitField0_; if (((from_bitField0_ & 0x00000001) != 0)) { - result.value_ = value_; + result.definition_ = definition_; } } @@ -365,20 +363,20 @@ public Builder addRepeatedField(com.google.protobuf.Descriptors.FieldDescriptor @Override public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof OpenAPI) { - return mergeFrom((OpenAPI) other); + if (other instanceof OpenAPIInfo) { + return mergeFrom((OpenAPIInfo) other); } else { super.mergeFrom(other); return this; } } - public Builder mergeFrom(OpenAPI other) { - if (other == OpenAPI.getDefaultInstance()) { + public Builder mergeFrom(OpenAPIInfo other) { + if (other == OpenAPIInfo.getDefaultInstance()) { return this; } - if (!other.getValue().isEmpty()) { - value_ = other.value_; + if (!other.getDefinition().isEmpty()) { + definition_ = other.definition_; bitField0_ |= 0x00000001; onChanged(); } @@ -408,7 +406,7 @@ public Builder mergeFrom( done = true; break; case 10: { - value_ = input.readStringRequireUtf8(); + definition_ = input.readStringRequireUtf8(); bitField0_ |= 0x00000001; break; } // case 10 @@ -430,22 +428,22 @@ public Builder mergeFrom( private int bitField0_; - private Object value_ = ""; + private Object definition_ = ""; /** *
-         * The value of the OpenAPI.
+         * The OpenAPI definition.
          * 
* - * string value = 1; - * @return The value. + * string definition = 1; + * @return The definition. */ - public String getValue() { - Object ref = value_; + public String getDefinition() { + Object ref = definition_; if (!(ref instanceof String)) { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; String s = bs.toStringUtf8(); - value_ = s; + definition_ = s; return s; } else { return (String) ref; @@ -454,17 +452,17 @@ public String getValue() { /** *
-         * The value of the OpenAPI.
+         * The OpenAPI definition.
          * 
* - * string value = 1; - * @return The bytes for value. + * string definition = 1; + * @return The bytes for definition. */ - public com.google.protobuf.ByteString getValueBytes() { - Object ref = value_; + public com.google.protobuf.ByteString getDefinitionBytes() { + Object ref = definition_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8((String) ref); - value_ = b; + definition_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; @@ -473,18 +471,18 @@ public com.google.protobuf.ByteString getValueBytes() { /** *
-         * The value of the OpenAPI.
+         * The OpenAPI definition.
          * 
* - * string value = 1; - * @param value The value to set. + * string definition = 1; + * @param value The definition to set. * @return This builder for chaining. */ - public Builder setValue(String value) { + public Builder setDefinition(String value) { if (value == null) { throw new NullPointerException(); } - value_ = value; + definition_ = value; bitField0_ |= 0x00000001; onChanged(); return this; @@ -492,14 +490,14 @@ public Builder setValue(String value) { /** *
-         * The value of the OpenAPI.
+         * The OpenAPI definition.
          * 
* - * string value = 1; + * string definition = 1; * @return This builder for chaining. */ - public Builder clearValue() { - value_ = getDefaultInstance().getValue(); + public Builder clearDefinition() { + definition_ = getDefaultInstance().getDefinition(); bitField0_ = (bitField0_ & ~0x00000001); onChanged(); return this; @@ -507,19 +505,19 @@ public Builder clearValue() { /** *
-         * The value of the OpenAPI.
+         * The OpenAPI definition.
          * 
* - * string value = 1; - * @param value The bytes for value to set. + * string definition = 1; + * @param value The bytes for definition to set. * @return This builder for chaining. */ - public Builder setValueBytes(com.google.protobuf.ByteString value) { + public Builder setDefinitionBytes(com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } checkByteStringIsUtf8(value); - value_ = value; + definition_ = value; bitField0_ |= 0x00000001; onChanged(); return this; @@ -535,24 +533,24 @@ public final Builder mergeUnknownFields(final com.google.protobuf.UnknownFieldSe return super.mergeUnknownFields(unknownFields); } - // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.OpenAPI) + // @@protoc_insertion_point(builder_scope:org.apache.dubbo.metadata.OpenAPIInfo) } - // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.OpenAPI) - private static final OpenAPI DEFAULT_INSTANCE; + // @@protoc_insertion_point(class_scope:org.apache.dubbo.metadata.OpenAPIInfo) + private static final OpenAPIInfo DEFAULT_INSTANCE; static { - DEFAULT_INSTANCE = new OpenAPI(); + DEFAULT_INSTANCE = new OpenAPIInfo(); } - public static OpenAPI getDefaultInstance() { + public static OpenAPIInfo getDefaultInstance() { return DEFAULT_INSTANCE; } - private static final com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { + private static final com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { @Override - public OpenAPI parsePartialFrom( + public OpenAPIInfo parsePartialFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { @@ -571,17 +569,17 @@ public OpenAPI parsePartialFrom( } }; - public static com.google.protobuf.Parser parser() { + public static com.google.protobuf.Parser parser() { return PARSER; } @Override - public com.google.protobuf.Parser getParserForType() { + public com.google.protobuf.Parser getParserForType() { return PARSER; } @Override - public OpenAPI getDefaultInstanceForType() { + public OpenAPIInfo getDefaultInstanceForType() { return DEFAULT_INSTANCE; } } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIOrBuilder.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfoOrBuilder.java similarity index 74% rename from dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIOrBuilder.java rename to dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfoOrBuilder.java index a9578f728f2..17540e1df73 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIOrBuilder.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIInfoOrBuilder.java @@ -16,28 +16,28 @@ */ package org.apache.dubbo.metadata; -public interface OpenAPIOrBuilder +public interface OpenAPIInfoOrBuilder extends - // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.OpenAPI) + // @@protoc_insertion_point(interface_extends:org.apache.dubbo.metadata.OpenAPIInfo) com.google.protobuf.MessageOrBuilder { /** *
-     * The value of the OpenAPI.
+     * The OpenAPI definition.
      * 
* - * string value = 1; - * @return The value. + * string definition = 1; + * @return The definition. */ - String getValue(); + String getDefinition(); /** *
-     * The value of the OpenAPI.
+     * The OpenAPI definition.
      * 
* - * string value = 1; - * @return The bytes for value. + * string definition = 1; + * @return The bytes for definition. */ - com.google.protobuf.ByteString getValueBytes(); + com.google.protobuf.ByteString getDefinitionBytes(); } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java index e8393680b43..cb15b273e3a 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/OpenAPIRequest.java @@ -27,7 +27,6 @@ public final class OpenAPIRequest extends com.google.protobuf.GeneratedMessageV3 implements // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.OpenAPIRequest) OpenAPIRequestOrBuilder { - private static final long serialVersionUID = 0L; // Use OpenAPIRequest.newBuilder() to construct. @@ -655,7 +654,6 @@ public static final class Builder extends com.google.protobuf.GeneratedMessageV3 implements // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.OpenAPIRequest) OpenAPIRequestOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_OpenAPIRequest_descriptor; } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java index 7292671d56c..ca4341c6c71 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/ServiceInfoV2.java @@ -27,7 +27,6 @@ public final class ServiceInfoV2 extends com.google.protobuf.GeneratedMessageV3 implements // @@protoc_insertion_point(message_implements:org.apache.dubbo.metadata.ServiceInfoV2) ServiceInfoV2OrBuilder { - private static final long serialVersionUID = 0L; // Use ServiceInfoV2.newBuilder() to construct. @@ -319,7 +318,6 @@ public com.google.protobuf.ByteString getPathBytes() { public static final int PARAMS_FIELD_NUMBER = 7; private static final class ParamsDefaultEntryHolder { - static final com.google.protobuf.MapEntry defaultEntry = com.google.protobuf.MapEntry.newDefaultInstance( MetadataServiceV2OuterClass @@ -660,7 +658,6 @@ public static final class Builder extends com.google.protobuf.GeneratedMessageV3 implements // @@protoc_insertion_point(builder_implements:org.apache.dubbo.metadata.ServiceInfoV2) ServiceInfoV2OrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return MetadataServiceV2OuterClass.internal_static_org_apache_dubbo_metadata_ServiceInfoV2_descriptor; } diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto b/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto index b47678d21d5..cffe6129f30 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto +++ b/dubbo-metadata/dubbo-metadata-api/src/main/proto/metadata_service_v2.proto @@ -23,33 +23,32 @@ option java_package = "org.apache.dubbo.metadata"; option java_multiple_files = true; // Metadata service V2. -service MetadataServiceV2{ - +service MetadataServiceV2 { // Retrieves metadata information. rpc GetMetadataInfo(MetadataRequest) returns (MetadataInfoV2); - // Retrieves OpenAPI. - rpc GetOpenAPI(OpenAPIRequest) returns (OpenAPI); + // Retrieves OpenAPI information. + rpc GetOpenAPIInfo(OpenAPIRequest) returns (OpenAPIInfo); } // Metadata request message. -message MetadataRequest{ +message MetadataRequest { // The revision of the metadata. string revision = 1; } // Metadata information message. -message MetadataInfoV2{ +message MetadataInfoV2 { // The application name. string app = 1; // The application version. string version = 2; // A map of service information. - map services = 3; + map services = 3; } // Service information message. -message ServiceInfoV2{ +message ServiceInfoV2 { // The service name. string name = 1; // The service group. @@ -63,7 +62,7 @@ message ServiceInfoV2{ // The service path. string path = 6; // A map of service parameters. - map params = 7; + map params = 7; } // OpenAPI request message. @@ -99,8 +98,8 @@ enum OpenAPIFormat { PROTO = 2; } -// OpenAPI message. -message OpenAPI { - // The value of the OpenAPI. - string value = 1; +// OpenAPI information message. +message OpenAPIInfo { + // The OpenAPI definition. + string definition = 1; } diff --git a/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleInterfaceStub.mustache b/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleInterfaceStub.mustache index 559e2b9e5ce..ccc00ce0ed6 100644 --- a/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleInterfaceStub.mustache +++ b/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleInterfaceStub.mustache @@ -31,6 +31,7 @@ import java.util.function.BiConsumer; import java.util.concurrent.CompletableFuture; public interface {{interfaceClassName}} extends org.apache.dubbo.rpc.model.DubboStub { + String JAVA_SERVICE_NAME = "{{packageName}}.{{serviceName}}"; {{#commonPackageName}} String SERVICE_NAME = "{{commonPackageName}}.{{serviceName}}"; @@ -39,6 +40,7 @@ public interface {{interfaceClassName}} extends org.apache.dubbo.rpc.model.Dubbo String SERVICE_NAME = "{{serviceName}}"; {{/commonPackageName}} {{#unaryMethods}} + {{#javaDoc}} {{{javaDoc}}} {{/javaDoc}} @@ -50,6 +52,7 @@ public interface {{interfaceClassName}} extends org.apache.dubbo.rpc.model.Dubbo CompletableFuture<{{outputType}}> {{methodName}}Async({{#needRequestAnnotation}}@GRequest {{/needRequestAnnotation}}{{inputType}} request); {{/unaryMethods}} {{#serverStreamingMethods}} + {{#javaDoc}} {{{javaDoc}}} {{/javaDoc}} @@ -59,12 +62,14 @@ public interface {{interfaceClassName}} extends org.apache.dubbo.rpc.model.Dubbo void {{methodName}}({{#needRequestAnnotation}}@GRequest{{#body}}("{{body}}"){{/body}} {{/needRequestAnnotation}}{{inputType}} request, StreamObserver<{{outputType}}> responseObserver); {{/serverStreamingMethods}} {{#biStreamingWithoutClientStreamMethods}} + {{#javaDoc}} {{{javaDoc}}} {{/javaDoc}} StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver); {{/biStreamingWithoutClientStreamMethods}} {{#clientStreamingMethods}} + {{#javaDoc}} {{{javaDoc}}} {{/javaDoc}} diff --git a/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleStub.mustache b/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleStub.mustache index 94572b36e42..800aaf4a203 100644 --- a/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleStub.mustache +++ b/dubbo-plugin/dubbo-compiler/src/main/resources/Dubbo3TripleStub.mustache @@ -47,26 +47,25 @@ import java.util.function.BiConsumer; import java.util.concurrent.CompletableFuture; public final class {{className}} { + public static final String SERVICE_NAME = {{interfaceClassName}}.SERVICE_NAME; - private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME,{{interfaceClassName}}.class); + private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME, {{interfaceClassName}}.class); static { - org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME,{{outerClassName}}.getDescriptor()); + org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME, {{outerClassName}}.getDescriptor()); StubSuppliers.addSupplier(SERVICE_NAME, {{className}}::newStub); StubSuppliers.addSupplier({{interfaceClassName}}.JAVA_SERVICE_NAME, {{className}}::newStub); StubSuppliers.addDescriptor(SERVICE_NAME, serviceDescriptor); StubSuppliers.addDescriptor({{interfaceClassName}}.JAVA_SERVICE_NAME, serviceDescriptor); } - @SuppressWarnings("all") + @SuppressWarnings("unchecked") public static {{interfaceClassName}} newStub(Invoker invoker) { return new {{interfaceClassName}}Stub((Invoker<{{interfaceClassName}}>)invoker); } {{#unaryMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor("{{originMethodName}}", {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.UNARY, obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), {{inputType}}::parseFrom, @@ -83,27 +82,21 @@ public final class {{className}} { {{outputType}}::parseFrom); {{/unaryMethods}} {{#serverStreamingMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor("{{originMethodName}}", {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.SERVER_STREAM, obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), {{inputType}}::parseFrom, {{outputType}}::parseFrom); {{/serverStreamingMethods}} {{#clientStreamingMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor("{{originMethodName}}", {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.CLIENT_STREAM, obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), {{inputType}}::parseFrom, {{outputType}}::parseFrom); {{/clientStreamingMethods}} {{#biStreamingWithoutClientStreamMethods}} - {{#javaDoc}} - {{{javaDoc}}} - {{/javaDoc}} + private static final StubMethodDescriptor {{methodName}}Method = new StubMethodDescriptor("{{originMethodName}}", {{inputType}}.class, {{outputType}}.class, MethodDescriptor.RpcType.BI_STREAM, obj -> ((Message) obj).toByteArray(), obj -> ((Message) obj).toByteArray(), {{inputType}}::parseFrom, @@ -138,10 +131,12 @@ public final class {{className}} { invoker.destroy(); } {{#unaryMethods}} + @Override public {{outputType}} {{methodName}}({{inputType}} request){ return StubInvocationUtil.unaryCall(invoker, {{methodName}}Method, request); } + public CompletableFuture<{{outputType}}> {{methodName}}Async({{inputType}} request){ return StubInvocationUtil.unaryCall(invoker, {{methodName}}AsyncMethod, request); } @@ -151,18 +146,21 @@ public final class {{className}} { } {{/unaryMethods}} {{#serverStreamingMethods}} + @Override public void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver){ StubInvocationUtil.serverStreamCall(invoker, {{methodName}}Method , request, responseObserver); } {{/serverStreamingMethods}} {{#biStreamingWithoutClientStreamMethods}} + @Override public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){ return StubInvocationUtil.biOrClientStreamCall(invoker, {{methodName}}Method , responseObserver); } {{/biStreamingWithoutClientStreamMethods}} {{#clientStreamingMethods}} + @Override public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){ return StubInvocationUtil.biOrClientStreamCall(invoker, {{methodName}}Method , responseObserver); @@ -186,6 +184,7 @@ public final class {{className}} { }; } {{#unaryMethods}} + @Override public CompletableFuture<{{outputType}}> {{methodName}}Async({{inputType}} request){ return CompletableFuture.completedFuture({{methodName}}(request)); @@ -195,6 +194,7 @@ public final class {{className}} { // This server stream type unary method is only used for generated stub to support async unary method. // It will not be called if you are NOT using Dubbo3 generated triple stub and DO NOT implement this method. {{#unaryMethods}} + public void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver){ {{methodName}}Async(request).whenComplete((r, t) -> { if (t != null) { @@ -212,7 +212,7 @@ public final class {{className}} { PathResolver pathResolver = url.getOrDefaultFrameworkModel() .getExtensionLoader(PathResolver.class) .getDefaultExtension(); - Map> handlers = new HashMap<>(); + Map> handlers = new HashMap<>(); {{#methods}} pathResolver.addNativeStub( "/" + SERVICE_NAME + "/{{originMethodName}}"); pathResolver.addNativeStub( "/" + SERVICE_NAME + "/{{originMethodName}}Async"); @@ -239,24 +239,28 @@ public final class {{className}} { return new StubInvoker<>(this, url, {{interfaceClassName}}.class, handlers); } {{#unaryMethods}} + @Override public {{outputType}} {{methodName}}({{inputType}} request){ throw unimplementedMethodException({{methodName}}Method); } {{/unaryMethods}} {{#serverStreamingMethods}} + @Override public void {{methodName}}({{inputType}} request, StreamObserver<{{outputType}}> responseObserver){ throw unimplementedMethodException({{methodName}}Method); } {{/serverStreamingMethods}} {{#biStreamingWithoutClientStreamMethods}} + @Override public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){ throw unimplementedMethodException({{methodName}}Method); } {{/biStreamingWithoutClientStreamMethods}} {{#clientStreamingMethods}} + @Override public StreamObserver<{{inputType}}> {{methodName}}(StreamObserver<{{outputType}}> responseObserver){ throw unimplementedMethodException({{methodName}}Method); diff --git a/dubbo-plugin/dubbo-compiler/src/main/resources/ReactorDubbo3TripleStub.mustache b/dubbo-plugin/dubbo-compiler/src/main/resources/ReactorDubbo3TripleStub.mustache index c36513f9165..16ac2a41709 100644 --- a/dubbo-plugin/dubbo-compiler/src/main/resources/ReactorDubbo3TripleStub.mustache +++ b/dubbo-plugin/dubbo-compiler/src/main/resources/ReactorDubbo3TripleStub.mustache @@ -51,10 +51,10 @@ public final class {{className}} { public static final String SERVICE_NAME = {{interfaceClassName}}.SERVICE_NAME; - private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME,{{interfaceClassName}}.class); + private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME, {{interfaceClassName}}.class); static { - org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME,{{outerClassName}}.getDescriptor()); + org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME, {{outerClassName}}.getDescriptor()); StubSuppliers.addSupplier(SERVICE_NAME, {{className}}::newStub); StubSuppliers.addSupplier({{interfaceClassName}}.JAVA_SERVICE_NAME, {{className}}::newStub); StubSuppliers.addDescriptor(SERVICE_NAME, serviceDescriptor); @@ -149,7 +149,7 @@ public final class {{className}} { PathResolver pathResolver = url.getOrDefaultFrameworkModel() .getExtensionLoader(PathResolver.class) .getDefaultExtension(); - Map> handlers = new HashMap<>(); + Map> handlers = new HashMap<>(); {{#methods}} pathResolver.addNativeStub( "/" + SERVICE_NAME + "/{{originMethodName}}"); diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java index e2814aed4fb..68206ae6468 100644 --- a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/DefinitionMerger.java @@ -250,6 +250,9 @@ private void mergeInfo(OpenAPI target, OpenAPI source) { License sourceLicense = sourceInfo.getLicense(); if (sourceLicense != null) { License license = info.getLicense(); + if (license == null) { + info.setLicense(license = new License()); + } setValue(sourceLicense::getName, license::setName); setValue(sourceLicense::getUrl, license::setUrl); license.addExtensions(sourceLicense.getExtensions()); diff --git a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java index bda5bbd3a62..45fa1ae7aea 100644 --- a/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java +++ b/dubbo-plugin/dubbo-rest-openapi/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/openapi/model/Node.java @@ -68,7 +68,9 @@ public void removeExtension(String name) { @SuppressWarnings("unchecked") public T setExtensions(Map extensions) { - this.extensions = new LinkedHashMap<>(extensions); + if (extensions != null) { + this.extensions = new LinkedHashMap<>(extensions); + } return (T) this; } diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java index c97c0691c71..9bf263e7767 100644 --- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java +++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/MetadataServiceDelegationV2.java @@ -23,8 +23,8 @@ import org.apache.dubbo.metadata.DubboMetadataServiceV2Triple.MetadataServiceV2ImplBase; import org.apache.dubbo.metadata.MetadataInfo; import org.apache.dubbo.metadata.MetadataRequest; -import org.apache.dubbo.metadata.OpenAPI; import org.apache.dubbo.metadata.OpenAPIFormat; +import org.apache.dubbo.metadata.OpenAPIInfo; import org.apache.dubbo.registry.client.ServiceDiscovery; import org.apache.dubbo.registry.support.RegistryManager; import org.apache.dubbo.remoting.http12.HttpStatus; @@ -57,7 +57,7 @@ public MetadataServiceDelegationV2(ApplicationModel applicationModel) { @Override public org.apache.dubbo.metadata.MetadataInfoV2 getMetadataInfo(MetadataRequest metadataRequestV2) { String revision = metadataRequestV2.getRevision(); - MetadataInfo info = null; + MetadataInfo info; if (StringUtils.isEmpty(revision)) { return null; } @@ -78,7 +78,7 @@ public org.apache.dubbo.metadata.MetadataInfoV2 getMetadataInfo(MetadataRequest } @Override - public OpenAPI getOpenAPI(org.apache.dubbo.metadata.OpenAPIRequest request) { + public OpenAPIInfo getOpenAPIInfo(org.apache.dubbo.metadata.OpenAPIRequest request) { if (TripleProtocol.OPENAPI_ENABLED) { OpenAPIService openAPIService = frameworkModel.getBean(OpenAPIService.class); if (openAPIService != null) { @@ -96,7 +96,7 @@ public OpenAPI getOpenAPI(org.apache.dubbo.metadata.OpenAPIRequest request) { oRequest.setPretty(request.getPretty()); } String document = openAPIService.getDocument(oRequest); - return OpenAPI.newBuilder().setValue(document).build(); + return OpenAPIInfo.newBuilder().setDefinition(document).build(); } } diff --git a/pom.xml b/pom.xml index 6165366625b..40072753238 100644 --- a/pom.xml +++ b/pom.xml @@ -162,7 +162,6 @@ 1.7.1 0.6.1 3.0.2 - 3.3.2 6.2.0 @@ -319,12 +318,14 @@ org.apache.dubbo dubbo-maven-plugin - ${dubbo_maven_version} + ${project.version} + generate-stubs compile + generate-sources