You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2023/08/23 00:55:05 UTC

[servicecomb-java-chassis] branch master updated (c30191c05 -> c6eeb90ff)

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

liubao pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git


    from c30191c05 [SCB-2803]fix checkstyle
     new b1642095c [SCB-2803]add proto-buffer schema codec
     new 3d4c0b071 [SCB-2803]add request proto-buffer codec
     new d3a787ccd [SCB-2803]add test case for request proto-buffer codec
     new 2607f0331 [SCB-2803]add response proto-buffer codec
     new 6ad909d91 [SCB-2803]add test case for response proto-buffer codec
     new c6eeb90ff [SCB-2803]fix checkstyle and test fails

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 ci/checkstyle/checkstyle.xml                       |   4 +
 common/common-protobuf/pom.xml                     |   4 -
 .../converter/SwaggerToProtoGenerator.java         |  30 +--
 .../protobuf/schema/SchemaToProtoGenerator.java    | 262 +++++++++++++++++++++
 .../utils/ScopedProtobufSchemaManager.java         |  55 +++++
 .../codec/protobuf/schema/TestSchemaCodec.java     |  87 +++++++
 .../schema/TestSchemaToProtoGenerator.java         | 189 +++++++++++++++
 common/common-rest/pom.xml                         |   4 +
 .../common/rest/HttpTransportContext.java          |  11 +-
 .../common/rest/RestProducerInvocationCreator.java |  17 --
 .../rest/RestVertxProducerInvocationCreator.java   |   3 +-
 .../common/rest/VertxHttpTransportContext.java     |   5 +-
 .../servicecomb/common/rest/codec/RestCodec.java   |   3 +-
 .../rest/codec/param/BodyProcessorCreator.java     | 212 +++++++++++++----
 .../rest/codec/param/CookieProcessorCreator.java   |   4 +-
 .../rest/codec/param/FormProcessorCreator.java     |   4 +-
 .../rest/codec/param/HeaderProcessorCreator.java   |   4 +-
 .../codec/param/ParamValueProcessorCreator.java    |   5 +-
 .../rest/codec/param/PathProcessorCreator.java     |   4 +-
 .../rest/codec/param/QueryProcessorCreator.java    |   4 +-
 .../codec/produce/ProduceProcessorManager.java     |  90 +++----
 .../codec/produce/ProduceProtoBufferProcessor.java | 107 +++++++++
 .../codec/produce/ProduceTextPlainProcessor.java   |  23 +-
 .../common/rest/definition/RestOperationMeta.java  | 128 +---------
 .../common/rest/definition/RestParam.java          |  18 +-
 .../rest/filter/inner/RestServerCodecFilter.java   |   8 +-
 .../rest/RestProducerInvocationCreatorTest.java    |  39 +--
 .../common/rest/codec/TestRestCodec.java           |   2 +-
 .../common/rest/codec/param/TestBodyProcessor.java |  46 ++--
 .../rest/codec/param/TestBodyProcessorCreator.java |   4 +-
 .../codec/param/TestCookieProcessorCreator.java    |   2 +-
 .../rest/codec/param/TestFormProcessorCreator.java |   2 +-
 .../codec/param/TestHeaderProcessorCreator.java    |   2 +-
 .../rest/codec/param/TestPathProcessorCreator.java |   2 +-
 .../codec/param/TestQueryProcessorCreator.java     |   4 +-
 .../produce/TestProduceTextPlainProcessor.java     |   4 +-
 .../common/rest/definition/TestPath.java           |   6 +-
 .../rest/definition/TestRestOperationMeta.java     | 195 ---------------
 .../definition/path/QueryVarParamWriterTest.java   |   6 +-
 .../rest/definition/path/URLPathBuilderTest.java   |   2 +-
 .../filter/inner/RestServerCodecFilterTest.java    |  33 ++-
 .../demo/springmvc/client/TestContentType.java     |  39 ++-
 .../demo/springmvc/server/CodeFirstSpringmvc.java  |   6 -
 .../springmvc/server/ContentTypeSpringmvc.java     |  13 +
 .../schemas/CodeFirstSpringmvcForSchema.yaml       |   8 +-
 pom.xml                                            |   2 +-
 .../apache/servicecomb/swagger/SwaggerUtils.java   |  83 +++++--
 .../parameter/RawJsonRequestBodyProcessor.java     |   6 +
 .../src/test/resources/schemas/echo.yaml           |   3 -
 ...stractHttpMethodMappingAnnotationProcessor.java |  13 +-
 .../RequestMappingClassAnnotationProcessor.java    |   8 +
 .../swagger/generator/springmvc/Echo.java          |  11 +-
 .../springmvc/MethodMixupAnnotations.java          |  24 +-
 .../springmvc/model/DefaultParameterSchema.java    |   4 +-
 .../resources/schemas/DefaultParameterSchema.yaml  |  13 +-
 .../src/test/resources/schemas/echo.yaml           |  35 ---
 .../test/resources/schemas/mixupAnnotations.yaml   |  90 ++-----
 .../transport/rest/client/RestClientDecoder.java   |   7 +-
 .../RestServletProducerInvocationCreator.java      |   2 +-
 59 files changed, 1230 insertions(+), 771 deletions(-)
 create mode 100644 common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/schema/SchemaToProtoGenerator.java
 create mode 100644 common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaCodec.java
 create mode 100644 common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaToProtoGenerator.java
 create mode 100644 common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProtoBufferProcessor.java


[servicecomb-java-chassis] 03/06: [SCB-2803]add test case for request proto-buffer codec

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit d3a787ccdfd2d3e966be697910ff8200620afeba
Author: liubao <bi...@qq.com>
AuthorDate: Mon Aug 21 21:07:09 2023 +0800

    [SCB-2803]add test case for request proto-buffer codec
---
 .../servicecomb/common/rest/codec/RestCodec.java   |  2 +-
 .../rest/codec/param/BodyProcessorCreator.java     | 21 +++++++++---------
 .../demo/springmvc/client/TestContentType.java     | 25 ++++++++++++++++++++--
 .../springmvc/server/ContentTypeSpringmvc.java     | 13 +++++++++++
 4 files changed, 48 insertions(+), 13 deletions(-)

diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java
index 3427a6065..161288b8f 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java
@@ -60,7 +60,7 @@ public final class RestCodec {
                 param.getParamName(),
                 param.getParamProcessor().getProcessorType(),
                 e.getMessage());
