You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2023/07/17 05:29:16 UTC

[dubbo] branch 3.3 updated: add rest provider body multipart json that JsonUtils supports ut (#12716)

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

liujun pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.3 by this push:
     new f78b4f5dea add rest provider body multipart  json that JsonUtils supports ut (#12716)
f78b4f5dea is described below

commit f78b4f5deaea9405430bb3b895aaf31dd8d0cb30
Author: suncairong163 <10...@users.noreply.github.com>
AuthorDate: Mon Jul 17 13:29:10 2023 +0800

    add rest provider body multipart  json that JsonUtils supports ut (#12716)
---
 .../AbstractNoAnnotatedParameterProcessor.java     | 13 +++++++--
 .../org/apache/dubbo/metadata/rest/ArgInfo.java    | 11 +++++++
 dubbo-rpc/dubbo-rpc-rest/pom.xml                   |  6 ++++
 .../dubbo/rpc/protocol/rest/RestInvoker.java       |  6 ++--
 .../rest/annotation/ParamParserManager.java        | 17 +++++------
 .../consumer/inercept/RequestHeaderIntercept.java  |  2 +-
 .../parse/provider/BodyProviderParamParser.java    |  3 +-
 .../parse/provider/HeaderProviderParamParser.java  |  1 -
 .../NoAnnotationParamProviderParamParser.java      | 14 ++++-----
 .../rest/message/HttpMessageCodecManager.java      |  5 ++--
 .../protocol/rest/message/HttpMessageDecode.java   |  7 +++--
 .../rest/message/codec/ByteArrayCodec.java         |  3 +-
 .../rpc/protocol/rest/message/codec/JsonCodec.java | 15 ++++++----
 .../rest/message/codec/MultiValueCodec.java        |  4 +--
 .../rest/message/codec/ResteasyResponseCodec.java  |  9 ++++--
 .../protocol/rest/message/codec/StringCodec.java   |  3 +-
 .../rpc/protocol/rest/message/codec/TextCodec.java |  3 +-
 .../rpc/protocol/rest/message/codec/XMLCodec.java  |  3 +-
 .../rpc/protocol/rest/util/DataParseUtils.java     |  3 +-
 .../rest/util/NoAnnotationBodyParseUtil.java       |  2 +-
 .../rpc/protocol/rest/DataParseUtilsTest.java      |  4 +--
 .../dubbo/rpc/protocol/rest/DemoService.java       | 21 +++++++++++++
 .../dubbo/rpc/protocol/rest/DemoServiceImpl.java   | 34 ++++++++++++++++++++--
 .../protocol/rest/HttpMessageCodecManagerTest.java |  2 +-
 .../rest/NoAnnotationRestProtocolTest.java         | 25 +++++++++++++---
 .../org/apache/dubbo/rpc/protocol/rest/User.java   | 14 +++++++++
 .../rest/noannotation/NoAnnotationDemoService.java |  6 +++-
 .../noannotation/NoAnnotationDemoServiceImpl.java  |  9 +++++-
 28 files changed, 187 insertions(+), 58 deletions(-)

diff --git a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/AbstractNoAnnotatedParameterProcessor.java b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/AbstractNoAnnotatedParameterProcessor.java
index 4541e52761..b4975dc0c6 100644
--- a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/AbstractNoAnnotatedParameterProcessor.java
+++ b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/AbstractNoAnnotatedParameterProcessor.java
@@ -16,6 +16,7 @@
  */
 package org.apache.dubbo.metadata.rest;
 
+import org.apache.dubbo.metadata.rest.jaxrs.JAXRSServiceRestMetadataResolver;
 import org.apache.dubbo.metadata.rest.media.MediaType;
 
 import java.lang.reflect.Parameter;
@@ -39,8 +40,16 @@ public abstract class AbstractNoAnnotatedParameterProcessor implements NoAnnotat
     private boolean contentTypeSupport(RestMethodMetadata restMethodMetadata, MediaType mediaType, Class paramType) {
 
         // @RequestParam String,number param
-        if (mediaType.equals(MediaType.ALL_VALUE) && (String.class == paramType || paramType.isPrimitive() || Number.class.isAssignableFrom(paramType))) {
-            return true;
+        if (mediaType.equals(MediaType.ALL_VALUE)) {
+             // jaxrs no annotation param is from http body
+            if (JAXRSServiceRestMetadataResolver.class.equals(restMethodMetadata.getCodeStyle())) {
+                return true;
+            }
+
+            // spring mvc no annotation param only is used by text data(string,number)
+            if (String.class == paramType || paramType.isPrimitive() || Number.class.isAssignableFrom(paramType)) {
+                return true;
+            }
         }
 
         Set<String> consumes = restMethodMetadata.getRequest().getConsumes();
diff --git a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/ArgInfo.java b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/ArgInfo.java
index a93b2e90e8..9c8a96550c 100644
--- a/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/ArgInfo.java
+++ b/dubbo-metadata/dubbo-metadata-rest/src/main/java/org/apache/dubbo/metadata/rest/ArgInfo.java
@@ -18,6 +18,7 @@ package org.apache.dubbo.metadata.rest;
 
 
 import java.lang.reflect.Parameter;
+import java.lang.reflect.Type;
 
 /**
  * description of service method args info
@@ -42,6 +43,11 @@ public class ArgInfo {
      */
     private Class paramType;
 
+    /**
+     *  param actual Type(collection,map,array)
+     */
+    private Type actualType;
+
     /**
      * param name
      */
@@ -64,6 +70,7 @@ public class ArgInfo {
 
     public ArgInfo(int index, Parameter parameter) {
         this(index, parameter.getName(), parameter.getType());
+        this.actualType = parameter.getParameterizedType();
     }
 
     public ArgInfo() {
@@ -152,6 +159,10 @@ public class ArgInfo {
         return this;
     }
 
+    public Type actualReflectType() {
+        return actualType;
+    }
+
     @Override
     public String toString() {
         return "ArgInfo{" +
diff --git a/dubbo-rpc/dubbo-rpc-rest/pom.xml b/dubbo-rpc/dubbo-rpc-rest/pom.xml
index e9fdd48a5b..62016fe4d7 100644
--- a/dubbo-rpc/dubbo-rpc-rest/pom.xml
+++ b/dubbo-rpc/dubbo-rpc-rest/pom.xml
@@ -150,6 +150,12 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <scope>test</scope>
+        </dependency>
+    
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-openfeign-core</artifactId>
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestInvoker.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestInvoker.java
index 09266c950a..a012dd8e44 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestInvoker.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/RestInvoker.java
@@ -40,6 +40,7 @@ import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodecManager;
 import org.apache.dubbo.rpc.protocol.rest.util.HttpHeaderUtil;
 import org.apache.dubbo.rpc.protocol.rest.util.MediaTypeUtil;
 
+import java.lang.reflect.Method;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
@@ -100,9 +101,10 @@ public class RestInvoker<T> extends AbstractInvoker<T> {
                         } else if (responseCode >= 500) {
                             responseFuture.completeExceptionally(new RemoteServerInternalException(r.getMessage()));
                         } else if (responseCode < 400) {
-                            mediaType = MediaTypeUtil.convertMediaType(restMethodMetadata.getReflectMethod().getReturnType(), r.getContentType());
+                            Method reflectMethod = restMethodMetadata.getReflectMethod();
+                            mediaType = MediaTypeUtil.convertMediaType(reflectMethod.getReturnType(), r.getContentType());
                             Object value = HttpMessageCodecManager.httpMessageDecode(r.getBody(),
-                                restMethodMetadata.getReflectMethod().getReturnType(), mediaType);
+                                reflectMethod.getReturnType(), reflectMethod.getGenericReturnType(), mediaType);
                             appResponse.setValue(value);
                             // resolve response attribute & attachment
                             HttpHeaderUtil.parseResponseHeader(appResponse, r);
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/ParamParserManager.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/ParamParserManager.java
index 90bea5b9ee..7f2ac44ec3 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/ParamParserManager.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/ParamParserManager.java
@@ -25,16 +25,15 @@ import org.apache.dubbo.rpc.protocol.rest.annotation.param.parse.provider.BasePr
 import org.apache.dubbo.rpc.protocol.rest.annotation.param.parse.provider.ProviderParseContext;
 
 import java.util.List;
-import java.util.Set;
 
 public class ParamParserManager {
 
 
-    private static final Set<BaseConsumerParamParser> consumerParamParsers =
-        FrameworkModel.defaultModel().getExtensionLoader(BaseConsumerParamParser.class).getSupportedExtensionInstances();
+    private static final List<BaseConsumerParamParser> consumerParamParsers =
+        FrameworkModel.defaultModel().getExtensionLoader(BaseConsumerParamParser.class).getActivateExtensions();
 
-    private static final Set<BaseProviderParamParser> providerParamParsers =
-        FrameworkModel.defaultModel().getExtensionLoader(BaseProviderParamParser.class).getSupportedExtensionInstances();
+    private static final List<BaseProviderParamParser> providerParamParsers =
+        FrameworkModel.defaultModel().getExtensionLoader(BaseProviderParamParser.class).getActivateExtensions();
 
     /**
      * provider  Design Description:
@@ -53,11 +52,11 @@ public class ParamParserManager {
         for (int i = 0; i < args.size(); i++) {
             for (BaseProviderParamParser paramParser : providerParamParsers) {
 
-                if (!paramParser.matchParseType(args.get(i).getParamAnnotationType())) {
-                    continue;
+                if (paramParser.matchParseType(args.get(i).getParamAnnotationType())) {
+                    paramParser.parse(parseContext, args.get(i));
+                    // one arg only can be parsed by one parser
+                    break;
                 }
-
-                paramParser.parse(parseContext, args.get(i));
             }
         }
         // TODO add param require or default & body arg size pre judge
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/consumer/inercept/RequestHeaderIntercept.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/consumer/inercept/RequestHeaderIntercept.java
index a2c1ce5abc..3ec4bbbaa8 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/consumer/inercept/RequestHeaderIntercept.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/consumer/inercept/RequestHeaderIntercept.java
@@ -49,7 +49,7 @@ public class RequestHeaderIntercept implements HttpConnectionPreBuildIntercept {
         if (produces == null || produces.isEmpty()) {
             requestTemplate.addHeader(RestHeaderEnum.ACCEPT.getHeader(), RestConstant.DEFAULT_ACCEPT);
         } else {
-            requestTemplate.addHeader(RestHeaderEnum.ACCEPT.getHeader(), produces);
+            requestTemplate.addHeaders(RestHeaderEnum.ACCEPT.getHeader(), produces);
         }
 
 //        URL url = connectionCreateContext.getUrl();
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/BodyProviderParamParser.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/BodyProviderParamParser.java
index 9da9d428ea..a92d5cf51f 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/BodyProviderParamParser.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/BodyProviderParamParser.java
@@ -28,7 +28,6 @@ import org.apache.dubbo.rpc.protocol.rest.request.RequestFacade;
 import org.apache.dubbo.rpc.protocol.rest.util.MediaTypeUtil;
 
 
-
 /**
  * body param parse
  */
@@ -43,7 +42,7 @@ public class BodyProviderParamParser extends ProviderParamParser {
         try {
             String contentType = parseContext.getRequestFacade().getHeader(RestHeaderEnum.CONTENT_TYPE.getHeader());
             MediaType mediaType = MediaTypeUtil.convertMediaType(argInfo.getParamType(), contentType);
-            Object param = HttpMessageCodecManager.httpMessageDecode(request.getInputStream(), argInfo.getParamType(), mediaType);
+            Object param = HttpMessageCodecManager.httpMessageDecode(request.getInputStream(), argInfo.getParamType(), argInfo.actualReflectType(), mediaType);
             parseContext.setValueByIndex(argInfo.getIndex(), param);
         } catch (Throwable e) {
             throw new ParamParseException("dubbo rest protocol provider body param parser  error: " + e.getMessage());
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/HeaderProviderParamParser.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/HeaderProviderParamParser.java
index 88d0abf4c3..43990a2d84 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/HeaderProviderParamParser.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/HeaderProviderParamParser.java
@@ -33,7 +33,6 @@ public class HeaderProviderParamParser extends ProviderParamParser {
     @Override
     protected void doParse(ProviderParseContext parseContext, ArgInfo argInfo) {
 
-        //TODO MAP<String,String> convert
         RequestFacade request = parseContext.getRequestFacade();
         if (Map.class.isAssignableFrom(argInfo.getParamType())) {
 
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/NoAnnotationParamProviderParamParser.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/NoAnnotationParamProviderParamParser.java
index 7553ec5ba1..0970232d6b 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/NoAnnotationParamProviderParamParser.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/annotation/param/parse/provider/NoAnnotationParamProviderParamParser.java
@@ -21,13 +21,15 @@ import org.apache.dubbo.common.utils.JsonUtils;
 import org.apache.dubbo.metadata.rest.ArgInfo;
 import org.apache.dubbo.metadata.rest.ParamType;
 import org.apache.dubbo.rpc.protocol.rest.constans.RestConstant;
-import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils;
 
 
 /**
  * body param parse
+ * users can custom NoAnnotationParamProviderParamParser
+ * and getParamType must return ParamType.PROVIDER_NO_ANNOTATION
+ * and order is smaller than NoAnnotationParamProviderParamParser`s order
  */
-@Activate(value = RestConstant.PROVIDER_NO_ANNOTATION)
+@Activate(value = RestConstant.PROVIDER_NO_ANNOTATION, order = Integer.MAX_VALUE)
 public class NoAnnotationParamProviderParamParser extends ProviderParamParser {
 
     @Override
@@ -39,13 +41,7 @@ public class NoAnnotationParamProviderParamParser extends ProviderParamParser {
 
         Object arg = arrayArgs[index];
 
-        Object convertArg = null;
-
-        if (DataParseUtils.isTextType(argInfo.getParamType())) {
-            convertArg = DataParseUtils.stringTypeConvert(argInfo.getParamType(), String.valueOf(arg));
-        } else {
-            convertArg = JsonUtils.toJavaObject(arg.toString(), argInfo.getParamType());
-        }
+        Object convertArg = JsonUtils.toJavaObject(JsonUtils.toJson(arg), argInfo.actualReflectType());
 
         parseContext.setValueByIndex(index, convertArg);
 
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/HttpMessageCodecManager.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/HttpMessageCodecManager.java
index 27b6ef57e7..eb34605eda 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/HttpMessageCodecManager.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/HttpMessageCodecManager.java
@@ -23,6 +23,7 @@ import org.apache.dubbo.rpc.protocol.rest.exception.UnSupportContentTypeExceptio
 import org.apache.dubbo.rpc.protocol.rest.pair.MessageCodecResultPair;
 
 import java.io.OutputStream;
+import java.lang.reflect.Type;
 import java.util.Set;
 
 public class HttpMessageCodecManager {
@@ -30,14 +31,14 @@ public class HttpMessageCodecManager {
         FrameworkModel.defaultModel().getExtensionLoader(HttpMessageCodec.class).getSupportedExtensionInstances();
 
 
-    public static Object httpMessageDecode(byte[] body, Class<?> type, MediaType mediaType) throws Exception {
+    public static Object httpMessageDecode(byte[] body, Class<?> type, Type actualType, MediaType mediaType) throws Exception {
         if (body == null || body.length == 0) {
             return null;
         }
 
         for (HttpMessageCodec httpMessageCodec : httpMessageCodecs) {
             if (httpMessageCodec.contentTypeSupport(mediaType, type) || typeJudge(mediaType, type, httpMessageCodec)) {
-                return httpMessageCodec.decode(body, type);
+                return httpMessageCodec.decode(body, type,actualType);
             }
         }
         throw new UnSupportContentTypeException("UnSupport content-type :" + mediaType.value);
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/HttpMessageDecode.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/HttpMessageDecode.java
index cf3b639b33..b072a8a9c2 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/HttpMessageDecode.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/HttpMessageDecode.java
@@ -17,8 +17,11 @@
 package org.apache.dubbo.rpc.protocol.rest.message;
 
 
-public interface HttpMessageDecode<InputStream>{
+import java.lang.reflect.Type;
+
+public interface HttpMessageDecode<InputStream> {
+
+    Object decode(InputStream body, Class<?> targetType,Type actualTYpe) throws Exception;
 
-    Object decode(InputStream body, Class<?> targetType) throws Exception;
 
 }
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/ByteArrayCodec.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/ByteArrayCodec.java
index 85dea16e00..ff15fc5663 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/ByteArrayCodec.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/ByteArrayCodec.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.metadata.rest.media.MediaType;
 import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec;
 
 import java.io.OutputStream;
+import java.lang.reflect.Type;
 
 /**
  *  body type is byte array
@@ -31,7 +32,7 @@ public class ByteArrayCodec implements HttpMessageCodec<byte[], OutputStream> {
 
 
     @Override
-    public Object decode(byte[] body, Class<?> targetType) throws Exception {
+    public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
         return body;
     }
 
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java
index 8ff5f2b60f..96fde0a09a 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/JsonCodec.java
@@ -23,14 +23,15 @@ import org.apache.dubbo.metadata.rest.media.MediaType;
 import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec;
 import org.apache.dubbo.rpc.protocol.rest.message.MediaTypeMatcher;
 import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils;
-import javax.ws.rs.core.Response;
+
 import java.io.OutputStream;
+import java.lang.reflect.Type;
 import java.nio.charset.StandardCharsets;
 import java.util.HashSet;
 import java.util.Set;
 
 /**
- *  body is json
+ * body is json
  */
 @Activate("json")
 public class JsonCodec implements HttpMessageCodec<byte[], OutputStream> {
@@ -39,12 +40,11 @@ public class JsonCodec implements HttpMessageCodec<byte[], OutputStream> {
     static {
         unSupportClasses.add(byte[].class);
         unSupportClasses.add(String.class);
-        unSupportClasses.add(Response.class);
     }
 
     @Override
-    public Object decode(byte[] body, Class<?> targetType) throws Exception {
-        return DataParseUtils.jsonConvert(targetType, body);
+    public Object decode(byte[] body, Class<?> targetType, Type actualType) throws Exception {
+        return DataParseUtils.jsonConvert(actualType, body);
     }
 
     @Override
@@ -67,4 +67,9 @@ public class JsonCodec implements HttpMessageCodec<byte[], OutputStream> {
     public void encode(OutputStream outputStream, Object unSerializedBody, URL url) throws Exception {
         outputStream.write(JsonUtils.toJson(unSerializedBody).getBytes(StandardCharsets.UTF_8));
     }
+
+
+    public static final void addUnSupportClass(Class<?> unSupportClass) {
+        unSupportClasses.add(unSupportClass);
+    }
 }
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/MultiValueCodec.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/MultiValueCodec.java
index b41955e8e9..ee11bb5954 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/MultiValueCodec.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/MultiValueCodec.java
@@ -26,6 +26,7 @@ import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils;
 
 import java.io.OutputStream;
 import java.lang.reflect.Field;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -39,8 +40,7 @@ public class MultiValueCodec implements HttpMessageCodec<byte[], OutputStream> {
 
 
     @Override
-    public Object decode(byte[] body, Class<?> targetType) throws Exception {
-        // TODO java bean  get set convert
+    public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
         Object map = DataParseUtils.multipartFormConvert(body,targetType);
         Map valuesMap = (Map) map;
         if (Map.class.isAssignableFrom(targetType)) {
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/ResteasyResponseCodec.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/ResteasyResponseCodec.java
index 31fe9e2db9..9717df88d7 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/ResteasyResponseCodec.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/ResteasyResponseCodec.java
@@ -26,15 +26,18 @@ import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec;
 
 import java.io.OutputStream;
 import java.lang.reflect.Method;
+import java.lang.reflect.Type;
 import java.nio.charset.StandardCharsets;
 
-@Activate(onClass="javax.ws.rs.core.Response")
+@Activate(onClass = "javax.ws.rs.core.Response")
 public class ResteasyResponseCodec implements HttpMessageCodec<byte[], OutputStream> {
 
     private Class<?> responseClass;
-    public ResteasyResponseCodec(){
+
+    public ResteasyResponseCodec() {
         try {
             responseClass = ClassUtils.forName("javax.ws.rs.core.Response");
+            JsonCodec.addUnSupportClass(responseClass);
         } catch (Exception exception) {
             responseClass = null;
         }
@@ -56,7 +59,7 @@ public class ResteasyResponseCodec implements HttpMessageCodec<byte[], OutputStr
     }
 
     @Override
-    public Object decode(byte[] body, Class<?> targetType) throws Exception {
+    public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
         if (null == body || body.length == 0) {
             return null;
         }
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/StringCodec.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/StringCodec.java
index d30b2e5a11..726c007f67 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/StringCodec.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/StringCodec.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.metadata.rest.media.MediaType;
 import org.apache.dubbo.rpc.protocol.rest.message.HttpMessageCodec;
 
 import java.io.OutputStream;
+import java.lang.reflect.Type;
 import java.nio.charset.StandardCharsets;
 
 /**
@@ -32,7 +33,7 @@ public class StringCodec implements HttpMessageCodec<byte[], OutputStream> {
 
 
     @Override
-    public Object decode(byte[] body, Class<?> targetType) throws Exception {
+    public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
         if (body == null || body.length == 0) {
             return null;
         }
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/TextCodec.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/TextCodec.java
index 63c06876f8..69c4eaa35a 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/TextCodec.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/TextCodec.java
@@ -24,6 +24,7 @@ import org.apache.dubbo.rpc.protocol.rest.message.MediaTypeMatcher;
 import org.apache.dubbo.rpc.protocol.rest.util.DataParseUtils;
 
 import java.io.OutputStream;
+import java.lang.reflect.Type;
 import java.nio.charset.StandardCharsets;
 
 /**
@@ -33,7 +34,7 @@ import java.nio.charset.StandardCharsets;
 public class TextCodec implements HttpMessageCodec<byte[], OutputStream> {
 
     @Override
-    public Object decode(byte[] body, Class<?> targetType) throws Exception {
+    public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
         return DataParseUtils.stringTypeConvert(targetType, new String(body, StandardCharsets.UTF_8));
     }
 
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/XMLCodec.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/XMLCodec.java
index d58fd9e8de..d24d27a85f 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/XMLCodec.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/message/codec/XMLCodec.java
@@ -32,6 +32,7 @@ import javax.xml.transform.Source;
 import javax.xml.transform.sax.SAXSource;
 import java.io.OutputStream;
 import java.io.StringReader;
+import java.lang.reflect.Type;
 
 /**
  *  body content-type is xml
@@ -41,7 +42,7 @@ public class XMLCodec implements HttpMessageCodec<byte[], OutputStream> {
 
 
     @Override
-    public Object decode(byte[] body, Class<?> targetType) throws Exception {
+    public Object decode(byte[] body, Class<?> targetType, Type type) throws Exception {
 
 
         SAXParserFactory spf = SAXParserFactory.newInstance();
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/util/DataParseUtils.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/util/DataParseUtils.java
index 4501c7972d..9737c152c4 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/util/DataParseUtils.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/util/DataParseUtils.java
@@ -22,6 +22,7 @@ import org.apache.dubbo.common.utils.StringUtils;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Type;
 import java.net.URLDecoder;
 import java.net.URLEncoder;
 import java.nio.charset.Charset;
@@ -151,7 +152,7 @@ public class DataParseUtils {
 
     }
 
-    public static Object jsonConvert(Class targetType, byte[] body) throws Exception {
+    public static Object jsonConvert(Type targetType, byte[] body) throws Exception {
         return JsonUtils.toJavaObject(new String(body, StandardCharsets.UTF_8), targetType);
     }
 
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/util/NoAnnotationBodyParseUtil.java b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/util/NoAnnotationBodyParseUtil.java
index c6abf12fef..11ecc4fc95 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/util/NoAnnotationBodyParseUtil.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/main/java/org/apache/dubbo/rpc/protocol/rest/util/NoAnnotationBodyParseUtil.java
@@ -30,7 +30,7 @@ public class NoAnnotationBodyParseUtil {
         try {
             Class<?> objectArraysType = Object[].class;
             MediaType mediaType = MediaTypeUtil.convertMediaType(objectArraysType, MediaType.APPLICATION_JSON_VALUE.value);
-            Object[] params = (Object[]) HttpMessageCodecManager.httpMessageDecode(request.getInputStream(), objectArraysType, mediaType);
+            Object[] params = (Object[]) HttpMessageCodecManager.httpMessageDecode(request.getInputStream(), objectArraysType, objectArraysType, mediaType);
             return params;
         } catch (Throwable e) {
             throw new ParamParseException("dubbo rest protocol provider body param parser  error: " + e.getMessage());
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DataParseUtilsTest.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DataParseUtilsTest.java
index ae29327019..93b8ed9585 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DataParseUtilsTest.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DataParseUtilsTest.java
@@ -29,8 +29,8 @@ public class DataParseUtilsTest {
         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
         DataParseUtils.writeJsonContent(User.getInstance(), byteArrayOutputStream);
 
-        Assertions.assertEquals("{\"age\":18,\"id\":404,\"name\":\"dubbo\"}",
-            new String(byteArrayOutputStream.toByteArray()));
+        Assertions.assertEquals("{\"age\":18,\"id\":404,\"name\":\"dubbo\"}".getBytes().length,
+            byteArrayOutputStream.toByteArray().length);
 
 
     }
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DemoService.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DemoService.java
index 85e61837d8..5ffa788828 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DemoService.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DemoService.java
@@ -31,6 +31,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 @Path("/demoService")
 public interface DemoService {
@@ -128,4 +129,24 @@ public interface DemoService {
     @Consumes({MediaType.APPLICATION_JSON})
     User noBodyArg(User user);
 
+    @POST
+    @Path("/list")
+    List<User> list(List<User> users);
+
+    @POST
+    @Path("/set")
+    Set<User> set(Set<User> users);
+
+    @POST
+    @Path("/array")
+    User[] array(User[] users);
+
+    @POST
+    @Path("/stringMap")
+    Map<String, User> stringMap(Map<String,User> userMap);
+
+    @POST
+    @Path("/map")
+    Map<User, User> userMap(Map<User,User> userMap);
+
 }
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DemoServiceImpl.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DemoServiceImpl.java
index f5e7c2369a..ea385a9283 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DemoServiceImpl.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/DemoServiceImpl.java
@@ -30,6 +30,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 @Path("/demoService")
 public class DemoServiceImpl implements DemoService {
@@ -91,7 +92,7 @@ public class DemoServiceImpl implements DemoService {
     }
 
     @Override
-    public List<String> testMapForm(MultivaluedMap<String,String> params) {
+    public List<String> testMapForm(MultivaluedMap<String, String> params) {
         return params.get("form");
     }
 
@@ -120,7 +121,7 @@ public class DemoServiceImpl implements DemoService {
     @Path("/noIntHeader")
     @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})
     @Override
-    public int noIntHeader(@HeaderParam("header")int header) {
+    public int noIntHeader(@HeaderParam("header") int header) {
         return header;
     }
 
@@ -128,7 +129,7 @@ public class DemoServiceImpl implements DemoService {
     @Path("/noIntParam")
     @Consumes({javax.ws.rs.core.MediaType.TEXT_PLAIN})
     @Override
-    public int noIntParam(@QueryParam("header")int header) {
+    public int noIntParam(@QueryParam("header") int header) {
         return header;
     }
 
@@ -156,4 +157,31 @@ public class DemoServiceImpl implements DemoService {
     public static Map<String, Object> getAttachments() {
         return context;
     }
+
+
+    @Override
+    public List<User> list(List<User> users) {
+        return users;
+    }
+
+    @Override
+    public Set<User> set(Set<User> users) {
+        return users;
+    }
+
+    @Override
+    public User[] array(User[] users) {
+        return users;
+    }
+
+    @Override
+    public Map<String, User> stringMap(Map<String, User> userMap) {
+        return userMap;
+    }
+
+    @Override
+    public Map<User, User> userMap(Map<User, User> userMap) {
+        return userMap;
+    }
+
 }
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/HttpMessageCodecManagerTest.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/HttpMessageCodecManagerTest.java
index 1f514ba8e5..b0f368e74b 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/HttpMessageCodecManagerTest.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/HttpMessageCodecManagerTest.java
@@ -37,7 +37,7 @@ public class HttpMessageCodecManagerTest {
         HttpMessageCodecManager.httpMessageEncode(byteArrayOutputStream,
             registrationResult, null, MediaType.TEXT_XML, null);
 
-        Object o = HttpMessageCodecManager.httpMessageDecode(byteArrayOutputStream.toByteArray(), RegistrationResult.class, MediaType.TEXT_XML);
+        Object o = HttpMessageCodecManager.httpMessageDecode(byteArrayOutputStream.toByteArray(), RegistrationResult.class, RegistrationResult.class, MediaType.TEXT_XML);
 
         Assertions.assertEquals(registrationResult, o);
 
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/NoAnnotationRestProtocolTest.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/NoAnnotationRestProtocolTest.java
index 1d40f2c612..3d8ad1b2fe 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/NoAnnotationRestProtocolTest.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/NoAnnotationRestProtocolTest.java
@@ -17,7 +17,9 @@
 package org.apache.dubbo.rpc.protocol.rest;
 
 import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
 import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.utils.JsonUtils;
 import org.apache.dubbo.common.utils.NetUtils;
 
 import org.apache.dubbo.rpc.Exporter;
@@ -38,14 +40,14 @@ import org.junit.jupiter.api.Assertions;
 
 import org.junit.jupiter.api.Test;
 
+import java.util.Arrays;
+import java.util.List;
+
 
 class NoAnnotationRestProtocolTest {
     private final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getExtension("rest");
     private final ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
-    private final int availablePort = NetUtils.getAvailablePort();
-    private final URL exportUrl = URL.valueOf("rest://127.0.0.1:" + availablePort + "/rest?interface=org.apache.dubbo.rpc.protocol.rest.noannotation.NoAnnotationDemoService");
     private final ModuleServiceRepository repository = ApplicationModel.defaultModel().getDefaultModule().getServiceRepository();
-    private static final String SERVER = "netty4";
 
     @AfterEach
     public void tearDown() {
@@ -54,6 +56,19 @@ class NoAnnotationRestProtocolTest {
     }
 
     @Test
+    void testJson() {
+        List<String> jsons = Arrays.asList("fastjson", "fastjson2", "jackson", "gson");
+        for (String json : jsons) {
+            new JsonUtils() {
+                public void clearJson() {
+                    setJson(null);
+                }
+            }.clearJson();
+            System.setProperty(CommonConstants.PREFER_JSON_FRAMEWORK_NAME, json);
+            testRestProtocol();
+        }
+    }
+
     void testRestProtocol() {
         URL url = URL.valueOf("rest://127.0.0.1:" + NetUtils.getAvailablePort() + "/?version=1.0.0&interface=org.apache.dubbo.rpc.protocol.rest.noannotation.NoAnnotationDemoService");
 
@@ -72,9 +87,11 @@ class NoAnnotationRestProtocolTest {
         result = client.hello(1, 2);
         Assertions.assertEquals(3, result);
 
-        User user = client.noBodyArg(User.getInstance());
+        User user = client.user(User.getInstance());
         Assertions.assertEquals("invoked", user.getName());
 
+        Assertions.assertEquals(User.getInstance(),client.userList(Arrays.asList(User.getInstance())).get(0));
+
 
         invoker.destroy();
         exporter.unexport();
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/User.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/User.java
index bb16caea7d..b877e2072c 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/User.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/User.java
@@ -17,6 +17,7 @@
 package org.apache.dubbo.rpc.protocol.rest;
 
 import java.io.Serializable;
+import java.util.Objects;
 
 /**
  * User Entity
@@ -63,6 +64,19 @@ public class User implements Serializable {
         return user;
     }
 
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        User user = (User) o;
+        return Objects.equals(id, user.id) && Objects.equals(name, user.name) && Objects.equals(age, user.age);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id, name, age);
+    }
+
     @Override
     public String toString() {
         return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/noannotation/NoAnnotationDemoService.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/noannotation/NoAnnotationDemoService.java
index 5811819a27..8970ebaf2a 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/noannotation/NoAnnotationDemoService.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/noannotation/NoAnnotationDemoService.java
@@ -19,6 +19,8 @@ package org.apache.dubbo.rpc.protocol.rest.noannotation;
 
 import org.apache.dubbo.rpc.protocol.rest.User;
 
+import java.util.List;
+
 
 public interface NoAnnotationDemoService {
     Integer hello(Integer a, Integer b);
@@ -27,6 +29,8 @@ public interface NoAnnotationDemoService {
 
     String sayHello(String name);
 
-    User noBodyArg(User user);
+    User user(User user);
+
+    List<User> userList(List<User> users);
 
 }
diff --git a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/noannotation/NoAnnotationDemoServiceImpl.java b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/noannotation/NoAnnotationDemoServiceImpl.java
index 77e63cef65..4160e51575 100644
--- a/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/noannotation/NoAnnotationDemoServiceImpl.java
+++ b/dubbo-rpc/dubbo-rpc-rest/src/test/java/org/apache/dubbo/rpc/protocol/rest/noannotation/NoAnnotationDemoServiceImpl.java
@@ -19,6 +19,8 @@ package org.apache.dubbo.rpc.protocol.rest.noannotation;
 
 import org.apache.dubbo.rpc.protocol.rest.User;
 
+import java.util.List;
+
 
 public class NoAnnotationDemoServiceImpl implements NoAnnotationDemoService {
 
@@ -39,8 +41,13 @@ public class NoAnnotationDemoServiceImpl implements NoAnnotationDemoService {
     }
 
     @Override
-    public User noBodyArg(User user) {
+    public User user(User user) {
         user.setName("invoked");
         return user;
     }
+
+    @Override
+    public List<User> userList(List<User> users) {
+        return users;
+    }
 }