-        throw new InvocationException(Status.BAD_REQUEST, message);
+        throw new InvocationException(Status.BAD_REQUEST, message, e);
       }
     }
 
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
index dd177a31c..736b8a060 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
@@ -79,6 +79,7 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
   private static final Object LOCK = new Object();
 
   public static class BodyProcessor implements ParamValueProcessor {
+    // Producer target type. For consumer, is null.
     protected JavaType targetType;
 
     protected Class<?> serialViewClass;
@@ -95,11 +96,12 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
 
     protected RequestBody requestBody;
 
-    public BodyProcessor(OperationMeta operationMeta, JavaType targetType, RequestBody parameter) {
-      if (!StringUtils.isEmpty((String) parameter.getExtensions()
+    public BodyProcessor(OperationMeta operationMeta, JavaType targetType, RequestBody requestBody) {
+      this.requestBody = requestBody;
+      if (!StringUtils.isEmpty((String) this.requestBody.getExtensions()
           .get(SwaggerConst.EXT_JSON_VIEW))) {
         try {
-          this.serialViewClass = Class.forName((String) parameter.getExtensions()
+          this.serialViewClass = Class.forName((String) this.requestBody.getExtensions()
               .get(SwaggerConst.EXT_JSON_VIEW));
         } catch (Throwable e) {
           //ignore
@@ -107,11 +109,10 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
         }
       }
 
-      this.requestBody = new RequestBody();
       this.targetType = targetType;
-      this.isRequired = parameter.getRequired() != null && parameter.getRequired();
-      if (parameter.getContent() != null) {
-        supportedContentTypes.addAll(parameter.getContent().keySet());
+      this.isRequired = this.requestBody.getRequired() != null && this.requestBody.getRequired();
+      if (this.requestBody.getContent() != null) {
+        supportedContentTypes.addAll(this.requestBody.getContent().keySet());
       }
 
       if (operationMeta != null) {
@@ -179,7 +180,7 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
       }
 
       if (SwaggerConst.PROTOBUF_TYPE.equals(contentType)) {
-        String messageName = (String) requestBody.getContent().get(SwaggerConst.PROTOBUF_TYPE).getExtensions()
+        String messageName = (String) requestBody.getExtensions()
             .get(SwaggerConst.EXT_BODY_NAME);
         ProtoMapper protoMapper = scopedProtobufSchemaManager
             .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(),
@@ -240,7 +241,7 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
      */
     private Buffer createBodyBuffer(String contentType, Object arg) throws IOException {
       if (SwaggerConst.PROTOBUF_TYPE.equals(contentType)) {
-        String messageName = (String) requestBody.getContent().get(SwaggerConst.PROTOBUF_TYPE).getExtensions()
+        String messageName = (String) requestBody.getExtensions()
             .get(SwaggerConst.EXT_BODY_NAME);
         ProtoMapper protoMapper = scopedProtobufSchemaManager
             .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(),
@@ -248,7 +249,7 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
                 requestBody.getContent().get(SwaggerConst.PROTOBUF_TYPE).getSchema());
         RootSerializer serializer = protoMapper.getSerializerSchemaManager()
             .createRootSerializer(protoMapper.getProto().getMessage(messageName),
-                targetType);
+                Object.class);
         Map<String, Object> bodyArg = new HashMap<>(1);
         bodyArg.put("value", arg);
         return new BufferImpl().appendBytes(serializer.serialize(bodyArg));
diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java
index aaf564673..662f153b0 100644
--- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java
+++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java
@@ -17,16 +17,18 @@
 
 package org.apache.servicecomb.demo.springmvc.client;
 
-import jakarta.ws.rs.core.MediaType;
-
 import org.apache.servicecomb.demo.TestMgr;
+import org.apache.servicecomb.demo.server.User;
 import org.apache.servicecomb.provider.springmvc.reference.CseHttpEntity;
 import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
+import org.apache.servicecomb.swagger.generator.SwaggerConst;
 import org.springframework.http.HttpHeaders;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.client.RestTemplate;
 
+import jakarta.ws.rs.core.MediaType;
+
 public class TestContentType {
 
   private RestTemplate restTemplate = RestTemplateBuilder.create();
@@ -35,6 +37,7 @@ public class TestContentType {
     testGlobalSetting();
     testApiOperation();
     testRequestMapping();
+    testProtoBuffer();
     testResponseTypeOverwrite();
   }
 
@@ -79,6 +82,24 @@ public class TestContentType {
     TestMgr.check(MediaType.APPLICATION_JSON, extractContentType(responseEntity.getHeaders().getContentType()));
   }
 
+
+  private void testProtoBuffer() {
+    HttpHeaders requestHeaders = new HttpHeaders();
+    requestHeaders.add(HttpHeaders.CONTENT_TYPE, SwaggerConst.PROTOBUF_TYPE);
+    User user = new User();
+    user.setIndex(100);
+    user.setName("hello");
+    user.setNames(new String[] {"a1", "a2"});
+    CseHttpEntity<User> requestEntity = new CseHttpEntity<>(user, requestHeaders);
+    ResponseEntity<String> responseEntity = restTemplate
+        .exchange("cse://springmvc/contentTypeSpringmvc/testProtoBuffer", HttpMethod.POST,
+            requestEntity, String.class);
+    TestMgr.check(
+        "testRequestMapping: name=[hello:100:[a1, a2]], request content-type=[application/protobuf]",
+        responseEntity.getBody());
+    TestMgr.check(MediaType.APPLICATION_JSON, extractContentType(responseEntity.getHeaders().getContentType()));
+  }
+
   private void testResponseTypeOverwrite() {
     ResponseEntity<String> responseEntity = restTemplate
         .getForEntity("cse://springmvc/contentTypeSpringmvcOverwrite/testResponseTypeOverwrite", String.class);
diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java
index a31232752..6626f553c 100644
--- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java
+++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java
@@ -17,7 +17,11 @@
 
 package org.apache.servicecomb.demo.springmvc.server;
 
+import java.util.Arrays;
+
+import org.apache.servicecomb.demo.server.User;
 import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.apache.servicecomb.swagger.generator.SwaggerConst;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
@@ -43,4 +47,13 @@ public class ContentTypeSpringmvc {
   public String testRequestMapping(@RequestBody String name, HttpServletRequest request) {
     return String.format("testRequestMapping: name=[%s], request content-type=[%s]", name, request.getContentType());
   }
+
+  // TODO: 注册中心不会覆盖契约
+  @RequestMapping(path = "/testProtoBuffer", method = RequestMethod.POST,
+      consumes = SwaggerConst.PROTOBUF_TYPE, produces = MediaType.APPLICATION_JSON)
+  public String testProtoBuffer(@RequestBody User user, HttpServletRequest request) {
+    return String.format("testRequestMapping: name=[%s], request content-type=[%s]",
+        user.getName() + ":" + user.getIndex() + ":" +
+            Arrays.toString(user.getNames()), request.getContentType());
+  }
 }


[servicecomb-java-chassis] 01/06: [SCB-2803]add proto-buffer schema codec

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit b1642095ccbc2d53a745db4640735a846efe7512
Author: liubao <bi...@qq.com>
AuthorDate: Mon Aug 21 09:46:24 2023 +0800

    [SCB-2803]add proto-buffer schema codec
---
 .../converter/SwaggerToProtoGenerator.java         |  30 +--
 .../protobuf/schema/SchemaToProtoGenerator.java    | 262 +++++++++++++++++++++
 .../utils/ScopedProtobufSchemaManager.java         |  55 +++++
 .../codec/protobuf/schema/TestSchemaCodec.java     |  87 +++++++
 .../schema/TestSchemaToProtoGenerator.java         | 191 +++++++++++++++
 .../apache/servicecomb/swagger/SwaggerUtils.java   |  83 +++++--
 6 files changed, 665 insertions(+), 43 deletions(-)

diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerToProtoGenerator.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerToProtoGenerator.java
index a9333148e..6d00adeda 100644
--- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerToProtoGenerator.java
+++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/internal/converter/SwaggerToProtoGenerator.java
@@ -79,22 +79,19 @@ public class SwaggerToProtoGenerator {
   public Proto convert() {
     convertDefinitions();
     convertOperations();
-    for (; ; ) {
+    do {
       List<Runnable> oldPending = pending;
       pending = new ArrayList<>();
       for (Runnable runnable : oldPending) {
         runnable.run();
       }
-      if (pending.isEmpty()) {
-        break;
-      }
-    }
+    } while (!pending.isEmpty());
 
     return createProto();
   }
 
   public static String escapePackageName(String name) {
-    return name.replaceAll("[\\-\\:]", "_");
+    return name.replaceAll("[\\-:]", "_");
   }
 
   public static String escapeMessageName(String name) {
@@ -102,10 +99,7 @@ public class SwaggerToProtoGenerator {
   }
 
   public static boolean isValidEnum(String name) {
-    if (name.contains(".") || name.contains("-")) {
-      return false;
-    }
-    return true;
+    return !name.contains(".") && !name.contains("-");
   }
 
   private void convertDefinitions() {
@@ -272,18 +266,14 @@ public class SwaggerToProtoGenerator {
     String key = swaggerType + ":" + swaggerFmt;
     return switch (key) {
       case "boolean:null" -> "bool";
-      // there is no int8/int16 in protobuf
-      case "integer:null" -> "int64";
-      case "integer:int8", "integer:int16", "integer:int32" -> "int32";
-      case "integer:int64" -> "int64";
-      case "number:null" -> "double";
+      case "integer:null", "integer:int64" -> "int64";
+      case "integer:int32" -> "int32";
+      case "number:null", "number:double" -> "double";
       case "number:float" -> "float";
-      case "number:double" -> "double";
       case "string:null" -> "string";
-      case "string:byte" -> "bytes"; // LocalDate
-      case "string:date", "string:date-time" -> // Date
-          "int64";
-      case "file:null" -> throw new IllegalStateException("not support swagger type: " + swaggerType);
+      case "string:byte" -> "bytes";
+      case "string:date", "string:date-time" -> "int64";
+      case "string:binary" -> throw new IllegalArgumentException("proto buffer not support file upload/download");
       default -> null;
     };
   }
diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/schema/SchemaToProtoGenerator.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/schema/SchemaToProtoGenerator.java
new file mode 100644
index 000000000..0e0c4bb6a
--- /dev/null
+++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/schema/SchemaToProtoGenerator.java
@@ -0,0 +1,262 @@
+/*
+ * 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.servicecomb.codec.protobuf.schema;
+
+
+import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.appendLine;
+
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.servicecomb.foundation.protobuf.internal.ProtoConst;
+import org.apache.servicecomb.foundation.protobuf.internal.parser.ProtoParser;
+import org.springframework.util.CollectionUtils;
+
+import com.google.common.hash.Hashing;
+
+import io.protostuff.compiler.model.Message;
+import io.protostuff.compiler.model.Proto;
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.media.Schema;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class SchemaToProtoGenerator {
+  private final String protoPackage;
+
+  private final OpenAPI openAPI;
+
+  private final Schema<?> rootSchema;
+
+  private final String rootName;
+
+  private final Set<String> imports = new HashSet<>();
+
+  private final Set<String> messages = new HashSet<>();
+
+  private final StringBuilder msgStringBuilder = new StringBuilder();
+
+  private List<Runnable> pending = new ArrayList<>();
+
+  public SchemaToProtoGenerator(String protoPackage, OpenAPI openAPI, Schema<?> rootSchema, String rootName) {
+    this.protoPackage = protoPackage;
+    this.openAPI = openAPI;
+    this.rootSchema = rootSchema;
+    this.rootName = rootName;
+  }
+
+  public Proto convert() {
+    convertSwaggerType(this.rootSchema);
+
+    Map<String, Schema> wrap = new HashMap<>(1);
+    wrap.put("value", this.rootSchema);
+    createMessage(rootName, wrap, ProtoConst.ANNOTATION_WRAP_PROPERTY);
+
+    do {
+      List<Runnable> oldPending = pending;
+      pending = new ArrayList<>();
+      for (Runnable runnable : oldPending) {
+        runnable.run();
+      }
+    } while (!pending.isEmpty());
+
+    return createProto();
+  }
+
+  protected Proto createProto() {
+    StringBuilder sb = new StringBuilder();
+    appendLine(sb, "syntax = \"proto3\";");
+    for (String importMsg : imports) {
+      appendLine(sb, "import \"%s\";", importMsg);
+    }
+    if (StringUtils.isNotEmpty(protoPackage)) {
+      sb.append("package ").append(protoPackage).append(";\n");
+    }
+    sb.append(msgStringBuilder);
+    ProtoParser protoParser = new ProtoParser();
+    return protoParser.parseFromContent(sb.toString());
+  }
+
+  private String convertSwaggerType(Schema<?> swaggerType) {
+    @SuppressWarnings("unchecked")
+    String type = tryFindEnumType((List<String>) swaggerType.getEnum());
+    if (type != null) {
+      return type;
+    }
+
+    type = findBaseType(swaggerType.getType(), swaggerType.getFormat());
+    if (type != null) {
+      return type;
+    }
+
+    Schema<?> itemProperty = swaggerType.getItems();
+    if (itemProperty != null) {
+      return "repeated " + convertArrayOrMapItem(itemProperty);
+    }
+
+    itemProperty = swaggerType.getAdditionalItems();
+    if (itemProperty != null) {
+      return String.format("map<string, %s>", convertArrayOrMapItem(itemProperty));
+    }
+
+    type = swaggerType.get$ref();
+    if (type != null) {
+      Schema<?> refSchema = openAPI.getComponents().getSchemas().get(
+          type.substring(Components.COMPONENTS_SCHEMAS_REF.length()));
+      if (refSchema == null) {
+        throw new IllegalArgumentException("not found ref in components " + type);
+      }
+      return convertSwaggerType(refSchema);
+    }
+
+    Map<String, Schema> properties = swaggerType.getProperties();
+    if (CollectionUtils.isEmpty(properties)) {
+      addImports(ProtoConst.ANY_PROTO);
+      return ProtoConst.ANY.getCanonicalName();
+    }
+    createMessage(swaggerType.getName(), properties);
+    return swaggerType.getName();
+  }
+
+  private void addImports(Proto proto) {
+    imports.add(proto.getFilename());
+    for (Message message : proto.getMessages()) {
+      messages.add(message.getCanonicalName());
+    }
+  }
+
+  private void createEnum(String enumName, List<String> enums) {
+    if (!messages.add(enumName)) {
+      // already created
+      return;
+    }
+
+    appendLine(msgStringBuilder, "enum %s {", enumName);
+    for (int idx = 0; idx < enums.size(); idx++) {
+      if (isValidEnum(enums.get(idx))) {
+        appendLine(msgStringBuilder, "  %s =%d;", enums.get(idx), idx);
+      } else {
+        throw new IllegalStateException(
+            String.format("enum class [%s] name [%s] not supported by protobuffer.", enumName, enums.get(idx)));
+      }
+    }
+    appendLine(msgStringBuilder, "}");
+  }
+
+  public static boolean isValidEnum(String name) {
+    return !name.contains(".") && !name.contains("-");
+  }
+
+  private String tryFindEnumType(List<String> enums) {
+    if (enums != null && !enums.isEmpty()) {
+      String strEnums = enums.toString();
+      String enumName = "Enum_" + Hashing.sha256().hashString(strEnums, StandardCharsets.UTF_8);
+      pending.add(() -> createEnum(enumName, enums));
+      return enumName;
+    }
+    return null;
+  }
+
+  private String findBaseType(String swaggerType, String swaggerFmt) {
+    String key = swaggerType + ":" + swaggerFmt;
+    return switch (key) {
+      case "boolean:null" -> "bool";
+      case "integer:null", "integer:int64" -> "int64";
+      case "integer:int32" -> "int32";
+      case "number:null", "number:double" -> "double";
+      case "number:float" -> "float";
+      case "string:null" -> "string";
+      case "string:byte" -> "bytes";
+      case "string:date", "string:date-time" -> "int64";
+      case "string:binary" -> throw new IllegalArgumentException("proto buffer not support file upload/download");
+      default -> null;
+    };
+  }
+
+  private String convertArrayOrMapItem(Schema<?> itemProperty) {
+    // List<List<>>, need to wrap
+    if (itemProperty.getItems() != null) {
+      String protoName = generateWrapPropertyName(List.class.getSimpleName(), itemProperty.getItems());
+      pending.add(() -> wrapPropertyToMessage(protoName, itemProperty));
+      return protoName;
+    }
+
+    // List<Map<>>, need to wrap
+    if (itemProperty.getAdditionalItems() != null) {
+      String protoName = generateWrapPropertyName(Map.class.getSimpleName(), itemProperty.getAdditionalItems());
+      pending.add(() -> wrapPropertyToMessage(protoName, itemProperty));
+      return protoName;
+    }
+
+    return convertSwaggerType(itemProperty);
+  }
+
+
+  private String generateWrapPropertyName(String prefix, Schema<?> property) {
+    // List<List<>>, need to wrap
+    if (property.getItems() != null) {
+      return generateWrapPropertyName(prefix + List.class.getSimpleName(), property.getItems());
+    }
+
+    // List<Map<>>, need to wrap
+    if (property.getAdditionalItems() != null) {
+      return generateWrapPropertyName(prefix + Map.class.getSimpleName(), property.getAdditionalItems());
+    }
+
+    // message name cannot have . (package separator)
+    return prefix + StringUtils.capitalize(escapeMessageName(convertSwaggerType(property)));
+  }
+
+  public static String escapeMessageName(String name) {
+    return name.replaceAll("\\.", "_");
+  }
+
+
+  private void wrapPropertyToMessage(String protoName, Schema<?> property) {
+    createMessage(protoName, Collections.singletonMap("value", property), ProtoConst.ANNOTATION_WRAP_PROPERTY);
+  }
+
+  private void createMessage(String protoName, Map<String, Schema> properties, String... annotations) {
+    if (!messages.add(protoName)) {
+      // already created
+      return;
+    }
+
+    for (String annotation : annotations) {
+      msgStringBuilder.append("//");
+      appendLine(msgStringBuilder, annotation);
+    }
+    appendLine(msgStringBuilder, "message %s {", protoName);
+    int tag = 1;
+    for (Entry<String, Schema> entry : properties.entrySet()) {
+      Schema property = entry.getValue();
+      String propertyType = convertSwaggerType(property);
+
+      appendLine(msgStringBuilder, "  %s %s = %d;", propertyType, entry.getKey(), tag);
+      tag++;
+    }
+    appendLine(msgStringBuilder, "}");
+  }
+}
diff --git a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ScopedProtobufSchemaManager.java b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ScopedProtobufSchemaManager.java
index 0df295d84..7cb40114e 100644
--- a/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ScopedProtobufSchemaManager.java
+++ b/common/common-protobuf/src/main/java/org/apache/servicecomb/codec/protobuf/utils/ScopedProtobufSchemaManager.java
@@ -19,14 +19,18 @@ package org.apache.servicecomb.codec.protobuf.utils;
 
 import java.util.Map;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.servicecomb.codec.protobuf.internal.converter.SwaggerToProtoGenerator;
+import org.apache.servicecomb.codec.protobuf.schema.SchemaToProtoGenerator;
 import org.apache.servicecomb.core.definition.SchemaMeta;
 import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
 import org.apache.servicecomb.foundation.protobuf.ProtoMapper;
 import org.apache.servicecomb.foundation.protobuf.ProtoMapperFactory;
+import org.apache.servicecomb.swagger.SwaggerUtils;
 
 import io.protostuff.compiler.model.Proto;
 import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.media.Schema;
 
 /**
  * Manage swagger -> protoBuffer mappings.
@@ -35,9 +39,46 @@ import io.swagger.v3.oas.models.OpenAPI;
  * for each MicroserviceMeta.
  */
 public class ScopedProtobufSchemaManager {
+  static class SchemaKey {
+    String schemaId;
+
+    Schema<?> schema;
+
+    int hashCode = -1;
+
+    SchemaKey(String schemaId, Schema<?> schema) {
+      this.schemaId = schemaId;
+      this.schema = schema;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      SchemaKey other = (SchemaKey) o;
+      return StringUtils.equals(schemaId, other.schemaId)
+          && SwaggerUtils.schemaEquals(schema, other.schema);
+    }
+
+    @Override
+    public int hashCode() {
+      if (hashCode != -1) {
+        return hashCode;
+      }
+      hashCode = schemaId.hashCode() ^ SwaggerUtils.schemaHashCode(schema);
+      return hashCode;
+    }
+  }
+
   // Because this class belongs to each SchemaMeta, the key is the schema id.
   private final Map<String, ProtoMapper> mapperCache = new ConcurrentHashMapEx<>();
 
+  private final Map<SchemaKey, ProtoMapper> schemaMapperCache = new ConcurrentHashMapEx<>();
+
   public ScopedProtobufSchemaManager() {
 
   }
@@ -55,4 +96,18 @@ public class ScopedProtobufSchemaManager {
       return protoMapperFactory.create(proto);
     });
   }
+
+  /**
+   * get the ProtoMapper from Schema
+   */
+  public ProtoMapper getOrCreateProtoMapper(OpenAPI openAPI, String schemaId, String name, Schema<?> schema) {
+    SchemaKey schemaKey = new SchemaKey(schemaId, schema);
+    return schemaMapperCache.computeIfAbsent(schemaKey, key -> {
+      SchemaToProtoGenerator generator = new SchemaToProtoGenerator("scb.schema", openAPI,
+          key.schema, name);
+      Proto proto = generator.convert();
+      ProtoMapperFactory protoMapperFactory = new ProtoMapperFactory();
+      return protoMapperFactory.create(proto);
+    });
+  }
 }
diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaCodec.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaCodec.java
new file mode 100644
index 000000000..a68ac1a1c
--- /dev/null
+++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaCodec.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.servicecomb.codec.protobuf.schema;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.servicecomb.codec.protobuf.utils.ScopedProtobufSchemaManager;
+import org.apache.servicecomb.foundation.protobuf.ProtoMapper;
+import org.apache.servicecomb.foundation.protobuf.RootDeserializer;
+import org.apache.servicecomb.foundation.protobuf.RootSerializer;
+import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper;
+import org.junit.jupiter.api.Test;
+
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.media.ObjectSchema;
+import io.swagger.v3.oas.models.media.StringSchema;
+
+public class TestSchemaCodec {
+  ScopedProtobufSchemaManager manager = new ScopedProtobufSchemaManager();
+
+  @Test
+  public void test_string_schema_codec() throws Exception {
+    OpenAPI openAPI = new OpenAPI();
+    StringSchema schema = new StringSchema();
+    ProtoMapper protoMapper = manager.getOrCreateProtoMapper(openAPI, "test", "input", schema);
+    RootSerializer serializer = protoMapper.getSerializerSchemaManager()
+        .createRootSerializer(protoMapper.getProto().getMessage("input"),
+            String.class);
+    Map<String, Object> arguments = new HashMap<>();
+    arguments.put("value", "abcdefg");
+    byte[] result = serializer.serialize(arguments);
+    RootDeserializer<PropertyWrapper<String>> deserializer = protoMapper.getDeserializerSchemaManager()
+        .createRootDeserializer(protoMapper.getProto().getMessage("input"), String.class);
+    PropertyWrapper<String> deserializedResult = deserializer.deserialize(result);
+    assertEquals("abcdefg", deserializedResult.getValue());
+  }
+
+  public static class User {
+    public String name;
+  }
+
+  @Test
+  public void test_object_schema_codec() throws Exception {
+    OpenAPI openAPI = new OpenAPI();
+
+    ObjectSchema schema = new ObjectSchema();
+    schema.setName("User");
+    schema.addProperty("name", new StringSchema());
+    openAPI.setComponents(new Components());
+    openAPI.getComponents().addSchemas("User", schema);
+
+    ObjectSchema ref = new ObjectSchema();
+    ref.set$ref(Components.COMPONENTS_SCHEMAS_REF + "User");
+
+    ProtoMapper protoMapper = manager.getOrCreateProtoMapper(openAPI, "test", "input", ref);
+    RootSerializer serializer = protoMapper.getSerializerSchemaManager()
+        .createRootSerializer(protoMapper.getProto().getMessage("input"),
+            User.class);
+    Map<String, Object> arguments = new HashMap<>();
+    User user = new User();
+    user.name = "abcdefg";
+    arguments.put("value", user);
+    byte[] result = serializer.serialize(arguments);
+    RootDeserializer<PropertyWrapper<User>> deserializer = protoMapper.getDeserializerSchemaManager()
+        .createRootDeserializer(protoMapper.getProto().getMessage("input"), User.class);
+    PropertyWrapper<User> deserializedResult = deserializer.deserialize(result);
+    assertEquals("abcdefg", deserializedResult.getValue().name);
+  }
+}
diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaToProtoGenerator.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaToProtoGenerator.java
new file mode 100644
index 000000000..c1b5f029a
--- /dev/null
+++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaToProtoGenerator.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.servicecomb.codec.protobuf.schema;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.apache.servicecomb.codec.protobuf.internal.converter.ProtoToStringGenerator;
+import org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGenerator;
+import org.junit.jupiter.api.Test;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import io.protostuff.compiler.model.Proto;
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.media.ObjectSchema;
+import io.swagger.v3.oas.models.media.StringSchema;
+import jakarta.ws.rs.core.MediaType;
+
+@SuppressWarnings("unused")
+public class TestSchemaToProtoGenerator {
+  @Test
+  public void test_string_schema_is_correct() {
+    OpenAPI openAPI = new OpenAPI();
+    StringSchema schema = new StringSchema();
+    SchemaToProtoGenerator generator =
+        new SchemaToProtoGenerator("test.string", openAPI, schema, "input");
+    Proto proto = generator.convert();
+    assertEquals("""
+        syntax = "proto3";
+        package test.string;
+
+        //@WrapProperty
+        message input {
+          string value = 1;
+        }
+
+        """, new ProtoToStringGenerator(proto).protoToString());
+  }
+
+  @Test
+  public void test_object_schema_is_correct() {
+    OpenAPI openAPI = new OpenAPI();
+
+    ObjectSchema schema = new ObjectSchema();
+    schema.setName("User");
+    schema.addProperty("name", new StringSchema());
+    openAPI.setComponents(new Components());
+    openAPI.getComponents().addSchemas("User", schema);
+
+    ObjectSchema ref = new ObjectSchema();
+    ref.set$ref(Components.COMPONENTS_SCHEMAS_REF + "User");
+
+    SchemaToProtoGenerator generator =
+        new SchemaToProtoGenerator("test.object", openAPI, ref, "input");
+    Proto proto = generator.convert();
+    assertEquals("""
+        syntax = "proto3";
+        package test.object;
+
+        message User {
+          string name = 1;
+        }
+
+        //@WrapProperty
+        message input {
+          User value = 1;
+        }
+
+        """, new ProtoToStringGenerator(proto).protoToString());
+  }
+
+  static class Model {
+    public String name;
+
+    public int age;
+  }
+
+  interface SpringMvcSchema {
+    @PostMapping("/testInt")
+    int testInt(@RequestBody int param);
+
+    @PostMapping("/testModel")
+    Model testModel(@RequestBody Model model);
+  }
+
+  @Test
+  public void test_springmvc_int_schema_correct() {
+    SpringmvcSwaggerGenerator generator = new SpringmvcSwaggerGenerator(SpringMvcSchema.class);
+    OpenAPI openAPI = generator.generate();
+
+    SchemaToProtoGenerator protoGenerator =
+        new SchemaToProtoGenerator("test.int", openAPI,
+            openAPI.getPaths().get("/testInt").getPost()
+                .getRequestBody().getContent().get(MediaType.APPLICATION_JSON)
+                .getSchema(), "testIntRequest");
+    Proto proto = protoGenerator.convert();
+    assertEquals("""
+        syntax = "proto3";
+        package test.int;
+                
+        //@WrapProperty
+        message testIntRequest {
+          int32 value = 1;
+        }
+
+        """, new ProtoToStringGenerator(proto).protoToString());
+
+    protoGenerator =
+        new SchemaToProtoGenerator("test.int", openAPI,
+            openAPI.getPaths().get("/testInt").getPost()
+                .getResponses().get("200").getContent().get(MediaType.APPLICATION_JSON)
+                .getSchema(), "testIntResponse");
+    proto = protoGenerator.convert();
+    assertEquals("""
+        syntax = "proto3";
+        package test.int;
+                
+        //@WrapProperty
+        message testIntResponse {
+          int32 value = 1;
+        }
+
+        """, new ProtoToStringGenerator(proto).protoToString());
+  }
+
+
+  @Test
+  public void test_springmvc_model_schema_correct() {
+    SpringmvcSwaggerGenerator generator = new SpringmvcSwaggerGenerator(SpringMvcSchema.class);
+    OpenAPI openAPI = generator.generate();
+
+    SchemaToProtoGenerator protoGenerator =
+        new SchemaToProtoGenerator("test.model", openAPI,
+            openAPI.getPaths().get("/testModel").getPost()
+                .getRequestBody().getContent().get(MediaType.APPLICATION_JSON)
+                .getSchema(), "testModelRequest");
+    Proto proto = protoGenerator.convert();
+    assertEquals("""
+        syntax = "proto3";
+        package test.model;
+                
+        message Model {
+          string name = 1;
+          int32 age = 2;
+        }
+                
+        //@WrapProperty
+        message testModelRequest {
+          Model value = 1;
+        }
+
+        """, new ProtoToStringGenerator(proto).protoToString());
+
+    protoGenerator =
+        new SchemaToProtoGenerator("test.model", openAPI,
+            openAPI.getPaths().get("/testModel").getPost()
+                .getResponses().get("200").getContent().get(MediaType.APPLICATION_JSON)
+                .getSchema(), "testIntResponse");
+    proto = protoGenerator.convert();
+    assertEquals("""
+        syntax = "proto3";
+        package test.model;
+                
+        message Model {
+          string name = 1;
+          int32 age = 2;
+        }
+                
+        //@WrapProperty
+        message testIntResponse {
+          Model value = 1;
+        }
+
+        """, new ProtoToStringGenerator(proto).protoToString());
+  }
+}
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java
index bf9aa56b8..b8da1ed61 100644
--- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java
@@ -239,7 +239,7 @@ public final class SwaggerUtils {
           if (!componentSchemas.containsKey(entry.getKey())) {
             componentSchemas.put(entry.getKey(), entry.getValue());
           } else {
-            if (!entry.getValue().equals(componentSchemas.get(entry.getKey()))) {
+            if (!schemaEquals(entry.getValue(), componentSchemas.get(entry.getKey()))) {
               throw new IllegalArgumentException("duplicate param model: " + entry.getKey());
             }
           }
@@ -250,6 +250,65 @@ public final class SwaggerUtils {
     return resolvedSchema.schema;
   }
 
+  // swagger api equals method will compare Map address(extensions)
+  // and is not applicable for usage.
+  public static int schemaHashCode(Schema<?> schema) {
+    int result = schema.getType() != null ? schema.getType().hashCode() : 0;
+    result = result ^ (schema.getFormat() != null ? schema.getFormat().hashCode() : 0);
+    result = result ^ (schema.getName() != null ? schema.getName().hashCode() : 0);
+    result = result ^ (schema.get$ref() != null ? schema.get$ref().hashCode() : 0);
+    result = result ^ (schema.getItems() != null ? schemaHashCode(schema.getItems()) : 0);
+    result = result ^ (schema.getAdditionalItems() != null ? schemaHashCode(schema.getAdditionalItems()) : 0);
+    result = result ^ (schema.getProperties() != null ? propertiesHashCode(schema.getProperties()) : 0);
+    return result;
+  }
+
+  private static int propertiesHashCode(Map<String, Schema> properties) {
+    int result = 0;
+    for (Entry<String, Schema> entry : properties.entrySet()) {
+      result = result ^ (entry.getKey().hashCode() ^ schemaHashCode(entry.getValue()));
+    }
+    return result;
+  }
+
+  // swagger api equals method will compare Map address(extensions)
+  // and is not applicable for usage.
+  public static boolean schemaEquals(Schema<?> schema1, Schema<?> schema2) {
+    if (schema1 == null && schema2 == null) {
+      return true;
+    }
+    if (schema1 == null || schema2 == null) {
+      return false;
+    }
+    return StringUtils.equals(schema1.getType(), schema2.getType())
+        && StringUtils.equals(schema1.getFormat(), schema2.getFormat())
+        && StringUtils.equals(schema1.getName(), schema2.getName())
+        && StringUtils.equals(schema1.get$ref(), schema2.get$ref())
+        && schemaEquals(schema1.getItems(), schema2.getItems())
+        && schemaEquals(schema1.getAdditionalItems(), schema2.getAdditionalItems())
+        && propertiesEquals(schema1.getProperties(), schema2.getProperties());
+  }
+
+  public static boolean propertiesEquals(Map<String, Schema> properties1, Map<String, Schema> properties2) {
+    if (properties1 == null && properties2 == null) {
+      return true;
+    }
+    if (properties1 == null || properties2 == null) {
+      return false;
+    }
+    if (properties1.size() != properties2.size()) {
+      return false;
+    }
+    boolean result = true;
+    for (String key : properties1.keySet()) {
+      if (!schemaEquals(properties1.get(key), properties2.get(key))) {
+        result = false;
+        break;
+      }
+    }
+    return result;
+  }
+
   public static Schema getSchema(OpenAPI swagger, String ref) {
     return swagger.getComponents().getSchemas().get(ref.substring(Components.COMPONENTS_SCHEMAS_REF.length()));
   }
@@ -310,11 +369,6 @@ public final class SwaggerUtils {
     return (T) vendorExtensions.get(key);
   }
 
-  public static boolean isBean(RequestBody body) {
-    MediaType type = body.getContent().values().iterator().next();
-    return type.getSchema().get$ref() != null;
-  }
-
   public static boolean isBean(Type type) {
     if (type == null) {
       return false;
@@ -362,23 +416,6 @@ public final class SwaggerUtils {
     }
   }
 
-  public static void updateConsumes(Operation operation, String[] consumes) {
-    if (consumes == null || consumes.length == 0) {
-      return;
-    }
-    if (operation.getRequestBody() == null) {
-      operation.setRequestBody(new RequestBody());
-    }
-    if (operation.getRequestBody().getContent() == null) {
-      operation.getRequestBody().setContent(new Content());
-    }
-    for (String consume : consumes) {
-      if (operation.getRequestBody().getContent().get(consume) == null) {
-        operation.getRequestBody().getContent().addMediaType(consume, new MediaType());
-      }
-    }
-  }
-
   public static boolean methodExists(PathItem pathItem, String httpMethod) {
     PathItem.HttpMethod method = PathItem.HttpMethod.valueOf(httpMethod);
     return switch (method) {


[servicecomb-java-chassis] 02/06: [SCB-2803]add request proto-buffer codec

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 3d4c0b071ca676e20d8c4f65bb664fcb65081fc0
Author: liubao <bi...@qq.com>
AuthorDate: Mon Aug 21 20:18:37 2023 +0800

    [SCB-2803]add request proto-buffer codec
---
 common/common-protobuf/pom.xml                     |   4 -
 common/common-rest/pom.xml                         |   4 +
 .../rest/codec/param/BodyProcessorCreator.java     | 184 ++++++++++++++++-----
 .../rest/codec/param/CookieProcessorCreator.java   |   4 +-
 .../rest/codec/param/FormProcessorCreator.java     |   4 +-
 .../rest/codec/param/HeaderProcessorCreator.java   |   4 +-
 .../codec/param/ParamValueProcessorCreator.java    |   5 +-
 .../rest/codec/param/PathProcessorCreator.java     |   4 +-
 .../rest/codec/param/QueryProcessorCreator.java    |   4 +-
 .../common/rest/definition/RestOperationMeta.java  |   4 +-
 .../common/rest/definition/RestParam.java          |  18 +-
 .../common/rest/codec/TestRestCodec.java           |   2 +-
 .../common/rest/codec/param/TestBodyProcessor.java |  48 +++---
 .../rest/codec/param/TestBodyProcessorCreator.java |   4 +-
 .../codec/param/TestCookieProcessorCreator.java    |   2 +-
 .../rest/codec/param/TestFormProcessorCreator.java |   2 +-
 .../codec/param/TestHeaderProcessorCreator.java    |   2 +-
 .../rest/codec/param/TestPathProcessorCreator.java |   2 +-
 .../codec/param/TestQueryProcessorCreator.java     |   4 +-
 .../common/rest/definition/TestPath.java           |   6 +-
 .../definition/path/QueryVarParamWriterTest.java   |   6 +-
 .../rest/definition/path/URLPathBuilderTest.java   |   2 +-
 .../parameter/RawJsonRequestBodyProcessor.java     |   6 +
 .../src/test/resources/schemas/echo.yaml           |   3 -
 .../src/test/resources/schemas/echo.yaml           |   3 -
 25 files changed, 228 insertions(+), 103 deletions(-)

diff --git a/common/common-protobuf/pom.xml b/common/common-protobuf/pom.xml
index 08e2a9a02..b94386e03 100644
--- a/common/common-protobuf/pom.xml
+++ b/common/common-protobuf/pom.xml
@@ -31,10 +31,6 @@
       <groupId>org.apache.servicecomb</groupId>
       <artifactId>java-chassis-core</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.apache.servicecomb</groupId>
-      <artifactId>swagger-invocation-core</artifactId>
-    </dependency>
 
     <dependency>
       <groupId>org.apache.servicecomb</groupId>
diff --git a/common/common-rest/pom.xml b/common/common-rest/pom.xml
index 1233e8fed..d9202f5be 100644
--- a/common/common-rest/pom.xml
+++ b/common/common-rest/pom.xml
@@ -34,6 +34,10 @@
       <groupId>org.apache.servicecomb</groupId>
       <artifactId>java-chassis-core</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.servicecomb</groupId>
+      <artifactId>common-protobuf</artifactId>
+    </dependency>
 
     <dependency>
       <groupId>io.vertx</groupId>
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
index 4c58902eb..dd177a31c 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
@@ -21,16 +21,26 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Type;
 import java.nio.charset.StandardCharsets;
-import java.util.Locale;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.http.entity.ContentType;
+import org.apache.servicecomb.codec.protobuf.utils.ScopedProtobufSchemaManager;
 import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.common.rest.codec.RestClientRequest;
 import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import org.apache.servicecomb.core.definition.MicroserviceMeta;
+import org.apache.servicecomb.core.definition.OperationMeta;
+import org.apache.servicecomb.foundation.protobuf.ProtoMapper;
+import org.apache.servicecomb.foundation.protobuf.RootDeserializer;
+import org.apache.servicecomb.foundation.protobuf.RootSerializer;
+import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper;
 import org.apache.servicecomb.foundation.vertx.stream.BufferOutputStream;
 import org.apache.servicecomb.swagger.SwaggerUtils;
-import org.apache.servicecomb.swagger.converter.ConverterMgr;
 import org.apache.servicecomb.swagger.generator.SwaggerConst;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.slf4j.Logger;
@@ -43,7 +53,7 @@ import com.fasterxml.jackson.databind.type.SimpleType;
 import com.fasterxml.jackson.databind.type.TypeFactory;
 import com.netflix.config.DynamicPropertyFactory;
 
-import io.swagger.v3.oas.models.media.Schema;
+import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.parameters.RequestBody;
 import io.vertx.core.buffer.Buffer;
 import io.vertx.core.buffer.impl.BufferImpl;
@@ -56,6 +66,8 @@ import jakarta.ws.rs.core.Response.Status;
 public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestBody> {
   private static final Logger LOGGER = LoggerFactory.getLogger(BodyProcessorCreator.class);
 
+  public static final String EXT_ID = "protobuf";
+
   public static final String PARAM_TYPE = "body";
 
   private static final JavaType OBJECT_TYPE = SimpleType.constructUnsafe(Object.class);
@@ -64,6 +76,8 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
   private static final boolean decodeAsObject = DynamicPropertyFactory.getInstance()
       .getBooleanProperty("servicecomb.rest.parameter.decodeAsObject", false).get();
 
+  private static final Object LOCK = new Object();
+
   public static class BodyProcessor implements ParamValueProcessor {
     protected JavaType targetType;
 
@@ -71,21 +85,57 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
 
     protected boolean isRequired;
 
-    public BodyProcessor(JavaType targetType, boolean isString, boolean isRequired) {
-      this(targetType, null, isString, isRequired);
-    }
+    protected OpenAPI openAPI;
 
-    public BodyProcessor(JavaType targetType, String serialViewClass, boolean isString, boolean isRequired) {
-      if (!StringUtils.isEmpty(serialViewClass)) {
+    protected ScopedProtobufSchemaManager scopedProtobufSchemaManager;
+
+    protected List<String> supportedContentTypes = new ArrayList<>();
+
+    protected OperationMeta operationMeta;
+
+    protected RequestBody requestBody;
+
+    public BodyProcessor(OperationMeta operationMeta, JavaType targetType, RequestBody parameter) {
+      if (!StringUtils.isEmpty((String) parameter.getExtensions()
+          .get(SwaggerConst.EXT_JSON_VIEW))) {
         try {
-          this.serialViewClass = Class.forName(serialViewClass);
+          this.serialViewClass = Class.forName((String) parameter.getExtensions()
+              .get(SwaggerConst.EXT_JSON_VIEW));
         } catch (Throwable e) {
           //ignore
           LOGGER.warn("Failed to create body processor {}, annotation @JsonView may be invalid", serialViewClass, e);
         }
       }
+
+      this.requestBody = new RequestBody();
       this.targetType = targetType;
-      this.isRequired = isRequired;
+      this.isRequired = parameter.getRequired() != null && parameter.getRequired();
+      if (parameter.getContent() != null) {
+        supportedContentTypes.addAll(parameter.getContent().keySet());
+      }
+
+      if (operationMeta != null) {
+        this.operationMeta = operationMeta;
+        this.openAPI = operationMeta.getSchemaMeta().getSwagger();
+        if (supportedContentTypes.contains(SwaggerConst.PROTOBUF_TYPE)) {
+          this.scopedProtobufSchemaManager = getOrCreateScopedProtobufSchemaManager(
+              operationMeta.getMicroserviceMeta());
+        }
+      }
+    }
+
+    private ScopedProtobufSchemaManager getOrCreateScopedProtobufSchemaManager(MicroserviceMeta microserviceMeta) {
+      ScopedProtobufSchemaManager scopedProtobufSchemaManager = microserviceMeta.getExtData(EXT_ID);
+      if (scopedProtobufSchemaManager == null) {
+        synchronized (LOCK) {
+          scopedProtobufSchemaManager = microserviceMeta.getExtData(EXT_ID);
+          if (scopedProtobufSchemaManager == null) {
+            scopedProtobufSchemaManager = new ScopedProtobufSchemaManager();
+            microserviceMeta.putExtData(EXT_ID, scopedProtobufSchemaManager);
+          }
+        }
+      }
+      return scopedProtobufSchemaManager;
     }
 
     @Override
@@ -109,10 +159,9 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
       }
 
       // edge support convert from form-data or x-www-form-urlencoded to json automatically
-      String contentType = request.getContentType();
-      contentType = contentType == null ? "" : contentType.toLowerCase(Locale.US);
-      if (contentType.startsWith(MediaType.MULTIPART_FORM_DATA)
-          || contentType.startsWith(MediaType.APPLICATION_FORM_URLENCODED)) {
+      String contentType = parseContentType(request);
+      if (contentType.equals(MediaType.MULTIPART_FORM_DATA)
+          || contentType.equals(MediaType.APPLICATION_FORM_URLENCODED)) {
         return convertValue(request.getParameterMap(), targetType);
       }
 
@@ -124,10 +173,25 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
         return null;
       }
 
-      if (!contentType.isEmpty() && !contentType.startsWith(MediaType.APPLICATION_JSON)) {
-        // TODO: we should consider body encoding
-        return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
+      if (!supportedContentTypes.contains(contentType)) {
+        throw new IllegalArgumentException(String.format("operation %s not support content-type %s",
+            operationMeta.getSchemaQualifiedName(), contentType));
+      }
+
+      if (SwaggerConst.PROTOBUF_TYPE.equals(contentType)) {
+        String messageName = (String) requestBody.getContent().get(SwaggerConst.PROTOBUF_TYPE).getExtensions()
+            .get(SwaggerConst.EXT_BODY_NAME);
+        ProtoMapper protoMapper = scopedProtobufSchemaManager
+            .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(),
+                messageName,
+                requestBody.getContent().get(SwaggerConst.PROTOBUF_TYPE).getSchema());
+        RootDeserializer<PropertyWrapper<Object>> deserializer = protoMapper.getDeserializerSchemaManager()
+            .createRootDeserializer(protoMapper.getProto().getMessage(messageName), targetType);
+        PropertyWrapper<Object> result = deserializer.deserialize(inputStream.readAllBytes());
+        return result.getValue();
       }
+
+      // For application/json and text/plain
       try {
         ObjectReader reader = serialViewClass != null
             ? RestObjectMapperFactory.getRestObjectMapper().readerWithView(serialViewClass)
@@ -147,6 +211,21 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
       }
     }
 
+    private String parseContentType(HttpServletRequest request) {
+      String type = request.getContentType();
+      if (StringUtils.isEmpty(type)) {
+        if (supportedContentTypes.size() == 0) {
+          throw new IllegalArgumentException("operation do not have any content type support.");
+        }
+        if (supportedContentTypes.contains(MediaType.APPLICATION_JSON)) {
+          return MediaType.APPLICATION_JSON;
+        }
+        return supportedContentTypes.get(0);
+      }
+      ContentType contentType = ContentType.parse(type);
+      return contentType.getMimeType();
+    }
+
     @Override
     public void setValue(RestClientRequest clientRequest, Object arg) throws Exception {
       ensureContentType(clientRequest);
@@ -160,13 +239,22 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
      * Deserialize body object into body buffer, according to the Content-Type.
      */
     private Buffer createBodyBuffer(String contentType, Object arg) throws IOException {
-      if (MediaType.TEXT_PLAIN.equals(contentType)) {
-        if (!(arg instanceof String)) {
-          throw new IllegalArgumentException("Content-Type is text/plain while arg type is not String");
-        }
-        return new BufferImpl().appendBytes(((String) arg).getBytes(StandardCharsets.UTF_8));
+      if (SwaggerConst.PROTOBUF_TYPE.equals(contentType)) {
+        String messageName = (String) requestBody.getContent().get(SwaggerConst.PROTOBUF_TYPE).getExtensions()
+            .get(SwaggerConst.EXT_BODY_NAME);
+        ProtoMapper protoMapper = scopedProtobufSchemaManager
+            .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(),
+                messageName,
+                requestBody.getContent().get(SwaggerConst.PROTOBUF_TYPE).getSchema());
+        RootSerializer serializer = protoMapper.getSerializerSchemaManager()
+            .createRootSerializer(protoMapper.getProto().getMessage(messageName),
+                targetType);
+        Map<String, Object> bodyArg = new HashMap<>(1);
+        bodyArg.put("value", arg);
+        return new BufferImpl().appendBytes(serializer.serialize(bodyArg));
       }
 
+      // For application/json and text/plain
       try (BufferOutputStream output = new BufferOutputStream()) {
         RestObjectMapperFactory.getConsumerWriterMapper().writeValue(output, arg);
         return output.getBuffer();
@@ -194,13 +282,28 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
     }
   }
 
-  public static class RawJsonBodyProcessor extends BodyProcessor {
-    public RawJsonBodyProcessor(JavaType targetType, boolean isString, boolean isRequired) {
-      this(targetType, null, isString, isRequired);
+  public static class RawJsonBodyProcessor implements ParamValueProcessor {
+    protected JavaType targetType;
+
+    protected Class<?> serialViewClass;
+
+    protected boolean isRequired;
+
+    public RawJsonBodyProcessor(JavaType targetType, boolean isRequired) {
+      this(targetType, null, isRequired);
     }
 
-    public RawJsonBodyProcessor(JavaType targetType, String serialViewClass, boolean isString, boolean isRequired) {
-      super(targetType, serialViewClass, isString, isRequired);
+    public RawJsonBodyProcessor(JavaType targetType, String serialViewClass, boolean isRequired) {
+      if (!StringUtils.isEmpty(serialViewClass)) {
+        try {
+          this.serialViewClass = Class.forName(serialViewClass);
+        } catch (Throwable e) {
+          //ignore
+          LOGGER.warn("Failed to create body processor {}, annotation @JsonView may be invalid", serialViewClass, e);
+        }
+      }
+      this.targetType = targetType;
+      this.isRequired = isRequired;
     }
 
     @Override
@@ -215,7 +318,6 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
         return null;
       }
 
-      // TODO: we should consider body encoding
       return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
     }
 
@@ -227,7 +329,17 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
         return;
       }
 
-      super.setValue(clientRequest, arg);
+      throw new IllegalArgumentException("@RawJsonRequestBody only supports string type.");
+    }
+
+    @Override
+    public String getParameterPath() {
+      return "";
+    }
+
+    @Override
+    public String getProcessorType() {
+      return PARAM_TYPE;
     }
   }
 
@@ -236,23 +348,17 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
   }
 
   @Override
-  public ParamValueProcessor create(String parameterName, RequestBody parameter, Type genericParamType) {
-    String mediaType = parameter.getContent().keySet().iterator().next();
-    Schema model = parameter.getContent().get(mediaType).getSchema();
-    JavaType swaggerType = ConverterMgr.findJavaType(model.getType(), model.getFormat());
-    boolean isString = swaggerType != null && swaggerType.getRawClass().equals(String.class);
-
+  public ParamValueProcessor create(OperationMeta operationMeta, String parameterName,
+      RequestBody parameter, Type genericParamType) {
     JavaType targetType =
         genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType);
     boolean rawJson = SwaggerUtils.isRawJsonType(parameter);
     if (rawJson) {
       return new RawJsonBodyProcessor(targetType, (String) parameter.getExtensions()
-          .get(SwaggerConst.EXT_JSON_VIEW), isString,
+          .get(SwaggerConst.EXT_JSON_VIEW),
           parameter.getRequired() != null && parameter.getRequired());
     }
 
-    return new BodyProcessor(targetType, (String) parameter.getExtensions()
-        .get(SwaggerConst.EXT_JSON_VIEW), isString,
-        parameter.getRequired() != null && parameter.getRequired());
+    return new BodyProcessor(operationMeta, targetType, parameter);
   }
 }
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java
index 4ff9d31a3..9426cc2e2 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java
@@ -22,6 +22,7 @@ import java.util.Objects;
 
 import org.apache.servicecomb.common.rest.codec.RestClientRequest;
 import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 
 import com.fasterxml.jackson.databind.JavaType;
@@ -85,7 +86,8 @@ public class CookieProcessorCreator implements ParamValueProcessorCreator<Parame
   }
 
   @Override
-  public ParamValueProcessor create(String parameterName, Parameter parameter, Type genericParamType) {
+  public ParamValueProcessor create(OperationMeta operationMeta,
+      String parameterName, Parameter parameter, Type genericParamType) {
     JavaType targetType =
         genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType);
     return new CookieProcessor(parameterName, targetType, parameter.getSchema().getDefault(),
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java
index 7721c3f9a..0f7bf6a63 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java
@@ -25,6 +25,7 @@ import java.util.stream.Collectors;
 
 import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.common.rest.codec.RestClientRequest;
+import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
 import org.apache.servicecomb.swagger.generator.SwaggerConst;
 import org.apache.servicecomb.swagger.invocation.converter.Converter;
@@ -100,7 +101,8 @@ public class FormProcessorCreator implements ParamValueProcessorCreator<RequestB
   }
 
   @Override
-  public ParamValueProcessor create(String paramName, RequestBody parameter, Type genericParamType) {
+  public ParamValueProcessor create(OperationMeta operationMeta,
+      String paramName, RequestBody parameter, Type genericParamType) {
     JavaType targetType =
         genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType);
 
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java
index fc70bb009..ab03afd49 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java
@@ -23,6 +23,7 @@ import java.util.Enumeration;
 
 import org.apache.servicecomb.common.rest.codec.RestClientRequest;
 import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -103,7 +104,8 @@ public class HeaderProcessorCreator implements ParamValueProcessorCreator<Parame
   }
 
   @Override
-  public ParamValueProcessor create(String parameterName, Parameter parameter, Type genericParamType) {
+  public ParamValueProcessor create(OperationMeta operationMeta,
+      String parameterName, Parameter parameter, Type genericParamType) {
     JavaType targetType =
         genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType);
     return new HeaderProcessor((HeaderParameter) parameter, targetType);
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessorCreator.java
index 85b408a10..1c3378dc6 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessorCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessorCreator.java
@@ -19,8 +19,11 @@ package org.apache.servicecomb.common.rest.codec.param;
 
 import java.lang.reflect.Type;
 
+import org.apache.servicecomb.core.definition.OperationMeta;
+
 public interface ParamValueProcessorCreator<T> {
-  default ParamValueProcessor create(String paramName, T parameter, Type genericParamType) {
+  default ParamValueProcessor create(OperationMeta operationMeta, String paramName, T parameter,
+      Type genericParamType) {
     throw new IllegalStateException("not implemented");
   }
 }
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java
index 53d60c599..861b7490f 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java
@@ -23,6 +23,7 @@ import java.util.Map;
 
 import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.common.rest.codec.RestClientRequest;
+import org.apache.servicecomb.core.definition.OperationMeta;
 import org.springframework.util.StringUtils;
 
 import com.fasterxml.jackson.databind.JavaType;
@@ -70,7 +71,8 @@ public class PathProcessorCreator implements ParamValueProcessorCreator<Paramete
   }
 
   @Override
-  public ParamValueProcessor create(String parameterName, Parameter parameter, Type genericParamType) {
+  public ParamValueProcessor create(OperationMeta operationMeta,
+      String parameterName, Parameter parameter, Type genericParamType) {
     JavaType targetType =
         genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType);
     return new PathProcessor(parameterName, targetType, parameter.getSchema().getDefault(), true);
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java
index 0874fa31a..1462e413a 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java
@@ -24,6 +24,7 @@ import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.common.rest.codec.RestClientRequest;
 import org.apache.servicecomb.common.rest.codec.query.QueryCodec;
 import org.apache.servicecomb.common.rest.codec.query.QueryCodecsUtils;
+import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 
 import com.fasterxml.jackson.databind.JavaType;
@@ -129,7 +130,8 @@ public class QueryProcessorCreator implements ParamValueProcessorCreator<Paramet
   }
 
   @Override
-  public ParamValueProcessor create(String parameterName, Parameter parameter, Type genericParamType) {
+  public ParamValueProcessor create(OperationMeta operationMeta,
+      String parameterName, Parameter parameter, Type genericParamType) {
     JavaType targetType =
         genericParamType == null ? null : TypeFactory.defaultInstance().constructType(genericParamType);
     return new QueryProcessor((QueryParameter) parameter, targetType);
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java
index 22b48c4ce..764160100 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java
@@ -108,7 +108,7 @@ public class RestOperationMeta {
         Parameter parameter = operation.getParameters().get(swaggerParameterIdx);
         Type type = operationMeta.getSwaggerProducerOperation() != null ? operationMeta.getSwaggerProducerOperation()
             .getSwaggerParameterTypes().get(parameter.getName()) : null;
-        RestParam param = new RestParam(parameter, type);
+        RestParam param = new RestParam(operationMeta, parameter, type);
         addParam(param);
       }
     }
@@ -135,7 +135,7 @@ public class RestOperationMeta {
     Type type = operationMeta.getSwaggerProducerOperation() != null ? operationMeta.getSwaggerProducerOperation()
         .getSwaggerParameterTypes().get(name) : null;
     type = correctFormBodyType(operation.getRequestBody(), type);
-    RestParam param = new RestParam(name, operation.getRequestBody(), formData, type);
+    RestParam param = new RestParam(operationMeta, name, operation.getRequestBody(), formData, type);
     addParam(param);
   }
 
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestParam.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestParam.java
index ef0c9fffb..a2b44674c 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestParam.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestParam.java
@@ -26,6 +26,7 @@ import org.apache.servicecomb.common.rest.codec.param.FormProcessorCreator;
 import org.apache.servicecomb.common.rest.codec.param.ParamValueProcessor;
 import org.apache.servicecomb.common.rest.codec.param.ParamValueProcessorCreator;
 import org.apache.servicecomb.common.rest.codec.param.ParamValueProcessorCreatorManager;
+import org.apache.servicecomb.core.definition.OperationMeta;
 
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.type.TypeFactory;
@@ -41,16 +42,17 @@ public class RestParam {
 
   protected String paramName;
 
-  public RestParam(Parameter parameter, Type genericParamType) {
+  public RestParam(OperationMeta operationMeta, Parameter parameter, Type genericParamType) {
     this.paramName = parameter.getName();
 
-    init(parameter, genericParamType);
+    init(operationMeta, parameter, genericParamType);
   }
 
-  public RestParam(String paramName, RequestBody parameter, boolean isForm, Type genericParamType) {
+  public RestParam(OperationMeta operationMeta,
+      String paramName, RequestBody parameter, boolean isForm, Type genericParamType) {
     this.paramName = paramName;
 
-    init(parameter, isForm, genericParamType);
+    init(operationMeta, parameter, isForm, genericParamType);
   }
 
 
@@ -66,15 +68,15 @@ public class RestParam {
     return paramName;
   }
 
-  protected void init(Parameter parameter, Type genericParamType) {
+  protected void init(OperationMeta operationMeta, Parameter parameter, Type genericParamType) {
     String paramType = parameter.getIn();
     ParamValueProcessorCreator creator =
         ParamValueProcessorCreatorManager.INSTANCE.ensureFindValue(paramType);
 
-    this.setParamProcessor(creator.create(parameter.getName(), parameter, genericParamType));
+    this.setParamProcessor(creator.create(operationMeta, parameter.getName(), parameter, genericParamType));
   }
 
-  protected void init(RequestBody parameter, boolean isForm, Type genericParamType) {
+  protected void init(OperationMeta operationMeta, RequestBody parameter, boolean isForm, Type genericParamType) {
     ParamValueProcessorCreator creator;
     if (isForm) {
       creator =
@@ -84,7 +86,7 @@ public class RestParam {
           ParamValueProcessorCreatorManager.INSTANCE.ensureFindValue(BodyProcessorCreator.PARAM_TYPE);
     }
 
-    this.setParamProcessor(creator.create(this.paramName,
+    this.setParamProcessor(creator.create(operationMeta, this.paramName,
         parameter, genericParamType));
   }
 
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
index dc30986b1..ebbe2975a 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
@@ -60,7 +60,7 @@ public class TestRestCodec {
     Parameter hp = new HeaderParameter();
     hp.setName("header");
     hp.setSchema(new Schema());
-    RestParam restParam = new RestParam(hp, int.class);
+    RestParam restParam = new RestParam(null, hp, int.class);
 
     restOperation = Mockito.mock(RestOperationMeta.class);
     paramList = new ArrayList<>();
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java
index b7c810050..5ad90a83a 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java
@@ -19,18 +19,17 @@ package org.apache.servicecomb.common.rest.codec.param;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
-import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
-
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.ws.rs.core.HttpHeaders;
-import jakarta.ws.rs.core.MediaType;
+import java.util.Set;
 
 import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.common.rest.codec.RestClientRequest;
 import org.apache.servicecomb.common.rest.codec.param.BodyProcessorCreator.BodyProcessor;
 import org.apache.servicecomb.common.rest.codec.param.BodyProcessorCreator.RawJsonBodyProcessor;
+import org.apache.servicecomb.core.definition.OperationMeta;
+import org.apache.servicecomb.core.definition.SchemaMeta;
 import org.apache.servicecomb.foundation.vertx.stream.BufferInputStream;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.junit.jupiter.api.Assertions;
@@ -42,10 +41,16 @@ import com.fasterxml.jackson.databind.type.TypeFactory;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.media.Content;
+import io.swagger.v3.oas.models.parameters.RequestBody;
 import io.vertx.core.MultiMap;
 import io.vertx.core.buffer.Buffer;
 import io.vertx.core.buffer.impl.BufferImpl;
 import io.vertx.core.http.impl.headers.HeadersMultiMap;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MediaType;
 
 
 public class TestBodyProcessor {
@@ -67,11 +72,24 @@ public class TestBodyProcessor {
   String value;
 
   private void createProcessor(Class<?> type) {
-    processor = new BodyProcessor(TypeFactory.defaultInstance().constructType(type), type.equals(String.class), true);
+    OperationMeta operationMeta = Mockito.mock(OperationMeta.class);
+    SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class);
+    OpenAPI openAPI = Mockito.mock(OpenAPI.class);
+    Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta);
+    Mockito.when(schemaMeta.getSwagger()).thenReturn(openAPI);
+    RequestBody requestBody = Mockito.mock(RequestBody.class);
+    Content content = Mockito.mock(Content.class);
+    Mockito.when(requestBody.getContent()).thenReturn(content);
+    Mockito.when(requestBody.getRequired()).thenReturn(true);
+    Set<String> supported = new HashSet<>();
+    supported.add(MediaType.APPLICATION_JSON);
+    supported.add(MediaType.TEXT_PLAIN);
+    Mockito.when(content.keySet()).thenReturn(supported);
+    processor = new BodyProcessor(operationMeta, TypeFactory.defaultInstance().constructType(type), requestBody);
   }
 
   private void createRawJsonProcessor() {
-    processor = new RawJsonBodyProcessor(TypeFactory.defaultInstance().constructType(String.class), true, true);
+    processor = new RawJsonBodyProcessor(TypeFactory.defaultInstance().constructType(String.class), true);
   }
 
   private void createClientRequest() {
@@ -118,7 +136,7 @@ public class TestBodyProcessor {
   @Test
   public void testGetValueTextPlain() throws Exception {
     setupGetValue(String.class);
-    inputBodyByteBuf.writeCharSequence("abc", StandardCharsets.UTF_8);
+    inputBodyByteBuf.writeCharSequence("\"abc\"", StandardCharsets.UTF_8);
 
     Mockito.when(request.getContentType()).thenReturn(MediaType.TEXT_PLAIN);
 
@@ -179,20 +197,6 @@ public class TestBodyProcessor {
     Assertions.assertEquals(value, outputBodyBuffer.toString());
   }
 
-  @Test
-  public void testSetValueTextPlainTypeMismatch() {
-    createClientRequest();
-    createProcessor(String.class);
-    headers.add(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN);
-
-    try {
-      processor.setValue(clientRequest, new Date());
-      Assertions.fail("an exception is expected!");
-    } catch (Exception e) {
-      Assertions.assertEquals(IllegalArgumentException.class, e.getClass());
-      Assertions.assertEquals("Content-Type is text/plain while arg type is not String", e.getMessage());
-    }
-  }
 
   @Test
   public void testGetParameterPath() {
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessorCreator.java
index 15a50f0ef..0de4a04c4 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessorCreator.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessorCreator.java
@@ -42,7 +42,7 @@ public class TestBodyProcessorCreator {
     param.getContent().get(SwaggerConst.DEFAULT_MEDIA_TYPE).setSchema(new Schema());
     param.setExtensions(new HashMap<>());
 
-    ParamValueProcessor processor = creator.create(null, param, String.class);
+    ParamValueProcessor processor = creator.create(null, null, param, String.class);
 
     Assertions.assertEquals(BodyProcessor.class, processor.getClass());
   }
@@ -57,7 +57,7 @@ public class TestBodyProcessorCreator {
     param.getContent().get(SwaggerConst.DEFAULT_MEDIA_TYPE).setSchema(new Schema());
     param.addExtension(SwaggerConst.EXT_RAW_JSON_TYPE, true);
 
-    ParamValueProcessor processor = creator.create(null, param, String.class);
+    ParamValueProcessor processor = creator.create(null, null, param, String.class);
 
     Assertions.assertEquals(RawJsonBodyProcessor.class, processor.getClass());
   }
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessorCreator.java
index df7dd2326..7cae38cd0 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessorCreator.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessorCreator.java
@@ -32,7 +32,7 @@ public class TestCookieProcessorCreator {
     CookieParameter p = new CookieParameter();
     p.setName("p1");
     p.setSchema(new Schema());
-    ParamValueProcessor processor = creator.create(p.getName(), p, String.class);
+    ParamValueProcessor processor = creator.create(null, p.getName(), p, String.class);
 
     Assertions.assertEquals(CookieProcessor.class, processor.getClass());
   }
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessorCreator.java
index 4d82126e4..f2b7b9c39 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessorCreator.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessorCreator.java
@@ -41,7 +41,7 @@ public class TestFormProcessorCreator {
     p.getContent().get(SwaggerConst.FORM_MEDIA_TYPE).setSchema(new Schema());
     p.getContent().get(SwaggerConst.FORM_MEDIA_TYPE).getSchema().setProperties(new HashMap<>());
 
-    ParamValueProcessor processor = creator.create("p1", p, String.class);
+    ParamValueProcessor processor = creator.create(null, "p1", p, String.class);
 
     Assertions.assertEquals(FormProcessor.class, processor.getClass());
   }
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessorCreator.java
index 6ad2418c7..2ea7c3823 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessorCreator.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessorCreator.java
@@ -33,7 +33,7 @@ public class TestHeaderProcessorCreator {
     hp.setName("h1");
     hp.setSchema(new Schema());
 
-    ParamValueProcessor processor = creator.create(hp.getName(), hp, String.class);
+    ParamValueProcessor processor = creator.create(null, hp.getName(), hp, String.class);
 
     Assertions.assertEquals(HeaderProcessor.class, processor.getClass());
   }
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessorCreator.java
index 2a58dc3e3..0f40291c8 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessorCreator.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessorCreator.java
@@ -34,7 +34,7 @@ public class TestPathProcessorCreator {
     parameter.setName("path");
     parameter.setSchema(new Schema());
 
-    ParamValueProcessor processor = creator.create(parameter.getName(), parameter, String.class);
+    ParamValueProcessor processor = creator.create(null, parameter.getName(), parameter, String.class);
 
     Assertions.assertEquals(PathProcessor.class, processor.getClass());
   }
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessorCreator.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessorCreator.java
index e262d3055..6f59823b0 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessorCreator.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessorCreator.java
@@ -38,7 +38,7 @@ public class TestQueryProcessorCreator {
     Parameter parameter = new QueryParameter();
     parameter.setName("query");
     parameter.setSchema(new Schema());
-    ParamValueProcessor processor = creator.create(parameter.getName(), parameter, String.class);
+    ParamValueProcessor processor = creator.create(null, parameter.getName(), parameter, String.class);
 
     Assertions.assertEquals(QueryProcessor.class, processor.getClass());
 
@@ -63,7 +63,7 @@ public class TestQueryProcessorCreator {
     parameter.setName("query");
     parameter.setSchema(new Schema());
 
-    ParamValueProcessor processor = creator.create(parameter.getName(), parameter, String.class);
+    ParamValueProcessor processor = creator.create(null, parameter.getName(), parameter, String.class);
 
     Assertions.assertEquals(QueryProcessor.class, processor.getClass());
 
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestPath.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestPath.java
index 46fdccb5f..51a4cf26e 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestPath.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestPath.java
@@ -101,13 +101,13 @@ public class TestPath {
     Parameter pathParameter = new PathParameter();
     pathParameter.setName("id");
     pathParameter.setSchema(new Schema<>());
-    RestParam oRestParam = new RestParam(pathParameter, int.class);
+    RestParam oRestParam = new RestParam(null, pathParameter, int.class);
     paramMap.put(oRestParam.getParamName(), oRestParam);
 
     Parameter queryParameter = new QueryParameter();
     queryParameter.setName("q");
     queryParameter.setSchema(new Schema<>());
-    oRestParam = new RestParam(queryParameter, String.class);
+    oRestParam = new RestParam(null, queryParameter, String.class);
     paramMap.put(oRestParam.getParamName(), oRestParam);
 
     URLPathBuilder oURLPathBuilder = new URLPathBuilder("/root/{id}", paramMap);
@@ -124,7 +124,7 @@ public class TestPath {
 
     Parameter parameter = new QueryParameter();
     parameter.setSchema(new Schema<>());
-    RestParam restParam = new RestParam(parameter, String.class);
+    RestParam restParam = new RestParam(null, parameter, String.class);
     RestParam spy = Mockito.spy(restParam);
     Mockito.when(spy.getParamName()).thenReturn("queryVar");
     QueryVarParamWriter writer = new QueryVarParamWriter(spy);
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriterTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriterTest.java
index 737319aca..55c69bf60 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriterTest.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/QueryVarParamWriterTest.java
@@ -49,7 +49,7 @@ public class QueryVarParamWriterTest {
     parameter.setStyle(StyleEnum.FORM);
     parameter.setExplode(false);
     queryVarParamWriterCsv = new QueryVarParamWriter(
-        new RestParam(parameter, String[].class));
+        new RestParam(null, parameter, String[].class));
 
     parameter = new QueryParameter();
     parameter.setName("q");
@@ -57,13 +57,13 @@ public class QueryVarParamWriterTest {
     parameter.setStyle(StyleEnum.FORM);
     parameter.setExplode(true);
     queryVarParamWriterMulti = new QueryVarParamWriter(
-        new RestParam(parameter, String[].class));
+        new RestParam(null, parameter, String[].class));
 
     parameter = new QueryParameter();
     parameter.setName("q");
     parameter.setSchema(new Schema());
     queryVarParamWriterDefault = new QueryVarParamWriter(
-        new RestParam(parameter, String[].class));
+        new RestParam(null, parameter, String[].class));
   }
 
   @Test
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilderTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilderTest.java
index 5bd774515..43f2b1396 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilderTest.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/path/URLPathBuilderTest.java
@@ -119,7 +119,7 @@ public class URLPathBuilderTest {
     Parameter parameter = constructor.construct();
     parameter.setName(paramName);
     parameter.setSchema(new Schema());
-    paramMap.put(paramName, new RestParam(parameter, paramType));
+    paramMap.put(paramName, new RestParam(null, parameter, paramType));
   }
 
   interface ParameterConstructor {
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/RawJsonRequestBodyProcessor.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/RawJsonRequestBodyProcessor.java
index 8eb8c6bdc..1d6414436 100644
--- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/RawJsonRequestBodyProcessor.java
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/RawJsonRequestBodyProcessor.java
@@ -17,6 +17,8 @@
 
 package org.apache.servicecomb.swagger.generator.core.processor.parameter;
 
+import java.util.Arrays;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.servicecomb.swagger.extend.annotations.RawJsonRequestBody;
 import org.apache.servicecomb.swagger.generator.OperationGenerator;
@@ -25,6 +27,8 @@ import org.apache.servicecomb.swagger.generator.SwaggerGenerator;
 import org.apache.servicecomb.swagger.generator.SwaggerParameterAnnotationProcessor;
 import org.apache.servicecomb.swagger.generator.core.model.HttpParameterType;
 
+import jakarta.ws.rs.core.MediaType;
+
 public class RawJsonRequestBodyProcessor extends
     SwaggerParameterAnnotationProcessor<RawJsonRequestBody> {
   @Override
@@ -53,5 +57,7 @@ public class RawJsonRequestBodyProcessor extends
 
     parameterGenerator.getParameterGeneratorContext().setRequired(annotation.required());
     parameterGenerator.getParameterGeneratorContext().setRawJson(true);
+    parameterGenerator.getParameterGeneratorContext().updateConsumes(Arrays.asList(MediaType.APPLICATION_JSON,
+        MediaType.TEXT_PLAIN));
   }
 }
diff --git a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/echo.yaml b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/echo.yaml
index 04ba2b2be..d5227f916 100644
--- a/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/echo.yaml
+++ b/swagger/swagger-generator/generator-jaxrs/src/test/resources/schemas/echo.yaml
@@ -480,9 +480,6 @@ paths:
           application/json:
             schema:
               type: string
-          application/protobuf:
-            schema:
-              type: string
           text/plain:
             schema:
               type: string
diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/echo.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/echo.yaml
index 7e70e366c..77cc098d7 100644
--- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/echo.yaml
+++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/echo.yaml
@@ -266,9 +266,6 @@ paths:
           application/json:
             schema:
               type: string
-          application/protobuf:
-            schema:
-              type: string
           text/plain:
             schema:
               type: string


[servicecomb-java-chassis] 05/06: [SCB-2803]add test case for response proto-buffer codec

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 6ad909d9189291a163c9df1fc9e5f3b135831482
Author: liubao <bi...@qq.com>
AuthorDate: Tue Aug 22 20:04:49 2023 +0800

    [SCB-2803]add test case for response proto-buffer codec
---
 .../servicecomb/common/rest/codec/RestCodec.java   |  3 ++-
 .../rest/codec/param/BodyProcessorCreator.java     | 23 ++++++++--------------
 .../codec/produce/ProduceProcessorManager.java     |  2 +-
 .../common/rest/codec/TestRestCodec.java           |  3 ++-
 .../common/rest/codec/param/TestBodyProcessor.java |  2 +-
 .../demo/springmvc/client/TestContentType.java     | 16 ++++++---------
 .../demo/springmvc/server/CodeFirstSpringmvc.java  |  6 ------
 .../springmvc/server/ContentTypeSpringmvc.java     |  2 +-
 .../schemas/CodeFirstSpringmvcForSchema.yaml       |  8 +-------
 ...stractHttpMethodMappingAnnotationProcessor.java | 13 +++++++-----
 .../RequestMappingClassAnnotationProcessor.java    |  8 ++++++++
 11 files changed, 38 insertions(+), 48 deletions(-)

diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java
index 161288b8f..260ac0d4c 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestCodec.java
@@ -23,6 +23,7 @@ import java.util.Map;
 
 import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
 import org.apache.servicecomb.common.rest.definition.RestParam;
+import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 
 import jakarta.servlet.http.HttpServletRequest;
@@ -60,7 +61,7 @@ public final class RestCodec {
                 param.getParamName(),
                 param.getParamProcessor().getProcessorType(),
                 e.getMessage());
-        throw new InvocationException(Status.BAD_REQUEST, message, e);
+        throw new InvocationException(Status.BAD_REQUEST, new CommonExceptionData(message), e);
       }
     }
 
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
index b231f854c..83e46002a 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
@@ -160,7 +160,7 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
       }
 
       // edge support convert from form-data or x-www-form-urlencoded to json automatically
-      String contentType = parseContentType(request);
+      String contentType = validContentType(request.getContentType());
       if (contentType.equals(MediaType.MULTIPART_FORM_DATA)
           || contentType.equals(MediaType.APPLICATION_FORM_URLENCODED)) {
         return convertValue(request.getParameterMap(), targetType);
@@ -216,8 +216,7 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
       }
     }
 
-    private String parseContentType(HttpServletRequest request) {
-      String type = request.getContentType();
+    private String validContentType(String type) {
       if (StringUtils.isEmpty(type)) {
         if (supportedContentTypes.size() == 0) {
           throw new IllegalArgumentException("operation do not have any content type support.");
@@ -233,9 +232,13 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
 
     @Override
     public void setValue(RestClientRequest clientRequest, Object arg) throws Exception {
-      ensureContentType(clientRequest);
+      String userContentType = clientRequest.getHeaders().get(HttpHeaders.CONTENT_TYPE);
+      String contentType = validContentType(userContentType);
+      if (StringUtils.isEmpty(userContentType)) {
+        clientRequest.putHeader(HttpHeaders.CONTENT_TYPE, contentType);
+      }
       if (arg != null) {
-        Buffer buffer = createBodyBuffer(clientRequest.getHeaders().get(HttpHeaders.CONTENT_TYPE), arg);
+        Buffer buffer = createBodyBuffer(contentType, arg);
         clientRequest.write(buffer);
       }
     }
@@ -270,16 +273,6 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
       }
     }
 
-    /**
-     * If the Content-Type has not been set yet, set application/json as default value.
-     */
-    private void ensureContentType(RestClientRequest clientRequest) {
-      if (null == clientRequest.getHeaders()
-          || StringUtils.isEmpty(clientRequest.getHeaders().get(HttpHeaders.CONTENT_TYPE))) {
-        clientRequest.putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
-      }
-    }
-
     @Override
     public String getParameterPath() {
       return "";
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java
index 81302d576..36b9a8c3e 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java
@@ -137,7 +137,7 @@ public final class ProduceProcessorManager extends RegisterManager<String, Map<S
     }
     if (SwaggerConst.PROTOBUF_TYPE.equals(actualAccept)) {
       return new ProduceProtoBufferProcessor(operationMeta,
-          operationMeta.getSchemaMeta().getSwagger(), response.getContent().get(accept).getSchema());
+          operationMeta.getSchemaMeta().getSwagger(), response.getContent().get(actualAccept).getSchema());
     }
     if (MediaType.TEXT_PLAIN.equals(actualAccept)) {
       return findPlainProcessorByViewClass(serialViewClass);
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
index 5e7270a6e..ebbe2975a 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
@@ -27,6 +27,7 @@ import org.apache.servicecomb.common.rest.codec.param.RestClientRequestImpl;
 import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
 import org.apache.servicecomb.common.rest.definition.RestParam;
 import org.apache.servicecomb.core.definition.OperationMeta;
+import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
@@ -159,7 +160,7 @@ public class TestRestCodec {
       success = true;
     } catch (InvocationException e) {
       Assertions.assertEquals(e.getStatusCode(), Status.BAD_REQUEST.getStatusCode());
-      Assertions.assertTrue(((String) e.getErrorData())
+      Assertions.assertTrue(((CommonExceptionData) e.getErrorData()).getMessage()
           .contains("Parameter is not valid for operation"));
     }
     Assertions.assertFalse(success);
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java
index 5ad90a83a..340b7f15c 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestBodyProcessor.java
@@ -136,7 +136,7 @@ public class TestBodyProcessor {
   @Test
   public void testGetValueTextPlain() throws Exception {
     setupGetValue(String.class);
-    inputBodyByteBuf.writeCharSequence("\"abc\"", StandardCharsets.UTF_8);
+    inputBodyByteBuf.writeCharSequence("abc", StandardCharsets.UTF_8);
 
     Mockito.when(request.getContentType()).thenReturn(MediaType.TEXT_PLAIN);
 
diff --git a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java
index 662f153b0..4fa466af3 100644
--- a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java
+++ b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestContentType.java
@@ -51,22 +51,20 @@ public class TestContentType {
     TestMgr.check(
         "testGlobalSetting: name=[from testGlobalSetting], request content-type=[" + MediaType.TEXT_PLAIN + "]",
         responseEntity.getBody());
-    // TODO: ContentTypeSpringmvc should generate consumes and produces TEXT_PLAIN, but now is JSON
-    // will fix later.
-//    TestMgr.check(MediaType.TEXT_PLAIN, extractContentType(responseEntity.getHeaders().getContentType()));
+    TestMgr.check(MediaType.TEXT_PLAIN, extractContentType(responseEntity.getHeaders().getContentType()));
   }
 
   private void testApiOperation() {
     HttpHeaders requestHeaders = new HttpHeaders();
-    requestHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
+    requestHeaders.add(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN);
     CseHttpEntity<String> requestEntity = new CseHttpEntity<>("from testApiOperation", requestHeaders);
     ResponseEntity<String> responseEntity = restTemplate
         .exchange("cse://springmvc/contentTypeSpringmvc/testApiOperation", HttpMethod.POST,
             requestEntity, String.class);
     TestMgr.check(
-        "testApiOperation: name=[from testApiOperation], request content-type=[" + MediaType.APPLICATION_JSON + "]",
+        "testApiOperation: name=[from testApiOperation], request content-type=[" + MediaType.TEXT_PLAIN + "]",
         responseEntity.getBody());
-    TestMgr.check(MediaType.APPLICATION_JSON, extractContentType(responseEntity.getHeaders().getContentType()));
+    TestMgr.check(MediaType.TEXT_PLAIN, extractContentType(responseEntity.getHeaders().getContentType()));
   }
 
   private void testRequestMapping() {
@@ -97,16 +95,14 @@ public class TestContentType {
     TestMgr.check(
         "testRequestMapping: name=[hello:100:[a1, a2]], request content-type=[application/protobuf]",
         responseEntity.getBody());
-    TestMgr.check(MediaType.APPLICATION_JSON, extractContentType(responseEntity.getHeaders().getContentType()));
+    TestMgr.check(SwaggerConst.PROTOBUF_TYPE, extractContentType(responseEntity.getHeaders().getContentType()));
   }
 
   private void testResponseTypeOverwrite() {
     ResponseEntity<String> responseEntity = restTemplate
         .getForEntity("cse://springmvc/contentTypeSpringmvcOverwrite/testResponseTypeOverwrite", String.class);
     TestMgr.check("testResponseTypeOverwrite: OK", responseEntity.getBody());
-    // TODO: ContentTypeSpringmvc should generate consumes and produces TEXT_PLAIN, but now is JSON
-    // will fix later.
-//    TestMgr.check(MediaType.TEXT_PLAIN, extractContentType(responseEntity.getHeaders().getContentType()));
+    TestMgr.check(MediaType.TEXT_PLAIN, extractContentType(responseEntity.getHeaders().getContentType()));
   }
 
   private String extractContentType(org.springframework.http.MediaType mediaType) {
diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java
index 821fed840..71eacd4dc 100644
--- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java
+++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/CodeFirstSpringmvc.java
@@ -36,7 +36,6 @@ import org.apache.servicecomb.demo.compute.GenericParamWithJsonIgnore;
 import org.apache.servicecomb.demo.compute.Person;
 import org.apache.servicecomb.demo.ignore.InputModelForTestIgnore;
 import org.apache.servicecomb.demo.ignore.OutputModelForTestIgnore;
-import org.apache.servicecomb.demo.jaxbbean.JAXBPerson;
 import org.apache.servicecomb.demo.server.User;
 import org.apache.servicecomb.demo.springmvc.decoderesponse.DecodeTestResponse;
 import org.apache.servicecomb.foundation.common.Holder;
@@ -202,11 +201,6 @@ public class CodeFirstSpringmvc {
     return body;
   }
 
-  @RequestMapping(path = "/appXml", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_XML_VALUE)
-  public JAXBPerson appXml(@RequestBody JAXBPerson person) {
-    return person;
-  }
-
   @RequestMapping(path = "/bytes", method = RequestMethod.POST)
   public byte[] bytes(@RequestBody byte[] input) {
     input[0] = (byte) (input[0] + 1);
diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java
index 6626f553c..cd290cb75 100644
--- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java
+++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ContentTypeSpringmvc.java
@@ -50,7 +50,7 @@ public class ContentTypeSpringmvc {
 
   // TODO: 注册中心不会覆盖契约
   @RequestMapping(path = "/testProtoBuffer", method = RequestMethod.POST,
-      consumes = SwaggerConst.PROTOBUF_TYPE, produces = MediaType.APPLICATION_JSON)
+      consumes = SwaggerConst.PROTOBUF_TYPE, produces = SwaggerConst.PROTOBUF_TYPE)
   public String testProtoBuffer(@RequestBody User user, HttpServletRequest request) {
     return String.format("testRequestMapping: name=[%s], request content-type=[%s]",
         user.getName() + ":" + user.getIndex() + ":" +
diff --git a/demo/demo-springmvc/springmvc-server/src/main/resources/schemas/CodeFirstSpringmvcForSchema.yaml b/demo/demo-springmvc/springmvc-server/src/main/resources/schemas/CodeFirstSpringmvcForSchema.yaml
index 9ac86e2f7..59f893152 100644
--- a/demo/demo-springmvc/springmvc-server/src/main/resources/schemas/CodeFirstSpringmvcForSchema.yaml
+++ b/demo/demo-springmvc/springmvc-server/src/main/resources/schemas/CodeFirstSpringmvcForSchema.yaml
@@ -53,10 +53,4 @@ paths:
             application/json:
               schema:
                 type: boolean
-            application/protobuf:
-              schema:
-                type: boolean
-            text/plain:
-              schema:
-                type: boolean
-components: {}
+components: {}
\ No newline at end of file
diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/AbstractHttpMethodMappingAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/AbstractHttpMethodMappingAnnotationProcessor.java
index ed094f1c4..8fe797bbb 100644
--- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/AbstractHttpMethodMappingAnnotationProcessor.java
+++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/AbstractHttpMethodMappingAnnotationProcessor.java
@@ -17,6 +17,8 @@
 
 package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation;
 
+import java.util.Arrays;
+
 import org.apache.servicecomb.swagger.generator.MethodAnnotationProcessor;
 import org.apache.servicecomb.swagger.generator.OperationGenerator;
 import org.springframework.web.bind.annotation.RequestMethod;
@@ -33,11 +35,12 @@ abstract class AbstractHttpMethodMappingAnnotationProcessor<ANNOTATION> implemen
     if (requestMethod != null) {
       operationGenerator.setHttpMethod(requestMethod.name());
     }
-    // TODO: actually is no use to update consumes and produces
-    // Because they are system capabilities.
-//    Operation operation = operationGenerator.getOperation();
-//    SwaggerUtils.updateConsumes(operation, consumes);
-//    SwaggerUtils.updateProduces(operation, produces);
+    if (consumes.length > 0) {
+      operationGenerator.getOperationGeneratorContext().updateConsumes(Arrays.asList(consumes));
+    }
+    if (produces.length > 0) {
+      operationGenerator.getOperationGeneratorContext().updateProduces(Arrays.asList(produces));
+    }
   }
 
   protected void processPath(OperationGenerator operationGenerator, String[] paths) {
diff --git a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessor.java b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessor.java
index 459ada5bd..df18070f9 100644
--- a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessor.java
+++ b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestMappingClassAnnotationProcessor.java
@@ -18,6 +18,7 @@
 package org.apache.servicecomb.swagger.generator.springmvc.processor.annotation;
 
 import java.lang.reflect.Type;
+import java.util.Arrays;
 
 import org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor;
 import org.apache.servicecomb.swagger.generator.SwaggerGenerator;
@@ -37,6 +38,13 @@ public class RequestMappingClassAnnotationProcessor implements ClassAnnotationPr
     // path/value是等同的
     this.processPath(requestMapping.path(), swaggerGenerator);
     this.processPath(requestMapping.value(), swaggerGenerator);
+
+    if (requestMapping.consumes().length > 0) {
+      swaggerGenerator.getSwaggerGeneratorContext().updateConsumes(Arrays.asList(requestMapping.consumes()));
+    }
+    if (requestMapping.produces().length > 0) {
+      swaggerGenerator.getSwaggerGeneratorContext().updateProduces(Arrays.asList(requestMapping.produces()));
+    }
   }
 
   protected void processPath(String[] paths, SwaggerGenerator swaggerGenerator) {


[servicecomb-java-chassis] 04/06: [SCB-2803]add response proto-buffer codec

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit 2607f03314d7fb6e18e0d2f4188783bd56142220
Author: liubao <bi...@qq.com>
AuthorDate: Tue Aug 22 17:33:45 2023 +0800

    [SCB-2803]add response proto-buffer codec
---
 .../common/rest/HttpTransportContext.java          |  11 +-
 .../common/rest/RestProducerInvocationCreator.java |  17 --
 .../rest/RestVertxProducerInvocationCreator.java   |   3 +-
 .../common/rest/VertxHttpTransportContext.java     |   5 +-
 .../rest/codec/param/BodyProcessorCreator.java     |  10 +-
 .../codec/produce/ProduceProcessorManager.java     |  90 +++++-----
 .../codec/produce/ProduceProtoBufferProcessor.java | 107 +++++++++++
 .../codec/produce/ProduceTextPlainProcessor.java   |  23 +--
 .../common/rest/definition/RestOperationMeta.java  | 124 -------------
 .../rest/filter/inner/RestServerCodecFilter.java   |   8 +-
 .../rest/RestProducerInvocationCreatorTest.java    |  39 +----
 .../common/rest/codec/TestRestCodec.java           |   3 +-
 .../produce/TestProduceTextPlainProcessor.java     |   4 +-
 .../rest/definition/TestRestOperationMeta.java     | 195 ---------------------
 .../filter/inner/RestServerCodecFilterTest.java    |  33 ++--
 .../transport/rest/client/RestClientDecoder.java   |   7 +-
 .../RestServletProducerInvocationCreator.java      |   2 +-
 17 files changed, 226 insertions(+), 455 deletions(-)

diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/HttpTransportContext.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/HttpTransportContext.java
index b9c8ea20a..d9b0df27c 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/HttpTransportContext.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/HttpTransportContext.java
@@ -16,7 +16,6 @@
  */
 package org.apache.servicecomb.common.rest;
 
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import org.apache.servicecomb.swagger.invocation.context.TransportContext;
@@ -26,13 +25,9 @@ public class HttpTransportContext implements TransportContext {
 
   private final HttpServletResponseEx responseEx;
 
-  private final ProduceProcessor produceProcessor;
-
-  public HttpTransportContext(HttpServletRequestEx requestEx, HttpServletResponseEx responseEx,
-      ProduceProcessor produceProcessor) {
+  public HttpTransportContext(HttpServletRequestEx requestEx, HttpServletResponseEx responseEx) {
     this.requestEx = requestEx;
     this.responseEx = responseEx;
-    this.produceProcessor = produceProcessor;
   }
 
   public HttpServletRequestEx getRequestEx() {
@@ -42,8 +37,4 @@ public class HttpTransportContext implements TransportContext {
   public HttpServletResponseEx getResponseEx() {
     return responseEx;
   }
-
-  public ProduceProcessor getProduceProcessor() {
-    return produceProcessor;
-  }
 }
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreator.java
index e38f228c7..778f3de4c 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreator.java
@@ -16,9 +16,7 @@
  */
 package org.apache.servicecomb.common.rest;
 
-import static jakarta.ws.rs.core.Response.Status.NOT_ACCEPTABLE;
 import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;
-import static org.apache.servicecomb.core.exception.ExceptionCodes.GENERIC_CLIENT;
 import static org.apache.servicecomb.core.exception.ExceptionCodes.NOT_DEFINED_ANY_SCHEMA;
 
 import java.util.HashMap;
@@ -26,7 +24,6 @@ import java.util.Map;
 import java.util.concurrent.CompletableFuture;
 
 import javax.annotation.Nonnull;
-import jakarta.ws.rs.core.HttpHeaders;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
@@ -46,7 +43,6 @@ import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.annotations.VisibleForTesting;
 import com.netflix.config.DynamicPropertyFactory;
 
 import io.vertx.core.json.Json;
@@ -81,7 +77,6 @@ public abstract class RestProducerInvocationCreator implements InvocationCreator
     Invocation invocation = createInstance();
     initInvocationContext(invocation);
     addParameterContext(invocation);
-    initProduceProcessor();
     initTransportContext(invocation);
 
     invocation.addLocalContext(RestConst.REST_REQUEST, requestEx);
@@ -158,16 +153,4 @@ public abstract class RestProducerInvocationCreator implements InvocationCreator
   protected OperationLocator locateOperation(ServicePathManager servicePathManager) {
     return servicePathManager.producerLocateOperation(requestEx.getRequestURI(), requestEx.getMethod());
   }
-
-  @VisibleForTesting
-  void initProduceProcessor() {
-    produceProcessor = restOperationMeta.ensureFindProduceProcessor(requestEx);
-    if (produceProcessor == null) {
-      LOGGER.error("Accept {} is not supported, operation={}.", requestEx.getHeader(HttpHeaders.ACCEPT),
-          restOperationMeta.getOperationMeta().getMicroserviceQualifiedName());
-
-      String msg = String.format("Accept %s is not supported", requestEx.getHeader(HttpHeaders.ACCEPT));
-      throw Exceptions.create(NOT_ACCEPTABLE, GENERIC_CLIENT, msg);
-    }
-  }
 }
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestVertxProducerInvocationCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestVertxProducerInvocationCreator.java
index fcae4c7ab..a809f0968 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestVertxProducerInvocationCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/RestVertxProducerInvocationCreator.java
@@ -38,8 +38,7 @@ public class RestVertxProducerInvocationCreator extends RestProducerInvocationCr
 
   @Override
   protected void initTransportContext(Invocation invocation) {
-    VertxHttpTransportContext transportContext = new VertxHttpTransportContext(routingContext, requestEx, responseEx,
-        produceProcessor);
+    VertxHttpTransportContext transportContext = new VertxHttpTransportContext(routingContext, requestEx, responseEx);
     invocation.setTransportContext(transportContext);
     routingContext.put(RestConst.REST_INVOCATION_CONTEXT, invocation);
   }
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxHttpTransportContext.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxHttpTransportContext.java
index b88c1a12b..55576022e 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxHttpTransportContext.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/VertxHttpTransportContext.java
@@ -16,7 +16,6 @@
  */
 package org.apache.servicecomb.common.rest;
 
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import org.apache.servicecomb.swagger.invocation.context.VertxTransportContext;
@@ -31,8 +30,8 @@ public class VertxHttpTransportContext extends HttpTransportContext implements V
   private final Context vertxContext;
 
   public VertxHttpTransportContext(RoutingContext routingContext, HttpServletRequestEx requestEx,
-      HttpServletResponseEx responseEx, ProduceProcessor produceProcessor) {
-    super(requestEx, responseEx, produceProcessor);
+      HttpServletResponseEx responseEx) {
+    super(requestEx, responseEx);
 
     this.routingContext = routingContext;
     this.vertxContext = Vertx.currentContext();
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
index 736b8a060..b231f854c 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
@@ -194,6 +194,10 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
 
       // For application/json and text/plain
       try {
+        if (MediaType.TEXT_PLAIN.equals(contentType) &&
+            targetType != null && String.class.equals(targetType.getRawClass())) {
+          return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
+        }
         ObjectReader reader = serialViewClass != null
             ? RestObjectMapperFactory.getRestObjectMapper().readerWithView(serialViewClass)
             : RestObjectMapperFactory.getRestObjectMapper().reader();
@@ -257,7 +261,11 @@ public class BodyProcessorCreator implements ParamValueProcessorCreator<RequestB
 
       // For application/json and text/plain
       try (BufferOutputStream output = new BufferOutputStream()) {
-        RestObjectMapperFactory.getConsumerWriterMapper().writeValue(output, arg);
+        if (MediaType.TEXT_PLAIN.equals(contentType) && (arg instanceof String)) {
+          output.write(((String) arg).getBytes(StandardCharsets.UTF_8));
+        } else {
+          RestObjectMapperFactory.getConsumerWriterMapper().writeValue(output, arg);
+        }
         return output.getBuffer();
       }
     }
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java
index c883fa4c1..81302d576 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProcessorManager.java
@@ -21,13 +21,17 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import jakarta.ws.rs.core.MediaType;
-
+import org.apache.http.entity.ContentType;
+import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.foundation.common.RegisterManager;
 import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
+import org.apache.servicecomb.swagger.generator.SwaggerConst;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.util.CollectionUtils;
+
+import io.swagger.v3.oas.models.responses.ApiResponse;
+import io.swagger.v3.oas.models.responses.ApiResponses;
+import jakarta.ws.rs.core.MediaType;
 
 public final class ProduceProcessorManager extends RegisterManager<String, Map<String, ProduceProcessor>> {
   private static final Logger LOGGER = LoggerFactory.getLogger(ProduceProcessorManager.class);
@@ -37,14 +41,10 @@ public final class ProduceProcessorManager extends RegisterManager<String, Map<S
 
   private static final String NAME = "produce processor mgr";
 
-  public static final String DEFAULT_TYPE = MediaType.APPLICATION_JSON;
-
   public static final String DEFAULT_SERIAL_CLASS = "servicecomb_default_class";
 
   public static final ProduceProcessorManager INSTANCE = new ProduceProcessorManager();
 
-  private final Map<String, ProduceProcessor> nonSerialViewMap = new HashMap<>();
-
   private final Map<String, ProduceProcessor> jsonProcessorMap;
 
   private final Map<String, ProduceProcessor> plainProcessorMap;
@@ -54,7 +54,6 @@ public final class ProduceProcessorManager extends RegisterManager<String, Map<S
   private ProduceProcessorManager() {
     super(NAME);
     produceProcessor.forEach(processor -> {
-      nonSerialViewMap.put(processor.getName(), processor);
       Map<String, ProduceProcessor> prodProcessorMap = getObjMap()
           .computeIfAbsent(processor.getName(), key -> new HashMap<>());
       prodProcessorMap.putIfAbsent(processor.getSerializationView(), processor);
@@ -78,32 +77,6 @@ public final class ProduceProcessorManager extends RegisterManager<String, Map<S
     return produceViewMap.get(DEFAULT_SERIAL_CLASS);
   }
 
-  // key -> accept type
-  public Map<String, ProduceProcessor> getOrCreateAcceptMap(Class<?> serialViewClass) {
-    if (serialViewClass == null) {
-      return nonSerialViewMap;
-    }
-    Map<String, ProduceProcessor> result = new HashMap<>();
-    getObjMap().forEach((acceptKey, viewMap) -> {
-      ProduceProcessor produceProcessor = viewMap.computeIfAbsent(serialViewClass.getName(),
-          viewKey -> cloneNewProduceProcessor(serialViewClass, viewMap));
-      result.put(acceptKey, produceProcessor);
-    });
-    return result;
-  }
-
-  public ProduceProcessor findProcessor(String acceptType, Class<?> serialViewClass) {
-    Map<String, ProduceProcessor> viewMap = findValue(acceptType);
-    if (CollectionUtils.isEmpty(viewMap)) {
-      return null;
-    }
-    if (serialViewClass == null) {
-      return viewMap.get(DEFAULT_SERIAL_CLASS);
-    }
-    return viewMap.computeIfAbsent(serialViewClass.getName(),
-        viewKey -> cloneNewProduceProcessor(serialViewClass, viewMap));
-  }
-
   public ProduceProcessor findJsonProcessorByViewClass(Class<?> serialViewClass) {
     if (serialViewClass == null) {
       return jsonProcessorMap.get(DEFAULT_SERIAL_CLASS);
@@ -112,14 +85,6 @@ public final class ProduceProcessorManager extends RegisterManager<String, Map<S
         viewKey -> cloneNewProduceProcessor(serialViewClass, jsonProcessorMap));
   }
 
-  public ProduceProcessor findDefaultProcessorByViewClass(Class<?> serialViewClass) {
-    if (serialViewClass == null) {
-      return defaultProcessorMap.get(DEFAULT_SERIAL_CLASS);
-    }
-    return defaultProcessorMap.computeIfAbsent(serialViewClass.getName(),
-        viewKey -> cloneNewProduceProcessor(serialViewClass, defaultProcessorMap));
-  }
-
   public ProduceProcessor findPlainProcessorByViewClass(Class<?> serialViewClass) {
     if (serialViewClass == null) {
       return plainProcessorMap.get(DEFAULT_SERIAL_CLASS);
@@ -139,4 +104,45 @@ public final class ProduceProcessorManager extends RegisterManager<String, Map<S
   public ProduceProcessor findDefaultPlainProcessor() {
     return plainProcessorMap.get(DEFAULT_SERIAL_CLASS);
   }
+
+  public ProduceProcessor createProduceProcessor(OperationMeta operationMeta,
+      int statusCode, String accept, Class<?> serialViewClass) {
+    ApiResponses responses = operationMeta.getSwaggerOperation().getResponses();
+    ApiResponse response = responses.get(String.valueOf(statusCode));
+    if (response == null || response.getContent() == null ||
+        response.getContent().size() == 0) {
+      return findDefaultProcessor();
+    }
+    String actualAccept = accept;
+    if (actualAccept == null) {
+      if (response.getContent().get(MediaType.APPLICATION_JSON) != null) {
+        actualAccept = MediaType.APPLICATION_JSON;
+      } else {
+        actualAccept = response.getContent().keySet().iterator().next();
+      }
+    }
+    ContentType contentType = ContentType.parse(actualAccept);
+    actualAccept = contentType.getMimeType();
+    if (MediaType.WILDCARD.equals(contentType.getMimeType()) ||
+        MediaType.MEDIA_TYPE_WILDCARD.equals(contentType.getMimeType())) {
+      if (response.getContent().get(MediaType.APPLICATION_JSON) != null) {
+        actualAccept = MediaType.APPLICATION_JSON;
+      } else {
+        actualAccept = response.getContent().keySet().iterator().next();
+      }
+    }
+    if (response.getContent().get(actualAccept) == null) {
+      LOGGER.warn("Operation do not support accept type {}/{}", accept, actualAccept);
+      return findDefaultProcessor();
+    }
+    if (SwaggerConst.PROTOBUF_TYPE.equals(actualAccept)) {
+      return new ProduceProtoBufferProcessor(operationMeta,
+          operationMeta.getSchemaMeta().getSwagger(), response.getContent().get(accept).getSchema());
+    }
+    if (MediaType.TEXT_PLAIN.equals(actualAccept)) {
+      return findPlainProcessorByViewClass(serialViewClass);
+    }
+    // json
+    return findJsonProcessorByViewClass(serialViewClass);
+  }
 }
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProtoBufferProcessor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProtoBufferProcessor.java
new file mode 100644
index 000000000..f1c8bc105
--- /dev/null
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceProtoBufferProcessor.java
@@ -0,0 +1,107 @@
+/*
+ * 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.servicecomb.common.rest.codec.produce;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.servicecomb.codec.protobuf.utils.ScopedProtobufSchemaManager;
+import org.apache.servicecomb.core.definition.MicroserviceMeta;
+import org.apache.servicecomb.core.definition.OperationMeta;
+import org.apache.servicecomb.foundation.protobuf.ProtoMapper;
+import org.apache.servicecomb.foundation.protobuf.RootDeserializer;
+import org.apache.servicecomb.foundation.protobuf.RootSerializer;
+import org.apache.servicecomb.foundation.protobuf.internal.bean.PropertyWrapper;
+import org.apache.servicecomb.swagger.generator.SwaggerConst;
+
+import com.fasterxml.jackson.databind.JavaType;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.media.Schema;
+
+public class ProduceProtoBufferProcessor implements ProduceProcessor {
+  public static final String RESPONSE_MESSAGE_NAME = "response";
+
+  public static final String EXT_ID = "protobuf";
+
+  private static final Object LOCK = new Object();
+
+  private final OperationMeta operationMeta;
+
+  private final OpenAPI openAPI;
+
+  private final Schema<?> schema;
+
+  private final ScopedProtobufSchemaManager scopedProtobufSchemaManager;
+
+  public ProduceProtoBufferProcessor(OperationMeta operationMeta, OpenAPI openAPI, Schema<?> schema) {
+    this.operationMeta = operationMeta;
+    this.openAPI = openAPI;
+    this.schema = schema;
+    this.scopedProtobufSchemaManager = getOrCreateScopedProtobufSchemaManager(operationMeta.getMicroserviceMeta());
+  }
+
+  private ScopedProtobufSchemaManager getOrCreateScopedProtobufSchemaManager(MicroserviceMeta microserviceMeta) {
+    ScopedProtobufSchemaManager scopedProtobufSchemaManager = microserviceMeta.getExtData(EXT_ID);
+    if (scopedProtobufSchemaManager == null) {
+      synchronized (LOCK) {
+        scopedProtobufSchemaManager = microserviceMeta.getExtData(EXT_ID);
+        if (scopedProtobufSchemaManager == null) {
+          scopedProtobufSchemaManager = new ScopedProtobufSchemaManager();
+          microserviceMeta.putExtData(EXT_ID, scopedProtobufSchemaManager);
+        }
+      }
+    }
+    return scopedProtobufSchemaManager;
+  }
+
+  @Override
+  public String getName() {
+    return SwaggerConst.PROTOBUF_TYPE;
+  }
+
+  @Override
+  public int getOrder() {
+    return 0;
+  }
+
+  @Override
+  public void doEncodeResponse(OutputStream output, Object result) throws Exception {
+    ProtoMapper protoMapper = scopedProtobufSchemaManager
+        .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(),
+            RESPONSE_MESSAGE_NAME, schema);
+    RootSerializer serializer = protoMapper.getSerializerSchemaManager()
+        .createRootSerializer(protoMapper.getProto().getMessage(RESPONSE_MESSAGE_NAME),
+            Object.class);
+    Map<String, Object> bodyArg = new HashMap<>(1);
+    bodyArg.put("value", result);
+    output.write(serializer.serialize(bodyArg));
+  }
+
+  @Override
+  public Object doDecodeResponse(InputStream input, JavaType type) throws Exception {
+    ProtoMapper protoMapper = scopedProtobufSchemaManager
+        .getOrCreateProtoMapper(openAPI, operationMeta.getSchemaId(),
+            RESPONSE_MESSAGE_NAME, schema);
+    RootDeserializer<PropertyWrapper<Object>> deserializer = protoMapper.getDeserializerSchemaManager()
+        .createRootDeserializer(protoMapper.getProto().getMessage(RESPONSE_MESSAGE_NAME), type);
+    PropertyWrapper<Object> result = deserializer.deserialize(input.readAllBytes());
+    return result.getValue();
+  }
+}
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java
index d5739be48..21d73688d 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceTextPlainProcessor.java
@@ -21,13 +21,13 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 
-import jakarta.ws.rs.core.MediaType;
-
 import org.apache.commons.io.IOUtils;
 
 import com.fasterxml.jackson.databind.JavaType;
 
-public class ProduceTextPlainProcessor implements ProduceProcessor {
+import jakarta.ws.rs.core.MediaType;
+
+public class ProduceTextPlainProcessor extends ProduceJsonProcessor {
   @Override
   public String getName() {
     return MediaType.TEXT_PLAIN;
@@ -35,17 +35,18 @@ public class ProduceTextPlainProcessor implements ProduceProcessor {
 
   @Override
   public void doEncodeResponse(OutputStream output, Object result) throws Exception {
-    output.write(String.valueOf(result).getBytes(StandardCharsets.UTF_8));
+    if (result instanceof String) {
+      output.write(((String) result).getBytes(StandardCharsets.UTF_8));
+      return;
+    }
+    super.doEncodeResponse(output, result);
   }
 
   @Override
   public Object doDecodeResponse(InputStream input, JavaType type) throws Exception {
-    // plainText类型,肯定是返回string的,想不出有其他类型的场景
-    return IOUtils.toString(input, StandardCharsets.UTF_8);
-  }
-
-  @Override
-  public int getOrder() {
-    return 0;
+    if (String.class.equals(type.getRawClass())) {
+      return IOUtils.toString(input, StandardCharsets.UTF_8);
+    }
+    return super.doDecodeResponse(input, type);
   }
 }
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java
index 764160100..48bb32a8b 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/definition/RestOperationMeta.java
@@ -17,32 +17,23 @@
 
 package org.apache.servicecomb.common.rest.definition;
 
-import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
 import org.apache.servicecomb.common.rest.codec.param.FormProcessorCreator.PartProcessor;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager;
 import org.apache.servicecomb.common.rest.definition.path.PathRegExp;
 import org.apache.servicecomb.common.rest.definition.path.URLPathBuilder;
-import org.apache.servicecomb.core.Const;
 import org.apache.servicecomb.core.definition.OperationMeta;
-import org.apache.servicecomb.foundation.common.utils.MimeTypesUtils;
-import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import org.apache.servicecomb.swagger.SwaggerUtils;
-import org.apache.servicecomb.swagger.engine.SwaggerProducerOperation;
 import org.apache.servicecomb.swagger.generator.SwaggerConst;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.fasterxml.jackson.annotation.JsonView;
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.type.TypeFactory;
 
@@ -54,7 +45,6 @@ import io.swagger.v3.oas.models.parameters.Parameter;
 import io.swagger.v3.oas.models.parameters.RequestBody;
 import io.swagger.v3.oas.models.responses.ApiResponse;
 import io.swagger.v3.oas.models.responses.ApiResponses;
-import jakarta.ws.rs.core.HttpHeaders;
 import jakarta.ws.rs.core.MediaType;
 
 @SuppressWarnings("rawtypes")
@@ -63,8 +53,6 @@ public class RestOperationMeta {
 
   protected OperationMeta operationMeta;
 
-  protected List<String> produces;
-
   protected boolean formData;
 
   // make sure if response is file
@@ -77,12 +65,6 @@ public class RestOperationMeta {
 
   protected List<String> fileKeys = new ArrayList<>();
 
-  // key为数据类型,比如json之类
-  private final Map<String, ProduceProcessor> produceProcessorMap = new LinkedHashMap<>();
-
-  // 不一定等于mgr中的default,因为本operation可能不支持mgr中的default
-  private ProduceProcessor defaultProcessor;
-
   protected String absolutePath;
 
   protected PathRegExp absolutePathRegExp;
@@ -95,13 +77,8 @@ public class RestOperationMeta {
 
     OpenAPI swagger = operationMeta.getSchemaMeta().getSwagger();
     Operation operation = operationMeta.getSwaggerOperation();
-    this.produces =
-        (operation.getResponses().get(SwaggerConst.SUCCESS_KEY) == null ||
-            operation.getResponses().get(SwaggerConst.SUCCESS_KEY).getContent() == null) ?
-            null : operation.getResponses().get(SwaggerConst.SUCCESS_KEY).getContent().keySet().stream().toList();
 
     this.downloadFile = checkDownloadFileFlag();
-    this.createProduceProcessors();
 
     if (operation.getParameters() != null) {
       for (int swaggerParameterIdx = 0; swaggerParameterIdx < operation.getParameters().size(); swaggerParameterIdx++) {
@@ -259,76 +236,10 @@ public class RestOperationMeta {
     return paramMap.get(name);
   }
 
-  public RestParam getParamByIndex(int index) {
-    return paramList.get(index);
-  }
-
   public OperationMeta getOperationMeta() {
     return operationMeta;
   }
 
-  protected void createProduceProcessors() {
-    SwaggerProducerOperation producerOperation = operationMeta.getExtData(Const.PRODUCER_OPERATION);
-    if (producerOperation != null && producerOperation.getProducerMethod() != null) {
-      createProduceProcessors(producerOperation.getProducerMethod().getDeclaredAnnotations());
-      return;
-    }
-    createProduceProcessors(null);
-  }
-
-  // serialViewClass is deterministic for each operation
-  protected void createProduceProcessors(Annotation[] annotations) {
-    if (annotations == null || annotations.length < 1) {
-      doCreateProduceProcessors(null);
-      return;
-    }
-    for (Annotation annotation : annotations) {
-      if (annotation.annotationType() == JsonView.class) {
-        Class<?>[] value = ((JsonView) annotation).value();
-        if (value.length != 1) {
-          throw new IllegalArgumentException(
-              "@JsonView only supported for exactly 1 class argument ");
-        }
-        doCreateProduceProcessors(value[0]);
-        return;
-      }
-    }
-    doCreateProduceProcessors(null);
-  }
-
-  // 为operation创建支持的多种produce processor
-  protected void doCreateProduceProcessors(Class<?> serialViewClass) {
-    if (null == produces || produces.isEmpty()) {
-      produceProcessorMap.putAll(
-          ProduceProcessorManager.INSTANCE.getOrCreateAcceptMap(serialViewClass));
-    } else {
-      for (String produce : produces) {
-        if (produce.contains(";")) {
-          produce = produce.substring(0, produce.indexOf(";"));
-        }
-        ProduceProcessor processor = ProduceProcessorManager.INSTANCE.findProcessor(produce, serialViewClass);
-        if (processor == null) {
-          LOGGER.error("produce {} is not supported, operation={}.", produce,
-              operationMeta.getMicroserviceQualifiedName());
-          continue;
-        }
-        this.produceProcessorMap.put(produce, processor);
-      }
-
-      if (produceProcessorMap.isEmpty()) {
-        produceProcessorMap.put(ProduceProcessorManager.DEFAULT_TYPE,
-            ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(serialViewClass));
-      }
-    }
-
-    if (produceProcessorMap.get(ProduceProcessorManager.DEFAULT_TYPE) != null) {
-      defaultProcessor = produceProcessorMap.get(ProduceProcessorManager.DEFAULT_TYPE);
-    } else {
-      defaultProcessor = produceProcessorMap.values().stream().findFirst().get();
-    }
-    produceProcessorMap.putIfAbsent(MediaType.WILDCARD, defaultProcessor);
-  }
-
   public URLPathBuilder getPathBuilder() {
     return this.pathBuilder;
   }
@@ -345,37 +256,6 @@ public class RestOperationMeta {
     paramMap.put(param.getParamName(), param);
   }
 
-  public ProduceProcessor findProduceProcessor(String type) {
-    return this.produceProcessorMap.get(type);
-  }
-
-  // 选择与accept匹配的produce processor或者缺省的
-  public ProduceProcessor ensureFindProduceProcessor(HttpServletRequestEx requestEx) {
-    String acceptType = requestEx.getHeader(HttpHeaders.ACCEPT);
-    return ensureFindProduceProcessor(acceptType);
-  }
-
-  public ProduceProcessor ensureFindProduceProcessor(String acceptType) {
-    if (downloadFile) {
-      //do not check accept type, when the produces of provider is text/plain there will return text/plain processor
-      //when the produces of provider is application/json there will return the application/json processor
-      //so do not care what accept type the consumer will set.
-      return this.produceProcessorMap.get(MediaType.WILDCARD);
-    }
-    if (StringUtils.isEmpty(acceptType)) {
-      return defaultProcessor;
-    }
-    List<String> mimeTypes = MimeTypesUtils.getSortedAcceptableMimeTypes(acceptType.toLowerCase(Locale.US));
-    for (String mime : mimeTypes) {
-      ProduceProcessor processor = this.produceProcessorMap.get(mime);
-      if (null != processor) {
-        return processor;
-      }
-    }
-
-    return null;
-  }
-
   public String getHttpMethod() {
     return operationMeta.getHttpMethod();
   }
@@ -383,8 +263,4 @@ public class RestOperationMeta {
   public List<String> getFileKeys() {
     return fileKeys;
   }
-
-  public List<String> getProduces() {
-    return produces;
-  }
 }
diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java
index 392112ec6..a40c7cb55 100644
--- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java
+++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilter.java
@@ -31,6 +31,7 @@ import org.apache.servicecomb.common.rest.HttpTransportContext;
 import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.common.rest.codec.RestCodec;
 import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
+import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager;
 import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
 import org.apache.servicecomb.core.Const;
 import org.apache.servicecomb.core.Invocation;
@@ -51,6 +52,7 @@ import org.slf4j.LoggerFactory;
 import io.netty.buffer.Unpooled;
 import io.vertx.core.MultiMap;
 import jakarta.servlet.http.Part;
+import jakarta.ws.rs.core.HttpHeaders;
 
 public class RestServerCodecFilter implements ProviderFilter {
   private static final Logger LOGGER = LoggerFactory.getLogger(RestServerCodecFilter.class);
@@ -100,7 +102,11 @@ public class RestServerCodecFilter implements ProviderFilter {
     invocation.onEncodeResponseStart(response);
 
     HttpTransportContext transportContext = invocation.getTransportContext();
-    ProduceProcessor produceProcessor = transportContext.getProduceProcessor();
+
+    // TODO: response support JsonView
+    ProduceProcessor produceProcessor = ProduceProcessorManager.INSTANCE
+        .createProduceProcessor(invocation.getOperationMeta(), response.getStatusCode(),
+            invocation.getRequestEx().getHeader(HttpHeaders.ACCEPT), null);
     HttpServletResponseEx responseEx = transportContext.getResponseEx();
     boolean download = isDownloadFileResponseType(invocation, response);
 
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java
index 730aa22bf..108fb8722 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java
@@ -22,8 +22,6 @@ import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.catchThrowable;
 
-import jakarta.ws.rs.core.HttpHeaders;
-
 import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
 import org.apache.servicecomb.common.rest.locator.OperationLocator;
 import org.apache.servicecomb.common.rest.locator.ServicePathManager;
@@ -52,6 +50,7 @@ import org.mockito.Mockito;
 
 import io.vertx.core.json.Json;
 import io.vertx.ext.web.RoutingContext;
+import jakarta.ws.rs.core.HttpHeaders;
 
 public class RestProducerInvocationCreatorTest {
 
@@ -113,43 +112,21 @@ public class RestProducerInvocationCreatorTest {
 
       assertThat(throwable.getStatusCode()).isEqualTo(NOT_FOUND.getStatusCode());
       assertThat(Json.encode(data)).isIn("{\"code\":\"SCB.00000002\",\"message\":\"Not Found\"}",
-              "{\"message\":\"Not Found\",\"code\":\"SCB.00000002\"}");
-    }
-  }
-
-  @Test
-  public void should_failed_when_accept_is_not_support() {
-    try (MockedStatic<ServicePathManager> mockedStatic = Mockito.mockStatic(ServicePathManager.class)) {
-      mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)).thenReturn(servicePathManager);
-      Mockito.when(requestEx.getHeader(HttpHeaders.ACCEPT)).thenReturn("test-type");
-      Mockito.when(restOperationMeta.ensureFindProduceProcessor(requestEx)).thenReturn(null);
-      Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator);
-      Mockito.when(locator.getOperation()).thenReturn(restOperationMeta);
-      Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta);
-      Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType);
-      Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta);
-      Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta);
-
-      InvocationException throwable = (InvocationException) catchThrowable(() -> creator.createAsync().join());
-      CommonExceptionData data = (CommonExceptionData) throwable.getErrorData();
-
-      assertThat(throwable.getStatusCode()).isEqualTo(NOT_ACCEPTABLE.getStatusCode());
-      assertThat(Json.encode(data)).isIn("{\"code\":\"SCB.00000000\",\"message\":\"Accept test-type is not supported\"}",
-              "{\"message\":\"Accept test-type is not supported\",\"code\":\"SCB.00000000\"}");
+          "{\"message\":\"Not Found\",\"code\":\"SCB.00000002\"}");
     }
   }
 
   @Test
   public void should_save_requestEx_in_invocation_context() {
     try (MockedStatic<ServicePathManager> mockedStatic = Mockito.mockStatic(ServicePathManager.class)) {
-      mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)).thenReturn(servicePathManager);
+      mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta))
+          .thenReturn(servicePathManager);
       Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator);
       Mockito.when(locator.getOperation()).thenReturn(restOperationMeta);
       Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta);
       Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType);
       Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta);
       Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta);
-      Mockito.doNothing().when(creator).initProduceProcessor();
 
       Invocation invocation = creator.createAsync().join();
 
@@ -161,14 +138,14 @@ public class RestProducerInvocationCreatorTest {
   @Test
   public void should_save_path_var_map_in_requestEx() {
     try (MockedStatic<ServicePathManager> mockedStatic = Mockito.mockStatic(ServicePathManager.class)) {
-      mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)).thenReturn(servicePathManager);
+      mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta))
+          .thenReturn(servicePathManager);
       Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator);
       Mockito.when(locator.getOperation()).thenReturn(restOperationMeta);
       Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta);
       Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType);
       Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta);
       Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta);
-      Mockito.doNothing().when(creator).initProduceProcessor();
 
       creator.createAsync().join();
 
@@ -179,14 +156,14 @@ public class RestProducerInvocationCreatorTest {
   @Test
   public void should_merge_invocation_context_from_request() {
     try (MockedStatic<ServicePathManager> mockedStatic = Mockito.mockStatic(ServicePathManager.class)) {
-      mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta)).thenReturn(servicePathManager);
+      mockedStatic.when(() -> ServicePathManager.getServicePathManager(microserviceMeta))
+          .thenReturn(servicePathManager);
       Mockito.when(creator.locateOperation(microserviceMeta)).thenReturn(locator);
       Mockito.when(locator.getOperation()).thenReturn(restOperationMeta);
       Mockito.when(restOperationMeta.getOperationMeta()).thenReturn(operationMeta);
       Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType);
       Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta);
       Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta);
-      Mockito.doNothing().when(creator).initProduceProcessor();
       Mockito.when(requestEx.getHeader(Const.CSE_CONTEXT)).thenReturn("{\"k\":\"v\"}");
 
       Invocation invocation = creator.createAsync().join();
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
index ebbe2975a..5e7270a6e 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/TestRestCodec.java
@@ -27,7 +27,6 @@ import org.apache.servicecomb.common.rest.codec.param.RestClientRequestImpl;
 import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
 import org.apache.servicecomb.common.rest.definition.RestParam;
 import org.apache.servicecomb.core.definition.OperationMeta;
-import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
 import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
@@ -160,7 +159,7 @@ public class TestRestCodec {
       success = true;
     } catch (InvocationException e) {
       Assertions.assertEquals(e.getStatusCode(), Status.BAD_REQUEST.getStatusCode());
-      Assertions.assertTrue(((CommonExceptionData) e.getErrorData()).getMessage()
+      Assertions.assertTrue(((String) e.getErrorData())
           .contains("Parameter is not valid for operation"));
     }
     Assertions.assertFalse(success);
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java
index d7413d938..d717072a2 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/produce/TestProduceTextPlainProcessor.java
@@ -52,7 +52,7 @@ public class TestProduceTextPlainProcessor {
     Object result = pp.decodeResponse(Buffer.buffer(), resultType);
     Assertions.assertNull(result);
 
-    ByteArrayInputStream is = new ByteArrayInputStream(new byte[] {});
+    ByteArrayInputStream is = new ByteArrayInputStream("\"\"".getBytes(StandardCharsets.UTF_8));
     result = pp.decodeResponse(is, resultType);
     Assertions.assertEquals(result, "");
   }
@@ -91,6 +91,6 @@ public class TestProduceTextPlainProcessor {
     Assertions.assertEquals(DEFAULT_SERIAL_CLASS, pp.getSerializationView());
 
     pp.setSerializationView(Object.class);
-    Assertions.assertEquals(DEFAULT_SERIAL_CLASS, pp.getSerializationView());
+    Assertions.assertEquals("java.lang.Object", pp.getSerializationView());
   }
 }
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java
index 27d70d4e7..911bf2c6f 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/definition/TestRestOperationMeta.java
@@ -25,8 +25,6 @@ import java.util.Arrays;
 import java.util.List;
 
 import org.apache.servicecomb.common.rest.RestEngineSchemaListener;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager;
 import org.apache.servicecomb.config.ConfigUtil;
 import org.apache.servicecomb.core.BootListener;
 import org.apache.servicecomb.core.SCBEngine;
@@ -36,7 +34,6 @@ import org.apache.servicecomb.core.definition.SchemaMeta;
 import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
 import org.hamcrest.MatcherAssert;
 import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
@@ -191,198 +188,6 @@ public class TestRestOperationMeta {
     Mockito.when(schemaMeta.getSwagger()).thenReturn(swagger);
   }
 
-  @Test
-  public void testCreateProduceProcessorsNull() {
-    findOperation("emptyProduces");
-    operationMeta.produces = null;
-    operationMeta.createProduceProcessors();
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor((String) null));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor("*/*"));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
-    for (String produce : ProduceProcessorManager.INSTANCE.keys()) {
-      ProduceProcessor expected = ProduceProcessorManager.INSTANCE.findProcessor(produce, null);
-      Assertions.assertSame(expected, operationMeta.findProduceProcessor(produce));
-    }
-  }
-
-  @Test
-  public void testCreateProduceProcessorsNullWithView() {
-    findOperation("emptyProducesWithView");
-    operationMeta.produces = null;
-    operationMeta.createProduceProcessors();
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor((String) null));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor("*/*"));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
-    for (String produce : ProduceProcessorManager.INSTANCE.keys()) {
-      ProduceProcessor expected = ProduceProcessorManager.INSTANCE.findProcessor(produce, Object.class);
-      Assertions.assertSame(expected, operationMeta.findProduceProcessor(produce));
-    }
-  }
-
-  @Test
-  public void testCreateProduceProcessorsEmpty() {
-    findOperation("emptyProduces");
-    operationMeta.produces = Arrays.asList();
-    operationMeta.createProduceProcessors();
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor((String) null));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor("*/*"));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
-    for (String produce : ProduceProcessorManager.INSTANCE.keys()) {
-      ProduceProcessor expected = ProduceProcessorManager.INSTANCE.findProcessor(produce, null);
-      Assertions.assertSame(expected, operationMeta.findProduceProcessor(produce));
-    }
-  }
-
-  @Test
-  public void testCreateProduceProcessorsEmptyWithView() {
-    findOperation("emptyProducesWithView");
-    operationMeta.produces = Arrays.asList();
-    operationMeta.createProduceProcessors();
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor((String) null));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor("*/*"));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
-    for (String produce : ProduceProcessorManager.INSTANCE.keys()) {
-      ProduceProcessor expected = ProduceProcessorManager.INSTANCE.findProcessor(produce, Object.class);
-      Assertions.assertSame(expected, operationMeta.findProduceProcessor(produce));
-    }
-  }
-
-  @Test
-  public void testCreateProduceProcessorsNormal() {
-    findOperation("json");
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor((String) null));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor("*/*"));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultJsonProcessor(),
-        operationMeta.findProduceProcessor(MediaType.APPLICATION_JSON));
-    Assertions.assertNull(operationMeta.findProduceProcessor(MediaType.TEXT_PLAIN));
-  }
-
-  @Test
-  public void testCreateProduceProcessorsNormalWithView() {
-    findOperation("jsonWithView");
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findJsonProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor((String) null));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findJsonProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor("*/*"));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findJsonProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findJsonProcessorByViewClass(Object.class),
-        operationMeta.findProduceProcessor(MediaType.APPLICATION_JSON));
-    Assertions.assertNull(operationMeta.findProduceProcessor(MediaType.TEXT_PLAIN));
-  }
-
-  @Test
-  public void testCreateProduceProcessorsNotSupported() {
-    findOperation("notSupport");
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor((String) null));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor("*/*"));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessor(),
-        operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultJsonProcessor(),
-        operationMeta.findProduceProcessor(MediaType.APPLICATION_JSON));
-    Assertions.assertNotNull(operationMeta.findProduceProcessor(MediaType.TEXT_PLAIN));
-  }
-
-  @Test
-  public void testCreateProduceProcessorsNotSupportedWithView() {
-    findOperation("notSupportWithView");
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor((String) null));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor("*/*"));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor(ProduceProcessorManager.DEFAULT_TYPE));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultProcessorByViewClass(Object.class),
-        operationMeta.findProduceProcessor(MediaType.APPLICATION_JSON));
-    Assertions.assertNotNull(operationMeta.findProduceProcessor(MediaType.TEXT_PLAIN));
-  }
-
-  @Test
-  public void testCreateProduceProcessorsTextAndWildcard() {
-    findOperation("textPlain");
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultPlainProcessor(),
-        operationMeta.ensureFindProduceProcessor(MediaType.WILDCARD));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultPlainProcessor(),
-        operationMeta.ensureFindProduceProcessor(MediaType.TEXT_PLAIN));
-    Assertions.assertNull(operationMeta.ensureFindProduceProcessor(MediaType.APPLICATION_JSON));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultPlainProcessor(),
-        operationMeta.ensureFindProduceProcessor(
-            MediaType.APPLICATION_JSON + "," + MediaType.APPLICATION_XML + "," + MediaType.WILDCARD));
-  }
-
-  @Test
-  public void testCreateProduceProcessorsTextAndWildcardWithView() {
-    findOperation("textPlainWithView");
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findPlainProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor(MediaType.WILDCARD));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findPlainProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor(MediaType.TEXT_PLAIN));
-    Assertions.assertNull(operationMeta.ensureFindProduceProcessor(MediaType.APPLICATION_JSON));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findPlainProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor(
-            MediaType.APPLICATION_JSON + "," + MediaType.APPLICATION_XML + "," + MediaType.WILDCARD));
-  }
-
-  @Test
-  public void testCreateProduceProcessorsWithSemicolon() {
-    findOperation("textCharJsonChar");
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultPlainProcessor(),
-        operationMeta.ensureFindProduceProcessor(MediaType.TEXT_PLAIN));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findDefaultJsonProcessor(),
-        operationMeta.ensureFindProduceProcessor(MediaType.APPLICATION_JSON));
-  }
-
-  @Test
-  public void testCreateProduceProcessorsWithSemicolonWithView() {
-    findOperation("textCharJsonCharWithView");
-
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findPlainProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor(MediaType.TEXT_PLAIN));
-    Assertions.assertSame(ProduceProcessorManager.INSTANCE.findJsonProcessorByViewClass(Object.class),
-        operationMeta.ensureFindProduceProcessor(MediaType.APPLICATION_JSON));
-  }
-
-  @Test
-  public void testEnsureFindProduceProcessorAcceptNotFound() {
-    findOperation("textCharJsonChar");
-    Assertions.assertNull(operationMeta.ensureFindProduceProcessor("notSupport"));
-  }
-
-  @Test
-  public void testEnsureFindProduceProcessorAcceptNotFoundWithView() {
-    findOperation("textCharJsonCharWithView");
-    Assertions.assertNull(operationMeta.ensureFindProduceProcessor("notSupport"));
-  }
-
   @Test
   public void generatesAbsolutePathWithRootBasePath() {
     findOperation("textCharJsonChar");
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilterTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilterTest.java
index 0a88c3c2b..ab982a409 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilterTest.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/filter/inner/RestServerCodecFilterTest.java
@@ -20,14 +20,12 @@ package org.apache.servicecomb.common.rest.filter.inner;
 import static com.google.common.net.HttpHeaders.CONTENT_LENGTH;
 import static com.google.common.net.HttpHeaders.TRANSFER_ENCODING;
 import static jakarta.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
-import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 
 import org.apache.servicecomb.common.rest.HttpTransportContext;
 import org.apache.servicecomb.common.rest.RestConst;
-import org.apache.servicecomb.common.rest.codec.produce.ProduceJsonProcessor;
 import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
 import org.apache.servicecomb.config.ConfigUtil;
 import org.apache.servicecomb.core.Endpoint;
@@ -43,9 +41,11 @@ import org.apache.servicecomb.core.filter.FilterNode;
 import org.apache.servicecomb.core.invocation.InvocationFactory;
 import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
 import org.apache.servicecomb.foundation.test.scaffolding.exception.RuntimeExceptionWithoutStackTrace;
+import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -54,9 +54,14 @@ import org.mockito.Mockito;
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.type.TypeFactory;
 
+import io.swagger.v3.oas.models.Operation;
+import io.swagger.v3.oas.models.media.Content;
+import io.swagger.v3.oas.models.media.StringSchema;
+import io.swagger.v3.oas.models.responses.ApiResponse;
+import io.swagger.v3.oas.models.responses.ApiResponses;
 import io.vertx.core.MultiMap;
-import io.vertx.core.json.Json;
 import jakarta.servlet.http.Part;
+import jakarta.ws.rs.core.MediaType;
 
 public class RestServerCodecFilterTest {
   final RestServerCodecFilter codecFilter = new RestServerCodecFilter();
@@ -109,7 +114,6 @@ public class RestServerCodecFilterTest {
     Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta);
     Mockito.when(schemaMeta.getMicroserviceMeta()).thenReturn(microserviceMeta);
     Mockito.when(operationMeta.buildBaseProviderRuntimeType()).thenReturn(invocationRuntimeType);
-    Mockito.when(transportContext.getProduceProcessor()).thenReturn(Mockito.mock(ProduceJsonProcessor.class));
     invocation = Mockito.spy(InvocationFactory.forProvider(endpoint, operationMeta, null));
   }
 
@@ -137,16 +141,25 @@ public class RestServerCodecFilterTest {
     Mockito.when(invocation.findResponseType(INTERNAL_SERVER_ERROR.getStatusCode()))
         .thenReturn(TypeFactory.defaultInstance().constructType(String.class));
 
-    Response response = codecFilter.onFilter(invocation, nextNode).get();
-
-    assertThat(response.getStatus()).isEqualTo(INTERNAL_SERVER_ERROR);
-    assertThat(Json.encode(response.getResult())).
-        isIn("{\"code\":\"SCB.50000000\",\"message\":\"Unexpected "
-            + "exception when processing null. mock encode request failed\"}");
+    Assertions.assertThrows(ExecutionException.class,
+        () -> codecFilter.onFilter(invocation, nextNode).get());
   }
 
   private void success_invocation() throws InterruptedException, ExecutionException {
     Mockito.when(invocation.getTransportContext()).thenReturn(transportContext);
+    HttpServletRequestEx requestExt = Mockito.mock(HttpServletRequestEx.class);
+    Mockito.when(invocation.getRequestEx()).thenReturn(requestExt);
+    Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta);
+    Operation swaggerOperation = Mockito.mock(Operation.class);
+    Mockito.when(operationMeta.getSwaggerOperation()).thenReturn(swaggerOperation);
+    ApiResponses apiResponses = Mockito.mock(ApiResponses.class);
+    Mockito.when(swaggerOperation.getResponses()).thenReturn(apiResponses);
+    ApiResponse apiResponse = Mockito.mock(ApiResponse.class);
+    Mockito.when(apiResponses.get("200")).thenReturn(apiResponse);
+    Content content = new Content();
+    content.addMediaType(MediaType.APPLICATION_JSON, new io.swagger.v3.oas.models.media.MediaType());
+    content.get(MediaType.APPLICATION_JSON).setSchema(new StringSchema());
+    Mockito.when(apiResponse.getContent()).thenReturn(content);
     Mockito.when(operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION)).thenReturn(restOperationMeta);
     Mockito.when(invocation.findResponseType(INTERNAL_SERVER_ERROR.getStatusCode()))
         .thenReturn(TypeFactory.defaultInstance().constructType(String.class));
diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientDecoder.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientDecoder.java
index db277b68e..cd3c4e89e 100644
--- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientDecoder.java
+++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientDecoder.java
@@ -62,14 +62,15 @@ public class RestClientDecoder {
   }
 
   private ProduceProcessor safeFindProduceProcessor(Invocation invocation, Response response) {
-    RestClientTransportContext transportContext = invocation.getTransportContext();
-
     String contentType = extractContentType(response);
-    ProduceProcessor produceProcessor = transportContext.getRestOperationMeta().findProduceProcessor(contentType);
+    ProduceProcessor produceProcessor =
+        ProduceProcessorManager.INSTANCE.createProduceProcessor(invocation.getOperationMeta(), response.getStatusCode(),
+            contentType, null);
     if (produceProcessor != null) {
       return produceProcessor;
     }
 
+    RestClientTransportContext transportContext = invocation.getTransportContext();
     HttpClientRequest httpClientRequest = transportContext.getHttpClientRequest();
     LOGGER.warn(
         "operation={}, method={}, endpoint={}, uri={}, statusCode={}, reasonPhrase={}, response content-type={} is not supported in operation.",
diff --git a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocationCreator.java b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocationCreator.java
index 97cf131c5..a12ee8cc0 100644
--- a/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocationCreator.java
+++ b/transports/transport-rest/transport-rest-servlet/src/main/java/org/apache/servicecomb/transport/rest/servlet/RestServletProducerInvocationCreator.java
@@ -34,7 +34,7 @@ public class RestServletProducerInvocationCreator extends RestProducerInvocation
 
   @Override
   protected void initTransportContext(Invocation invocation) {
-    HttpTransportContext transportContext = new HttpTransportContext(requestEx, responseEx, produceProcessor);
+    HttpTransportContext transportContext = new HttpTransportContext(requestEx, responseEx);
     invocation.setTransportContext(transportContext);
   }
 }


[servicecomb-java-chassis] 06/06: [SCB-2803]fix checkstyle and test fails

Posted by li...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-java-chassis.git

commit c6eeb90ff403df19a4c61ad8eb2c7668b7e8c00b
Author: liubao <bi...@qq.com>
AuthorDate: Tue Aug 22 22:21:53 2023 +0800

    [SCB-2803]fix checkstyle and test fails
---
 ci/checkstyle/checkstyle.xml                       |  4 +
 .../schema/TestSchemaToProtoGenerator.java         | 14 ++--
 .../rest/RestProducerInvocationCreatorTest.java    |  2 -
 pom.xml                                            |  2 +-
 .../apache/servicecomb/swagger/SwaggerUtils.java   |  4 +-
 .../swagger/generator/springmvc/Echo.java          | 11 ++-
 .../springmvc/MethodMixupAnnotations.java          | 24 +++---
 .../springmvc/model/DefaultParameterSchema.java    |  4 +-
 .../resources/schemas/DefaultParameterSchema.yaml  | 13 +---
 .../src/test/resources/schemas/echo.yaml           | 32 --------
 .../test/resources/schemas/mixupAnnotations.yaml   | 90 ++++++----------------
 11 files changed, 58 insertions(+), 142 deletions(-)

diff --git a/ci/checkstyle/checkstyle.xml b/ci/checkstyle/checkstyle.xml
index 8c34ac08b..3813950a5 100644
--- a/ci/checkstyle/checkstyle.xml
+++ b/ci/checkstyle/checkstyle.xml
@@ -41,6 +41,10 @@
     <property name="message" value="Trailing whitespace"/>
     <property name="severity" value="error"/>
   </module>
+  <module name="SuppressWithPlainTextCommentFilter">
+    <property name="offCommentFormat" value="CHECKSTYLE.OFF"/>
+    <property name="onCommentFormat" value="CHECKSTYLE.ON"/>
+  </module>
   <module name="TreeWalker">
     <module name="AvoidStarImport"/>
     <module name="EmptyStatement"/>
diff --git a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaToProtoGenerator.java b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaToProtoGenerator.java
index c1b5f029a..4c0e0321f 100644
--- a/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaToProtoGenerator.java
+++ b/common/common-protobuf/src/test/java/org/apache/servicecomb/codec/protobuf/schema/TestSchemaToProtoGenerator.java
@@ -31,6 +31,7 @@ import io.swagger.v3.oas.models.media.ObjectSchema;
 import io.swagger.v3.oas.models.media.StringSchema;
 import jakarta.ws.rs.core.MediaType;
 
+//CHECKSTYLE:OFF
 @SuppressWarnings("unused")
 public class TestSchemaToProtoGenerator {
   @Test
@@ -117,8 +118,7 @@ public class TestSchemaToProtoGenerator {
         message testIntRequest {
           int32 value = 1;
         }
-
-        """, new ProtoToStringGenerator(proto).protoToString());
+        """.trim(), new ProtoToStringGenerator(proto).protoToString().trim());
 
     protoGenerator =
         new SchemaToProtoGenerator("test.int", openAPI,
@@ -134,8 +134,7 @@ public class TestSchemaToProtoGenerator {
         message testIntResponse {
           int32 value = 1;
         }
-
-        """, new ProtoToStringGenerator(proto).protoToString());
+        """.trim(), new ProtoToStringGenerator(proto).protoToString().trim());
   }
 
 
@@ -163,8 +162,7 @@ public class TestSchemaToProtoGenerator {
         message testModelRequest {
           Model value = 1;
         }
-
-        """, new ProtoToStringGenerator(proto).protoToString());
+        """.trim(), new ProtoToStringGenerator(proto).protoToString().trim());
 
     protoGenerator =
         new SchemaToProtoGenerator("test.model", openAPI,
@@ -185,7 +183,7 @@ public class TestSchemaToProtoGenerator {
         message testIntResponse {
           Model value = 1;
         }
-
-        """, new ProtoToStringGenerator(proto).protoToString());
+        """.trim(), new ProtoToStringGenerator(proto).protoToString().trim());
   }
 }
+//CHECKSTYLE:ON
diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java
index 108fb8722..ecc21f73f 100644
--- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java
+++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/RestProducerInvocationCreatorTest.java
@@ -17,7 +17,6 @@
 
 package org.apache.servicecomb.common.rest;
 
-import static jakarta.ws.rs.core.Response.Status.NOT_ACCEPTABLE;
 import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.catchThrowable;
@@ -50,7 +49,6 @@ import org.mockito.Mockito;
 
 import io.vertx.core.json.Json;
 import io.vertx.ext.web.RoutingContext;
-import jakarta.ws.rs.core.HttpHeaders;
 
 public class RestProducerInvocationCreatorTest {
 
diff --git a/pom.xml b/pom.xml
index 0f40c2972..0f8b4bb0c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,7 +44,7 @@
     <werror.properties></werror.properties>
     <!-- plugin version start -->
     <!-- sort by alpha -->
-    <checkstyle-maven-plugin.version>3.2.2</checkstyle-maven-plugin.version>
+    <checkstyle-maven-plugin.version>3.3.0</checkstyle-maven-plugin.version>
     <coveralls-maven-plugin.version>4.3.0</coveralls-maven-plugin.version>
     <dependency-check-maven-plugin.version>8.3.1</dependency-check-maven-plugin.version>
     <docker-maven-plugin.version>0.43.3</docker-maven-plugin.version>
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java
index b8da1ed61..6f6a591c6 100644
--- a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/SwaggerUtils.java
@@ -300,8 +300,8 @@ public final class SwaggerUtils {
       return false;
     }
     boolean result = true;
-    for (String key : properties1.keySet()) {
-      if (!schemaEquals(properties1.get(key), properties2.get(key))) {
+    for (Entry<String, Schema> item : properties1.entrySet()) {
+      if (!schemaEquals(item.getValue(), properties2.get(item.getKey()))) {
         result = false;
         break;
       }
diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/Echo.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/Echo.java
index 92d6d450b..48ac1256c 100644
--- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/Echo.java
+++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/Echo.java
@@ -80,28 +80,27 @@ public class Echo {
 
   }
 
-  // TODO: this should fail. RequestMapping not parse consumes and produces.
-  @RequestMapping("partArray")
+  @RequestMapping(value = "partArray", consumes = MediaType.MULTIPART_FORM_DATA)
   public void partArray(@RequestPart MultipartFile[] part) {
 
   }
 
-  @RequestMapping("partList")
+  @RequestMapping(value = "partList", consumes = MediaType.MULTIPART_FORM_DATA)
   public void partList(@RequestPart List<MultipartFile> part) {
 
   }
 
-  @RequestMapping("partAnnotation")
+  @RequestMapping(value = "partAnnotation", consumes = MediaType.MULTIPART_FORM_DATA)
   public void partAnnotation(@RequestPart MultipartFile part) {
 
   }
 
-  @RequestMapping("partArrayAnnotation")
+  @RequestMapping(value = "partArrayAnnotation", consumes = MediaType.MULTIPART_FORM_DATA)
   public void partArrayAnnotation(@RequestPart MultipartFile[] part) {
 
   }
 
-  @RequestMapping("partListAnnotation")
+  @RequestMapping(value = "partListAnnotation", consumes = MediaType.MULTIPART_FORM_DATA)
   public void partListAnnotation(@RequestPart List<MultipartFile> part) {
 
   }
diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodMixupAnnotations.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodMixupAnnotations.java
index 2513b4e91..5d93a2862 100644
--- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodMixupAnnotations.java
+++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/MethodMixupAnnotations.java
@@ -54,8 +54,8 @@ public class MethodMixupAnnotations {
   @RequestMapping(
       path = "usingRequestMapping/{targetName}",
       method = {RequestMethod.POST},
-      consumes = {"text/plain", "application/*"},
-      produces = {"text/plain", "application/*"})
+      consumes = {"text/plain", "application/json"},
+      produces = {"text/plain", "application/json"})
   public String usingRequestMapping(@RequestBody User srcUser, @RequestHeader String header,
       @PathVariable String targetName, @RequestParam(name = "word") String word) {
     return String.format("%s %s %s %s", srcUser.name, header, targetName, word);
@@ -63,8 +63,8 @@ public class MethodMixupAnnotations {
 
   @GetMapping(
       path = "usingGetMapping/{targetName}",
-      consumes = {"text/plain", "application/*"},
-      produces = {"text/plain", "application/*"})
+      consumes = {"text/plain", "application/json"},
+      produces = {"text/plain", "application/json"})
   public String usingGetMapping(@RequestBody User srcUser, @RequestHeader String header,
       @PathVariable String targetName, @RequestParam(name = "word") String word) {
     return String.format("%s %s %s %s", srcUser.name, header, targetName, word);
@@ -72,8 +72,8 @@ public class MethodMixupAnnotations {
 
   @PutMapping(
       path = "usingPutMapping/{targetName}",
-      consumes = {"text/plain", "application/*"},
-      produces = {"text/plain", "application/*"})
+      consumes = {"text/plain", "application/json"},
+      produces = {"text/plain", "application/json"})
   public String usingPutMapping(@RequestBody User srcUser, @RequestHeader String header,
       @PathVariable String targetName, @RequestParam(name = "word") String word) {
     return String.format("%s %s %s %s", srcUser.name, header, targetName, word);
@@ -81,8 +81,8 @@ public class MethodMixupAnnotations {
 
   @PostMapping(
       path = "usingPostMapping/{targetName}",
-      consumes = {"text/plain", "application/*"},
-      produces = {"text/plain", "application/*"})
+      consumes = {"text/plain", "application/json"},
+      produces = {"text/plain", "application/json"})
   public String usingPostMapping(@RequestBody User srcUser, @RequestHeader String header,
       @PathVariable String targetName, @RequestParam(name = "word") String word) {
     return String.format("%s %s %s %s", srcUser.name, header, targetName, word);
@@ -90,8 +90,8 @@ public class MethodMixupAnnotations {
 
   @PatchMapping(
       path = "usingPatchMapping/{targetName}",
-      consumes = {"text/plain", "application/*"},
-      produces = {"text/plain", "application/*"})
+      consumes = {"text/plain", "application/json"},
+      produces = {"text/plain", "application/json"})
   public String usingPatchMapping(@RequestBody User srcUser, @RequestHeader String header,
       @PathVariable String targetName, @RequestParam(name = "word") String word) {
     return String.format("%s %s %s %s", srcUser.name, header, targetName, word);
@@ -99,8 +99,8 @@ public class MethodMixupAnnotations {
 
   @DeleteMapping(
       path = "usingDeleteMapping/{targetName}",
-      consumes = {"text/plain", "application/*"},
-      produces = {"text/plain", "application/*"})
+      consumes = {"text/plain", "application/json"},
+      produces = {"text/plain", "application/json"})
   public String usingDeleteMapping(@RequestBody User srcUser, @RequestHeader String header,
       @PathVariable String targetName, @RequestParam(name = "word") String word) {
     return String.format("%s %s %s %s", srcUser.name, header, targetName, word);
diff --git a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/DefaultParameterSchema.java b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/DefaultParameterSchema.java
index bb987bc59..9a2bae4d5 100644
--- a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/DefaultParameterSchema.java
+++ b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/model/DefaultParameterSchema.java
@@ -43,7 +43,7 @@ public class DefaultParameterSchema {
     return null;
   }
 
-  @RequestMapping(path = "testSingleMediaType", method = RequestMethod.POST, consumes = MediaType.APPLICATION_XML, produces = MediaType.APPLICATION_XML)
+  @RequestMapping(path = "testSingleMediaType", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
   public String testSingleMediaType(String input) {
     return input;
   }
@@ -55,7 +55,7 @@ public class DefaultParameterSchema {
     return input;
   }
 
-  @RequestMapping(path = "testBlankMediaType", method = RequestMethod.POST, consumes = "", produces = "")
+  @RequestMapping(path = "testBlankMediaType", method = RequestMethod.POST)
   public String testBlankMediaType(String input) {
     return input;
   }
diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/DefaultParameterSchema.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/DefaultParameterSchema.yaml
index 42c4a2ad0..202825a95 100644
--- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/DefaultParameterSchema.yaml
+++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/DefaultParameterSchema.yaml
@@ -56,13 +56,10 @@ paths:
         "200":
           description: response of 200
           content:
-            application/json:
-              schema:
-                type: string
-            application/protobuf:
+            text/plain:
               schema:
                 type: string
-            text/plain:
+            application/json:
               schema:
                 type: string
   /testObjectParam:
@@ -127,12 +124,6 @@ paths:
             application/json:
               schema:
                 type: string
-            application/protobuf:
-              schema:
-                type: string
-            text/plain:
-              schema:
-                type: string
   /testUnsupportedParamType:
     get:
       operationId: testUnsupportedParamType
diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/echo.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/echo.yaml
index 77cc098d7..2553544fc 100644
--- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/echo.yaml
+++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/echo.yaml
@@ -35,11 +35,6 @@ paths:
                 type: array
                 items:
                   type: string
-            application/protobuf:
-              schema:
-                type: array
-                items:
-                  type: string
             text/plain:
               schema:
                 type: array
@@ -76,13 +71,6 @@ paths:
               - RED
               - YELLOW
               - BLUE
-          application/protobuf:
-            schema:
-              type: string
-              enum:
-              - RED
-              - YELLOW
-              - BLUE
           text/plain:
             schema:
               type: string
@@ -119,13 +107,6 @@ paths:
                 type: array
                 items:
                   type: string
-          application/protobuf:
-            schema:
-              type: array
-              items:
-                type: array
-                items:
-                  type: string
           text/plain:
             schema:
               type: array
@@ -146,13 +127,6 @@ paths:
                   type: array
                   items:
                     type: string
-            application/protobuf:
-              schema:
-                type: array
-                items:
-                  type: array
-                  items:
-                    type: string
             text/plain:
               schema:
                 type: array
@@ -285,9 +259,6 @@ paths:
             application/json:
               schema:
                 type: string
-            application/protobuf:
-              schema:
-                type: string
             text/plain:
               schema:
                 type: string
@@ -301,9 +272,6 @@ paths:
             application/json:
               schema:
                 type: string
-            application/protobuf:
-              schema:
-                type: string
             text/plain:
               schema:
                 type: string
diff --git a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/mixupAnnotations.yaml b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/mixupAnnotations.yaml
index 121f96127..bf5794890 100644
--- a/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/mixupAnnotations.yaml
+++ b/swagger/swagger-generator/generator-springmvc/src/test/resources/schemas/mixupAnnotations.yaml
@@ -144,12 +144,6 @@ paths:
         "200":
           description: response of 200
           content:
-            application/json:
-              schema:
-                type: string
-            application/protobuf:
-              schema:
-                type: string
             text/plain:
               schema:
                 type: string
@@ -369,13 +363,10 @@ paths:
           type: string
       requestBody:
         content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/User'
-          application/protobuf:
+          text/plain:
             schema:
               $ref: '#/components/schemas/User'
-          text/plain:
+          application/json:
             schema:
               $ref: '#/components/schemas/User'
         required: true
@@ -384,13 +375,10 @@ paths:
         "200":
           description: response of 200
           content:
-            application/json:
-              schema:
-                type: string
-            application/protobuf:
+            text/plain:
               schema:
                 type: string
-            text/plain:
+            application/json:
               schema:
                 type: string
   /usingGetMapping/{targetName}:
@@ -414,13 +402,10 @@ paths:
           type: string
       requestBody:
         content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/User'
-          application/protobuf:
+          text/plain:
             schema:
               $ref: '#/components/schemas/User'
-          text/plain:
+          application/json:
             schema:
               $ref: '#/components/schemas/User'
         required: true
@@ -429,13 +414,10 @@ paths:
         "200":
           description: response of 200
           content:
-            application/json:
-              schema:
-                type: string
-            application/protobuf:
+            text/plain:
               schema:
                 type: string
-            text/plain:
+            application/json:
               schema:
                 type: string
   /usingPatchMapping/{targetName}:
@@ -459,13 +441,10 @@ paths:
           type: string
       requestBody:
         content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/User'
-          application/protobuf:
+          text/plain:
             schema:
               $ref: '#/components/schemas/User'
-          text/plain:
+          application/json:
             schema:
               $ref: '#/components/schemas/User'
         required: true
@@ -474,13 +453,10 @@ paths:
         "200":
           description: response of 200
           content:
-            application/json:
-              schema:
-                type: string
-            application/protobuf:
+            text/plain:
               schema:
                 type: string
-            text/plain:
+            application/json:
               schema:
                 type: string
   /usingPostMapping/{targetName}:
@@ -504,13 +480,10 @@ paths:
           type: string
       requestBody:
         content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/User'
-          application/protobuf:
+          text/plain:
             schema:
               $ref: '#/components/schemas/User'
-          text/plain:
+          application/json:
             schema:
               $ref: '#/components/schemas/User'
         required: true
@@ -519,13 +492,10 @@ paths:
         "200":
           description: response of 200
           content:
-            application/json:
-              schema:
-                type: string
-            application/protobuf:
+            text/plain:
               schema:
                 type: string
-            text/plain:
+            application/json:
               schema:
                 type: string
   /usingPutMapping/{targetName}:
@@ -549,13 +519,10 @@ paths:
           type: string
       requestBody:
         content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/User'
-          application/protobuf:
+          text/plain:
             schema:
               $ref: '#/components/schemas/User'
-          text/plain:
+          application/json:
             schema:
               $ref: '#/components/schemas/User'
         required: true
@@ -564,13 +531,10 @@ paths:
         "200":
           description: response of 200
           content:
-            application/json:
-              schema:
-                type: string
-            application/protobuf:
+            text/plain:
               schema:
                 type: string
-            text/plain:
+            application/json:
               schema:
                 type: string
   /usingRequestMapping/{targetName}:
@@ -594,13 +558,10 @@ paths:
           type: string
       requestBody:
         content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/User'
-          application/protobuf:
+          text/plain:
             schema:
               $ref: '#/components/schemas/User'
-          text/plain:
+          application/json:
             schema:
               $ref: '#/components/schemas/User'
         required: true
@@ -609,13 +570,10 @@ paths:
         "200":
           description: response of 200
           content:
-            application/json:
-              schema:
-                type: string
-            application/protobuf:
+            text/plain:
               schema:
                 type: string
-            text/plain:
+            application/json:
               schema:
                 type: string
 components: