liubao68 closed pull request #815:  [SCB-708] Aggregate simple query params 
into object param in spring mvc style
URL: https://github.com/apache/incubator-servicecomb-java-chassis/pull/815
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git 
a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ProducerSchemaFactory.java
 
b/core/src/main/java/org/apache/servicecomb/core/definition/schema/ProducerSchemaFactory.java
index 1334332f7..a3b0a38cf 100644
--- 
a/core/src/main/java/org/apache/servicecomb/core/definition/schema/ProducerSchemaFactory.java
+++ 
b/core/src/main/java/org/apache/servicecomb/core/definition/schema/ProducerSchemaFactory.java
@@ -17,6 +17,8 @@
 
 package org.apache.servicecomb.core.definition.schema;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
@@ -41,6 +43,7 @@
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectWriter;
 
+import io.swagger.models.Operation;
 import io.swagger.models.Swagger;
 import io.swagger.util.Yaml;
 
@@ -79,7 +82,8 @@ public SchemaMeta getOrCreateProducerSchema(String 
microserviceName, String sche
 
     SchemaMeta schemaMeta = getOrCreateSchema(context);
 
-    SwaggerProducer producer = swaggerEnv.createProducer(producerInstance, 
schemaMeta.getSwaggerIntf());
+    SwaggerProducer producer = swaggerEnv.createProducer(producerInstance, 
schemaMeta.getSwaggerIntf(),
+        convertSwaggerOperationMap(schemaMeta));
     Executor reactiveExecutor = 
BeanUtils.getBean(ExecutorManager.EXECUTOR_REACTIVE);
     for (OperationMeta operationMeta : schemaMeta.getOperations()) {
       SwaggerProducerOperation producerOperation = 
producer.findOperation(operationMeta.getOperationId());
@@ -93,6 +97,13 @@ public SchemaMeta getOrCreateProducerSchema(String 
microserviceName, String sche
     return schemaMeta;
   }
 
+  private Map<String, Operation> convertSwaggerOperationMap(SchemaMeta 
schemaMeta) {
+    Map<String, Operation> operationMap = new 
LinkedHashMap<>(schemaMeta.getOperations().size());
+    schemaMeta.getOperations().forEach(
+        operationMeta -> operationMap.put(operationMeta.getOperationId(), 
operationMeta.getSwaggerOperation()));
+    return operationMap;
+  }
+
   protected SchemaMeta createSchema(ProducerSchemaContext context) {
     // 尝试从规划的目录加载契约
     Swagger swagger = loadSwagger(context);
diff --git 
a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParam.java
 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParam.java
new file mode 100644
index 000000000..3ec6f17c5
--- /dev/null
+++ 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParam.java
@@ -0,0 +1,63 @@
+/*
+ * 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.demo.compute;
+
+public class GenericParam<T> {
+  private String str;
+
+  private long num;
+
+  private T data;
+
+  public String getStr() {
+    return str;
+  }
+
+  public GenericParam<T> setStr(String str) {
+    this.str = str;
+    return this;
+  }
+
+  public long getNum() {
+    return num;
+  }
+
+  public GenericParam<T> setNum(long num) {
+    this.num = num;
+    return this;
+  }
+
+  public T getData() {
+    return data;
+  }
+
+  public GenericParam<T> setData(T data) {
+    this.data = data;
+    return this;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder("GenericParam{");
+    sb.append("str='").append(str).append('\'');
+    sb.append(", num=").append(num);
+    sb.append(", data=").append(data);
+    sb.append('}');
+    return sb.toString();
+  }
+}
diff --git 
a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamExtended.java
 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamExtended.java
new file mode 100644
index 000000000..1f97197f4
--- /dev/null
+++ 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamExtended.java
@@ -0,0 +1,52 @@
+/*
+ * 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.demo.compute;
+
+public class GenericParamExtended<T> extends GenericParam<T> {
+  private String strExtended;
+
+  private int intExtended;
+
+  public String getStrExtended() {
+    return strExtended;
+  }
+
+  public GenericParamExtended<T> setStrExtended(String strExtended) {
+    this.strExtended = strExtended;
+    return this;
+  }
+
+  public int getIntExtended() {
+    return intExtended;
+  }
+
+  public GenericParamExtended<T> setIntExtended(int intExtended) {
+    this.intExtended = intExtended;
+    return this;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder("GenericParamExtended{");
+    sb.append("strExtended='").append(strExtended).append('\'');
+    sb.append(", intExtended=").append(intExtended);
+    sb.append(", super=").append(super.toString());
+    sb.append('}');
+    return sb.toString();
+  }
+}
diff --git 
a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamWithJsonIgnore.java
 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamWithJsonIgnore.java
new file mode 100644
index 000000000..0a295a881
--- /dev/null
+++ 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/compute/GenericParamWithJsonIgnore.java
@@ -0,0 +1,66 @@
+/*
+ * 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.demo.compute;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+public class GenericParamWithJsonIgnore<T> {
+  private String str;
+
+  private long num;
+
+  @JsonIgnore
+  private T data;
+
+  public String getStr() {
+    return str;
+  }
+
+  public GenericParamWithJsonIgnore<T> setStr(String str) {
+    this.str = str;
+    return this;
+  }
+
+  public long getNum() {
+    return num;
+  }
+
+  public GenericParamWithJsonIgnore<T> setNum(long num) {
+    this.num = num;
+    return this;
+  }
+
+  public T getData() {
+    return data;
+  }
+
+  public GenericParamWithJsonIgnore<T> setData(T data) {
+    this.data = data;
+    return this;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder("GenericParamWithJsonIgnore{");
+    sb.append("str='").append(str).append('\'');
+    sb.append(", num=").append(num);
+    sb.append(", data=").append(data);
+    sb.append('}');
+    return sb.toString();
+  }
+}
diff --git 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java
 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java
index 04f2ec6bc..2525f8757 100644
--- 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java
+++ 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstRestTemplateSpringmvc.java
@@ -88,6 +88,7 @@ protected void testOnlyRest(RestTemplate template, String 
cseUrlPrefix) {
     testResponse.runRest();
     testObject.runRest();
     testGeneric.runRest();
+    testRestTemplate.runRest();
 
     super.testOnlyRest(template, cseUrlPrefix);
   }
diff --git 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSpringmvcIntf.java
 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSpringmvcIntf.java
index 6fb55e223..cb1824ba2 100644
--- 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSpringmvcIntf.java
+++ 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/CodeFirstSpringmvcIntf.java
@@ -24,6 +24,8 @@
 
 import org.apache.servicecomb.demo.EmptyObject;
 import org.apache.servicecomb.demo.Generic;
+import org.apache.servicecomb.demo.compute.GenericParam;
+import org.apache.servicecomb.demo.compute.Person;
 import org.apache.servicecomb.demo.server.User;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.springframework.http.HttpStatus;
@@ -59,4 +61,11 @@
   void testvoidInRPC();
 
   Void testVoidInRPC();
+
+  String checkQueryObject(String name, String otherName, Person requestBody);
+
+  String checkQueryGenericObject(GenericParam<Person> requestBody, String str, 
long num);
+
+  String checkQueryGenericString(String str, GenericParam<Person> requestBody, 
long num, String data,
+      String strExtended, int intExtended);
 }
diff --git 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java
 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java
index e7f1d4c30..e417e200c 100644
--- 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java
+++ 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestResponse.java
@@ -19,6 +19,8 @@
 import java.util.Date;
 
 import org.apache.servicecomb.demo.TestMgr;
+import org.apache.servicecomb.demo.compute.GenericParam;
+import org.apache.servicecomb.demo.compute.Person;
 import org.apache.servicecomb.provider.pojo.Invoker;
 import org.apache.servicecomb.serviceregistry.RegistryUtils;
 import org.apache.servicecomb.swagger.invocation.Response;
@@ -32,6 +34,8 @@ public TestResponse() {
   }
 
   public void runRest() {
+    checkQueryGenericObject();
+    checkQueryGenericString();
   }
 
   public void runHighway() {
@@ -42,6 +46,7 @@ public void runAllTransport() {
     testCseResponse();
     testvoidResponse();
     testVoidResponse();
+    checkQueryObject();
   }
 
   private void testCseResponse() {
@@ -72,4 +77,29 @@ private void testvoidResponse() {
   private void testVoidResponse() {
     intf.testVoidInRPC();
   }
+
+  private void checkQueryObject() {
+    String result = intf.checkQueryObject("name1", "otherName2", new 
Person("bodyName"));
+    
TestMgr.check("invocationContext_is_null=false,person=name1,otherName=otherName2,name=name1,requestBody=bodyName",
+        result);
+  }
+
+  private void checkQueryGenericObject() {
+    final GenericParam<Person> requestBody = new GenericParam<>();
+    requestBody.setNum(1).setStr("str1").setData(new Person("bodyPerson"));
+    String result = intf.checkQueryGenericObject(requestBody, "str2", 2);
+    TestMgr.check(
+        "str=str2,generic=GenericParamWithJsonIgnore{str='str2', num=2, 
data=null},requestBody=GenericParam{str='str1', num=1, data=bodyPerson}",
+        result);
+  }
+
+  private void checkQueryGenericString() {
+    final GenericParam<Person> requestBody = new GenericParam<>();
+    requestBody.setNum(1).setStr("str1").setData(new Person("bodyPerson"));
+    String result = intf.checkQueryGenericString("str2", requestBody, 2, 
"dataTest", "strInSubclass", 33);
+    TestMgr.check(
+        "str=str2,generic=GenericParamExtended{strExtended='strInSubclass', 
intExtended=33, super="
+            + "GenericParam{str='str2', num=2, 
data=dataTest}},requestBody=GenericParam{str='str1', num=1, data=bodyPerson}",
+        result);
+  }
 }
diff --git 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestRestTemplate.java
 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestRestTemplate.java
index 5b8c9ebb5..06c302a56 100644
--- 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestRestTemplate.java
+++ 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/TestRestTemplate.java
@@ -17,7 +17,12 @@
 
 package org.apache.servicecomb.demo.springmvc.client;
 
+import org.apache.servicecomb.demo.TestMgr;
+import org.apache.servicecomb.demo.compute.GenericParam;
+import org.apache.servicecomb.demo.compute.Person;
 import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
 import org.springframework.http.ResponseEntity;
 import org.springframework.util.Assert;
 import org.springframework.web.client.RestTemplate;
@@ -29,6 +34,12 @@ public void runAllTest() {
     testvoidResponse();
     testVoidResponse();
     checkAllVoidTestResult();
+    checkQueryObject();
+  }
+
+  public void runRest() {
+    checkQueryGenericObject();
+    checkQueryGenericString();
   }
 
   private void testvoidResponse() {
@@ -48,4 +59,37 @@ private void checkAllVoidTestResult() {
         .getForEntity("cse://springmvc/codeFirstSpringmvc/checkVoidResult", 
boolean.class);
     Assert.isTrue(resultEntity.getBody(), "not all void test is passed");
   }
+
+  private void checkQueryObject() {
+    final ResponseEntity<String> responseEntity = restTemplate
+        
.postForEntity("cse://springmvc/codeFirstSpringmvc/checkQueryObject?name={1}&otherName={2}",
+            new Person("bodyName"), String.class, "name1", "otherName2");
+    
TestMgr.check("invocationContext_is_null=false,person=name1,otherName=otherName2,name=name1,requestBody=bodyName",
+        responseEntity.getBody());
+  }
+
+  private void checkQueryGenericObject() {
+    final GenericParam<Person> requestBody = new GenericParam<>();
+    requestBody.setNum(1).setStr("str1").setData(new Person("bodyPerson"));
+    final HttpEntity<GenericParam<Person>> requestEntity = new 
HttpEntity<>(requestBody);
+    final ResponseEntity<String> responseEntity = restTemplate
+        
.exchange("cse://springmvc/codeFirstSpringmvc/checkQueryGenericObject?str={1}&num={2}",
+            HttpMethod.PUT, requestEntity, String.class, "str2", 2);
+    TestMgr.check(
+        "str=str2,generic=GenericParamWithJsonIgnore{str='str2', num=2, 
data=null},requestBody=GenericParam{str='str1', num=1, data=bodyPerson}",
+        responseEntity.getBody());
+  }
+
+  private void checkQueryGenericString() {
+    final GenericParam<Person> requestBody = new GenericParam<>();
+    requestBody.setNum(1).setStr("str1").setData(new Person("bodyPerson"));
+    final ResponseEntity<String> responseEntity = restTemplate.exchange(
+        
"cse://springmvc/codeFirstSpringmvc/checkQueryGenericString?str={1}&num={2}&data={3}&strExtended={4}&intExtended={5}",
+        HttpMethod.PUT, new HttpEntity<>(requestBody), String.class, "str2", 
2, "dataTest",
+        "strInSubclass", 33);
+    TestMgr.check(
+        "str=str2,generic=GenericParamExtended{strExtended='strInSubclass', 
intExtended=33, super="
+            + "GenericParam{str='str2', num=2, 
data=dataTest}},requestBody=GenericParam{str='str1', num=1, data=bodyPerson}",
+        responseEntity.getBody());
+  }
 }
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 883f0592c..6b97de5aa 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
@@ -34,6 +34,9 @@
 import org.apache.servicecomb.core.Const;
 import org.apache.servicecomb.demo.EmptyObject;
 import org.apache.servicecomb.demo.Generic;
+import org.apache.servicecomb.demo.compute.GenericParam;
+import org.apache.servicecomb.demo.compute.GenericParamExtended;
+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;
@@ -141,10 +144,10 @@ public String fileUpload(@RequestPart(name = "file1") 
MultipartFile file1,
   public Response cseResponse(InvocationContext c1) {
     Response response = Response.createSuccess(Status.ACCEPTED, new User());
     Headers headers = response.getHeaders();
-    headers.addHeader("h1", "h1v " + 
c1.getContext().get(Const.SRC_MICROSERVICE).toString());
+    headers.addHeader("h1", "h1v " + 
c1.getContext().get(Const.SRC_MICROSERVICE));
 
     InvocationContext c2 = ContextUtils.getInvocationContext();
-    headers.addHeader("h2", "h2v " + 
c2.getContext().get(Const.SRC_MICROSERVICE).toString());
+    headers.addHeader("h2", "h2v " + 
c2.getContext().get(Const.SRC_MICROSERVICE));
 
     return response;
   }
@@ -464,4 +467,37 @@ public boolean checkVoidResult() {
     return testvoidInRPCSuccess && testVoidInRPCSuccess && 
testvoidInRestTemplateSuccess
         && testVoidInRestTemplateSuccess;
   }
+
+  /**
+   * Simple query object test, users can use it mixed with InvocationContext 
and plain query param, RequestBody
+   */
+  @PostMapping(path = "/checkQueryObject")
+  public String checkQueryObject(Person person, @RequestParam(name = 
"otherName") String otherName,
+      InvocationContext invocationContext, @RequestParam(name = "name") String 
name, @RequestBody Person requestBody) {
+    LOGGER.info("checkQueryObject() is called!");
+    return "invocationContext_is_null=" + (null == invocationContext) + 
",person="
+        + person + ",otherName=" + otherName + ",name=" + name + 
",requestBody=" + requestBody;
+  }
+
+  /**
+   * For the nesting object params, including the generic params whose generic 
field is an object,
+   * the inner object field is not supported.
+   */
+  @PutMapping(path = "/checkQueryGenericObject")
+  public String checkQueryGenericObject(@RequestBody GenericParam<Person> 
requestBody,
+      GenericParamWithJsonIgnore<Person> generic, String str) {
+    LOGGER.info("checkQueryGenericObject() is called!");
+    return "str=" + str + ",generic=" + generic + ",requestBody=" + 
requestBody;
+  }
+
+  /**
+   * If the generic field is simple type, it's supported to be deserialized.
+   * The same for those simple type field inherited from the parent class.
+   */
+  @PutMapping(path = "/checkQueryGenericString")
+  public String checkQueryGenericString(String str, @RequestBody 
GenericParam<Person> requestBody,
+      GenericParamExtended<String> generic) {
+    LOGGER.info("checkQueryGenericObject() is called!");
+    return "str=" + str + ",generic=" + generic + ",requestBody=" + 
requestBody;
+  }
 }
diff --git 
a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGenerator.java
 
b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGenerator.java
index 40edc6795..ba0b90008 100644
--- 
a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGenerator.java
+++ 
b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/OperationGenerator.java
@@ -32,6 +32,8 @@
 import org.apache.servicecomb.swagger.SwaggerUtils;
 import org.apache.servicecomb.swagger.extend.parameter.ContextParameter;
 import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.util.StringUtils;
 
 import io.swagger.models.HttpMethod;
@@ -45,6 +47,8 @@
 import io.swagger.util.ReflectionUtils;
 
 public class OperationGenerator {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(OperationGenerator.class);
+
   protected SwaggerGenerator swaggerGenerator;
 
   protected Swagger swagger;
@@ -139,7 +143,27 @@ public void addMethodAnnotationParameter(Parameter 
parameter) {
     methodAnnotationParameters.add(parameter);
   }
 
+  /**
+   * Add a parameter into {@linkplain #providerParameters},
+   * duplicated name params will be ignored(excepting for {@linkplain 
ContextParameter}s)
+   */
   public void addProviderParameter(Parameter parameter) {
+    if (ContextParameter.class.isInstance(parameter)) {
+      // ContextParameter has no name and is not written in schema,
+      // so just add it without checking
+      providerParameters.add(parameter);
+      return;
+    }
+    // check duplicated param according to param name
+    for (Parameter providerParameter : providerParameters) {
+      if (parameter.getName().equals(providerParameter.getName())) {
+        LOGGER.warn(
+            "Param name [{}] is duplicated which may cause ambiguous 
deserialization result. Please check you schema definition",
+            parameter.getName());
+        return;
+      }
+    }
+
     providerParameters.add(parameter);
   }
 
@@ -294,7 +318,6 @@ protected void processByParameterAnnotation(Annotation[] 
paramAnnotations, int p
     if (parameter instanceof AbstractSerializableParameter && defaultValue != 
null) {
       ((AbstractSerializableParameter<?>) 
parameter).setDefaultValue(defaultValue);
     }
-
   }
 
   protected void processByParameterType(Type parameterType, int paramIdx) {
diff --git 
a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/ParamUtils.java
 
b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/ParamUtils.java
index 94323f86c..db6d20130 100644
--- 
a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/ParamUtils.java
+++ 
b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/utils/ParamUtils.java
@@ -27,8 +27,6 @@
 import org.springframework.core.DefaultParameterNameDiscoverer;
 import org.springframework.core.MethodParameter;
 
-import com.fasterxml.jackson.databind.ser.std.MapProperty;
-
 import io.swagger.converter.ModelConverters;
 import io.swagger.models.Model;
 import io.swagger.models.Swagger;
@@ -36,6 +34,7 @@
 import io.swagger.models.parameters.BodyParameter;
 import io.swagger.models.parameters.Parameter;
 import io.swagger.models.properties.ArrayProperty;
+import io.swagger.models.properties.MapProperty;
 import io.swagger.models.properties.ObjectProperty;
 import io.swagger.models.properties.Property;
 import io.swagger.models.properties.PropertyBuilder;
diff --git 
a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestClassUtils.java
 
b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestClassUtils.java
index 32d825351..d1b2d3808 100644
--- 
a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestClassUtils.java
+++ 
b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestClassUtils.java
@@ -84,10 +84,10 @@ public void getOrCreateBodyClass() throws 
NoSuchFieldException {
 
   @Test
   public void testHasAnnotation() {
-    Assert.assertEquals(true, ClassUtils.hasAnnotation(TestClassUtils.class, 
SwaggerDefinition.class));
-    Assert.assertEquals(true, ClassUtils.hasAnnotation(TestClassUtils.class, 
Test.class));
+    Assert.assertTrue(ClassUtils.hasAnnotation(TestClassUtils.class, 
SwaggerDefinition.class));
+    Assert.assertTrue(ClassUtils.hasAnnotation(TestClassUtils.class, 
Test.class));
 
-    Assert.assertEquals(false, ClassUtils.hasAnnotation(TestClassUtils.class, 
Path.class));
+    Assert.assertFalse(ClassUtils.hasAnnotation(TestClassUtils.class, 
Path.class));
   }
 
   @Test
diff --git 
a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestOperationGenerator.java
 
b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestOperationGenerator.java
index 1ecb0e605..1b520bc9d 100644
--- 
a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestOperationGenerator.java
+++ 
b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestOperationGenerator.java
@@ -26,11 +26,16 @@
 import java.util.List;
 
 import org.apache.servicecomb.foundation.test.scaffolding.spring.SpringUtils;
+import org.apache.servicecomb.swagger.extend.parameter.HttpRequestParameter;
 import 
org.apache.servicecomb.swagger.generator.pojo.PojoSwaggerGeneratorContext;
+import org.junit.Assert;
 import org.junit.Test;
 import org.springframework.util.StringValueResolver;
 
 import io.swagger.annotations.ApiOperation;
+import io.swagger.models.parameters.BodyParameter;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.parameters.QueryParameter;
 
 public class TestOperationGenerator {
   @Test
@@ -88,6 +93,34 @@ public void testConvertTagsOnMethodWithNoAnnotation() throws 
NoSuchMethodExcepti
     assertThat(tagList, contains("default0", "default1"));
   }
 
+  @Test
+  public void addProviderParameter() throws NoSuchMethodException {
+    Method function = TestClass.class.getMethod("functionWithNoAnnotation");
+    SwaggerGenerator swaggerGenerator = new SwaggerGenerator(new 
PojoSwaggerGeneratorContext(), TestClass.class);
+    OperationGenerator operationGenerator = new 
OperationGenerator(swaggerGenerator, function);
+
+    Parameter parameter = new BodyParameter();
+    parameter.setName("param0");
+    operationGenerator.addProviderParameter(parameter);
+    Assert.assertEquals(1, operationGenerator.getProviderParameters().size());
+    Assert.assertSame(parameter, 
operationGenerator.getProviderParameters().get(0));
+
+    parameter = new HttpRequestParameter();
+    operationGenerator.addProviderParameter(parameter);
+    Assert.assertSame(parameter, 
operationGenerator.getProviderParameters().get(1));
+
+    parameter = new QueryParameter();
+    parameter.setName("param1");
+    operationGenerator.addProviderParameter(parameter);
+    Assert.assertSame(parameter, 
operationGenerator.getProviderParameters().get(2));
+
+    parameter = new QueryParameter();
+    parameter.setName("param0");
+    operationGenerator.addProviderParameter(parameter);
+    Assert.assertEquals(3, operationGenerator.getProviderParameters().size());
+    Assert.assertNotSame(parameter, 
operationGenerator.getProviderParameters().get(2));
+  }
+
   private static class TestClass {
     @ApiOperation(value = "value1", tags = {"tag1", "tag2"})
     public void function() {
diff --git 
a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestParamUtils.java
 
b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestParamUtils.java
index ce609cf1f..1343f5f7b 100644
--- 
a/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestParamUtils.java
+++ 
b/swagger/swagger-generator/generator-core/src/test/java/org/apache/servicecomb/swagger/generator/core/TestParamUtils.java
@@ -23,11 +23,18 @@
 import java.util.Map;
 
 import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils;
+import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils;
 import org.junit.Assert;
 import org.junit.Test;
 import org.mockito.Mockito;
 
 import io.swagger.models.parameters.Parameter;
+import io.swagger.models.properties.ArrayProperty;
+import io.swagger.models.properties.MapProperty;
+import io.swagger.models.properties.ObjectProperty;
+import io.swagger.models.properties.Property;
+import io.swagger.models.properties.RefProperty;
+import io.swagger.models.properties.StringProperty;
 
 public class TestParamUtils {
   @Test
@@ -42,4 +49,21 @@ public void testGetRawJsonType() {
     extensions.put(SwaggerConst.EXT_RAW_JSON_TYPE, "test");
     Assert.assertFalse(ClassUtils.isRawJsonType(param));
   }
+
+  @Test
+  public void isComplexProperty() {
+    Property property = new RefProperty("ref");
+    Assert.assertTrue(ParamUtils.isComplexProperty(property));
+    property = new ObjectProperty();
+    Assert.assertTrue(ParamUtils.isComplexProperty(property));
+    property = new MapProperty();
+    Assert.assertTrue(ParamUtils.isComplexProperty(property));
+    property = new ArrayProperty(new ObjectProperty());
+    Assert.assertTrue(ParamUtils.isComplexProperty(property));
+
+    property = new ArrayProperty(new StringProperty());
+    Assert.assertFalse(ParamUtils.isComplexProperty(property));
+    property = new StringProperty();
+    Assert.assertFalse(ParamUtils.isComplexProperty(property));
+  }
 }
diff --git 
a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessor.java
 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessor.java
new file mode 100644
index 000000000..d1b44a01f
--- /dev/null
+++ 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessor.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter;
+
+import java.lang.reflect.Type;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.servicecomb.swagger.generator.core.DefaultParameterProcessor;
+import org.apache.servicecomb.swagger.generator.core.OperationGenerator;
+import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.swagger.converter.ModelConverters;
+import io.swagger.models.Model;
+import io.swagger.models.parameters.AbstractSerializableParameter;
+import io.swagger.models.parameters.QueryParameter;
+import io.swagger.models.properties.Property;
+import io.swagger.models.properties.RefProperty;
+
+/**
+ * Flatten a object parameter into a set of flatten simple parameters.
+ * <p/>
+ * <em>Nesting object params and generic Object params are NOT supported.</em>
+ * We support query object just for aggregating query params instead of 
transporting objects in query param.
+ * So we don't support a generic param whose generic type is complex, but a 
simple generic type param can be supported.
+ */
+public class SpringmvcDefaultObjectParameterProcessor implements 
DefaultParameterProcessor {
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(SpringmvcDefaultObjectParameterProcessor.class);
+
+  @Override
+  public void process(OperationGenerator operationGenerator, int paramIndex) {
+    Model paramModel = getParamModel(operationGenerator, paramIndex);
+
+    if (null == paramModel) {
+      throw new Error(String.format("cannot find param, provider method is 
[%s], paramIndex = [%d]. "
+              + "Please check your parameter definition.",
+          operationGenerator.getProviderMethod().getName(), paramIndex));
+    }
+
+    LinkedHashMap<String, AbstractSerializableParameter<?>> resultParamMap = 
getFlattenParams(paramModel);
+
+    addProviderParams(operationGenerator, resultParamMap);
+  }
+
+  private void addProviderParams(OperationGenerator operationGenerator,
+      LinkedHashMap<String, AbstractSerializableParameter<?>> resultParamMap) {
+    resultParamMap.forEach((paramName, param) -> 
operationGenerator.addProviderParameter(param));
+  }
+
+  private Model getParamModel(OperationGenerator operationGenerator, int 
paramIndex) {
+    Type paramType = 
ParamUtils.getGenericParameterType(operationGenerator.getProviderMethod(), 
paramIndex);
+    Property property = 
ModelConverters.getInstance().readAsProperty(paramType);
+    // ensure type
+    if (!RefProperty.class.isInstance(property)) {
+      LOGGER.error("Unsupported property type: [{}], paramIndex is [{}]", 
property.getClass().getName(), paramIndex);
+      return null;
+    }
+
+    Map<String, Model> models = 
ModelConverters.getInstance().readAll(paramType);
+
+    // find param root
+    RefProperty refProperty = (RefProperty) property;
+    String refTypeName = refProperty.getSimpleRef();
+    Model paramRoot = null;
+    for (Entry<String, Model> entry : models.entrySet()) {
+      if (refTypeName.equals(entry.getKey())) {
+        paramRoot = entry.getValue();
+        break;
+      }
+    }
+    return paramRoot;
+  }
+
+  private LinkedHashMap<String, AbstractSerializableParameter<?>> 
getFlattenParams(Model paramModel) {
+    LinkedHashMap<String, AbstractSerializableParameter<?>> flattenParamMap = 
new LinkedHashMap<>();
+    // traversal the properties of current paramModel
+    // create simple parameters, nesting object param is ignored
+    for (Entry<String, Property> propertyEntry : 
paramModel.getProperties().entrySet()) {
+      if (ParamUtils.isComplexProperty(propertyEntry.getValue())) {
+        throw new Error(
+            "A nesting complex field is found in the query object and this is 
not supported, field name  = ["
+                + propertyEntry.getKey() + "]. Please remove this field or tag 
@JsonIgnore on it.");
+      }
+      AbstractSerializableParameter<?> newParameter = 
createSimpleParam(propertyEntry);
+      flattenParamMap.put(propertyEntry.getKey(), newParameter);
+    }
+
+    return flattenParamMap;
+  }
+
+  private AbstractSerializableParameter<?> createSimpleParam(Entry<String, 
Property> propertyEntry) {
+    AbstractSerializableParameter<?> newParameter = new QueryParameter();
+    newParameter.setName(propertyEntry.getKey());
+    newParameter.setProperty(propertyEntry.getValue());
+    return newParameter;
+  }
+}
diff --git 
a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessor.java
 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessor.java
index a87ef87f6..d9b5a5d73 100644
--- 
a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessor.java
+++ 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessor.java
@@ -17,24 +17,42 @@
 
 package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter;
 
+import java.lang.reflect.Type;
+
 import org.apache.servicecomb.swagger.generator.core.DefaultParameterProcessor;
 import org.apache.servicecomb.swagger.generator.core.OperationGenerator;
 import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils;
 
-import io.swagger.models.parameters.QueryParameter;
+import io.swagger.converter.ModelConverters;
+import io.swagger.models.properties.Property;
+import io.swagger.models.properties.RefProperty;
 
 public class SpringmvcDefaultParameterProcessor implements 
DefaultParameterProcessor {
+  private SpringmvcDefaultSimpleParameterProcessor simpleParameterProcessor = 
new SpringmvcDefaultSimpleParameterProcessor();
+
+  private SpringmvcDefaultObjectParameterProcessor objectParameterProcessor = 
new SpringmvcDefaultObjectParameterProcessor();
 
   @Override
   public void process(OperationGenerator operationGenerator, int paramIdx) {
-    String paramName = 
ParamUtils.getParameterName(operationGenerator.getProviderMethod(), paramIdx);
+    Type paramType = 
ParamUtils.getGenericParameterType(operationGenerator.getProviderMethod(), 
paramIdx);
+    Property property = 
ModelConverters.getInstance().readAsProperty(paramType);
+
+    if (RefProperty.class.isInstance(property)) {
+      objectParameterProcessor.process(operationGenerator, paramIdx);
+      return;
+    }
+    if (!ParamUtils.isComplexProperty(property)) {
+      simpleParameterProcessor.process(operationGenerator, paramIdx);
+      return;
+    }
 
-    QueryParameter queryParameter = new QueryParameter();
-    queryParameter.setName(paramName);
-    ParamUtils.setParameterType(operationGenerator.getSwagger(),
-        operationGenerator.getProviderMethod(),
+    // unsupported param type
+    String msg = String.format("cannot process parameter [%s], method=%s:%s, 
paramIdx=%d, type=%s",
+        ParamUtils.getParameterName(operationGenerator.getProviderMethod(), 
paramIdx),
+        operationGenerator.getProviderMethod().getDeclaringClass().getName(),
+        operationGenerator.getProviderMethod().getName(),
         paramIdx,
-        queryParameter);
-    operationGenerator.addProviderParameter(queryParameter);
+        paramType.getTypeName());
+    throw new Error(msg);
   }
 }
diff --git 
a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessor.java
 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessor.java
new file mode 100644
index 000000000..3d9f5a115
--- /dev/null
+++ 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessor.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter;
+
+import org.apache.servicecomb.swagger.generator.core.DefaultParameterProcessor;
+import org.apache.servicecomb.swagger.generator.core.OperationGenerator;
+import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils;
+
+import io.swagger.models.parameters.QueryParameter;
+
+public class SpringmvcDefaultSimpleParameterProcessor implements 
DefaultParameterProcessor {
+
+  @Override
+  public void process(OperationGenerator operationGenerator, int paramIdx) {
+    String paramName = 
ParamUtils.getParameterName(operationGenerator.getProviderMethod(), paramIdx);
+
+    QueryParameter queryParameter = new QueryParameter();
+    queryParameter.setName(paramName);
+    ParamUtils.setParameterType(operationGenerator.getSwagger(),
+        operationGenerator.getProviderMethod(),
+        paramIdx,
+        queryParameter);
+    operationGenerator.addProviderParameter(queryParameter);
+  }
+}
diff --git 
a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessorTest.java
 
b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessorTest.java
new file mode 100644
index 000000000..7d948d750
--- /dev/null
+++ 
b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultObjectParameterProcessorTest.java
@@ -0,0 +1,385 @@
+/*
+ * 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.swagger.generator.springmvc.processor.parameter;
+
+import static org.junit.Assert.fail;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.servicecomb.swagger.generator.core.OperationGenerator;
+import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator;
+import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.parameters.QueryParameter;
+import mockit.Deencapsulation;
+
+public class SpringmvcDefaultObjectParameterProcessorTest {
+
+  @Test
+  public void processOnObjectParam() throws NoSuchMethodException {
+    final OperationGenerator operationGenerator = 
mockOperationGenerator("testObjectParam", "/test", TestParam.class);
+
+    new SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 
0);
+
+    final List<Parameter> providerParameters = 
operationGenerator.getProviderParameters();
+    Assert.assertEquals(2, providerParameters.size());
+    Parameter parameter = providerParameters.get(0);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("name", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    QueryParameter queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("string", queryParameter.getType());
+    parameter = providerParameters.get(1);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("age", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("integer", queryParameter.getType());
+    Assert.assertEquals("int32", queryParameter.getFormat());
+  }
+
+  @Test
+  public void processOnRecursiveObjectParam() throws NoSuchMethodException {
+    final OperationGenerator operationGenerator = 
mockOperationGenerator("testRecursiveParam", "/test",
+        RecursiveParamA.class);
+
+    new SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 
0);
+
+    final List<Parameter> providerParameters = 
operationGenerator.getProviderParameters();
+    Assert.assertEquals(1, providerParameters.size());
+    Parameter parameter = providerParameters.get(0);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("name", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    QueryParameter queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("string", queryParameter.getType());
+  }
+
+  @Test
+  public void processOnRecursiveObjectParamWithNoJsonIgnore() throws 
NoSuchMethodException {
+    final OperationGenerator operationGenerator = 
mockOperationGenerator("testRecursiveParamWithNoJsonIgnore", "/test",
+        RecursiveParamB.class);
+
+    try {
+      new 
SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 0);
+      fail("an error is expected");
+    } catch (Throwable e) {
+      Assert.assertEquals(Error.class, e.getClass());
+      Assert.assertEquals(
+          "A nesting complex field is found in the query object and this is 
not supported,"
+              + " field name  = [recursiveParamA]. Please remove this field or 
tag @JsonIgnore on it.",
+          e.getMessage());
+    }
+  }
+
+  @Test
+  public void processOnGenericObjectParam() throws NoSuchMethodException {
+    final OperationGenerator operationGenerator = 
mockOperationGenerator("testGenericObjectParam", "/test",
+        GenericParam.class);
+    try {
+      new 
SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 0);
+      fail("an error is expected");
+    } catch (Throwable e) {
+      Assert.assertEquals(Error.class, e.getClass());
+      Assert.assertEquals(
+          "A nesting complex field is found in the query object and this is 
not supported,"
+              + " field name  = [data]. Please remove this field or tag 
@JsonIgnore on it.",
+          e.getMessage());
+    }
+  }
+
+  @Test
+  public void processOnGenericObjectParamWithJsonIgnore() throws 
NoSuchMethodException {
+    final OperationGenerator operationGenerator = 
mockOperationGenerator("testGenericObjectParamWithJsonIgnore",
+        "/test",
+        GenericParamWithJsonIgnore.class);
+
+    new SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 
0);
+
+    final List<Parameter> providerParameters = 
operationGenerator.getProviderParameters();
+    Assert.assertEquals(2, providerParameters.size());
+    Parameter parameter = providerParameters.get(0);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("num", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    QueryParameter queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("integer", queryParameter.getType());
+    Assert.assertEquals("int32", queryParameter.getFormat());
+    parameter = providerParameters.get(1);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("str", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("string", queryParameter.getType());
+  }
+
+  @Test
+  public void processOnGenericSimpleParam() throws NoSuchMethodException {
+    final OperationGenerator operationGenerator = 
mockOperationGenerator("testGenericSimpleParam", "/test",
+        GenericParam.class);
+
+    new SpringmvcDefaultObjectParameterProcessor().process(operationGenerator, 
0);
+
+    final List<Parameter> providerParameters = 
operationGenerator.getProviderParameters();
+    Assert.assertEquals(3, providerParameters.size());
+    Parameter parameter = providerParameters.get(0);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("num", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    QueryParameter queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("integer", queryParameter.getType());
+    Assert.assertEquals("int32", queryParameter.getFormat());
+    parameter = providerParameters.get(1);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("str", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("string", queryParameter.getType());
+    parameter = providerParameters.get(2);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("data", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("string", queryParameter.getType());
+  }
+
+  private OperationGenerator mockOperationGenerator(String providerParamName, 
String path, Class<?>... classes)
+      throws NoSuchMethodException {
+    final SwaggerGenerator swaggerGenerator = new 
SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class),
+        TestProvider.class);
+    final Method providerMethod = 
TestProvider.class.getDeclaredMethod(providerParamName, classes);
+    final OperationGenerator operationGenerator = new 
OperationGenerator(swaggerGenerator, providerMethod);
+    Deencapsulation.setField(operationGenerator, "path", path);
+    return operationGenerator;
+  }
+
+  static class TestProvider {
+    public String testObjectParam(TestParam objParam) {
+      return objParam.toString();
+    }
+
+    public String testRecursiveParam(RecursiveParamA recursiveParamA) {
+      return null;
+    }
+
+    public String testRecursiveParamWithNoJsonIgnore(RecursiveParamB 
recursiveParamB) {
+      return null;
+    }
+
+    public String testGenericObjectParam(GenericParam<TestParam> genericParam) 
{
+      return genericParam.toString();
+    }
+
+    public String 
testGenericObjectParamWithJsonIgnore(GenericParamWithJsonIgnore<TestParam> 
genericParam) {
+      return genericParam.toString();
+    }
+
+    public String testGenericSimpleParam(GenericParam<String> genericParam) {
+      return genericParam.toString();
+    }
+  }
+
+  static class TestParam {
+    private String name;
+
+    private int age;
+
+    public String getName() {
+      return name;
+    }
+
+    public TestParam setName(String name) {
+      this.name = name;
+      return this;
+    }
+
+    public int getAge() {
+      return age;
+    }
+
+    public TestParam setAge(int age) {
+      this.age = age;
+      return this;
+    }
+  }
+
+  static class GenericParam<T> {
+    private int num;
+
+    private String str;
+
+    T data;
+
+    public int getNum() {
+      return num;
+    }
+
+    public void setNum(int num) {
+      this.num = num;
+    }
+
+    public String getStr() {
+      return str;
+    }
+
+    public void setStr(String str) {
+      this.str = str;
+    }
+
+    public T getData() {
+      return data;
+    }
+
+    public void setData(T data) {
+      this.data = data;
+    }
+  }
+
+  static class GenericParamWithJsonIgnore<T> {
+    private int num;
+
+    private String str;
+
+    @JsonIgnore
+    T data;
+
+    public int getNum() {
+      return num;
+    }
+
+    public void setNum(int num) {
+      this.num = num;
+    }
+
+    public String getStr() {
+      return str;
+    }
+
+    public void setStr(String str) {
+      this.str = str;
+    }
+
+    public T getData() {
+      return data;
+    }
+
+    public void setData(T data) {
+      this.data = data;
+    }
+  }
+
+  static class RecursiveParamA {
+    private String name;
+
+    @JsonIgnore
+    private RecursiveParamB recursiveParamB;
+
+    @JsonIgnore
+    private RecursiveParamC recursiveParamC;
+
+    public String getName() {
+      return name;
+    }
+
+    public void setName(String name) {
+      this.name = name;
+    }
+
+    public RecursiveParamB getRecursiveParamB() {
+      return recursiveParamB;
+    }
+
+    public void setRecursiveParamB(
+        RecursiveParamB recursiveParamB) {
+      this.recursiveParamB = recursiveParamB;
+    }
+
+    public RecursiveParamC getRecursiveParamC() {
+      return recursiveParamC;
+    }
+
+    public void setRecursiveParamC(
+        RecursiveParamC recursiveParamC) {
+      this.recursiveParamC = recursiveParamC;
+    }
+  }
+
+  static class RecursiveParamB {
+    private int age;
+
+    private RecursiveParamA recursiveParamA;
+
+    private RecursiveParamC recursiveParamC;
+
+    public int getAge() {
+      return age;
+    }
+
+    public void setAge(int age) {
+      this.age = age;
+    }
+
+    public RecursiveParamA getRecursiveParamA() {
+      return recursiveParamA;
+    }
+
+    public void setRecursiveParamA(
+        RecursiveParamA recursiveParamA) {
+      this.recursiveParamA = recursiveParamA;
+    }
+
+    public RecursiveParamC getRecursiveParamC() {
+      return recursiveParamC;
+    }
+
+    public void setRecursiveParamC(
+        RecursiveParamC recursiveParamC) {
+      this.recursiveParamC = recursiveParamC;
+    }
+  }
+
+  static class RecursiveParamC {
+    private String address;
+
+    private RecursiveParamB recursiveParamB;
+
+    public String getAddress() {
+      return address;
+    }
+
+    public void setAddress(String address) {
+      this.address = address;
+    }
+
+    public RecursiveParamB getRecursiveParamB() {
+      return recursiveParamB;
+    }
+
+    public void setRecursiveParamB(
+        RecursiveParamB recursiveParamB) {
+      this.recursiveParamB = recursiveParamB;
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessorTest.java
 
b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessorTest.java
new file mode 100644
index 000000000..4d194a1bc
--- /dev/null
+++ 
b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultParameterProcessorTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.swagger.generator.springmvc.processor.parameter;
+
+import static org.junit.Assert.fail;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.servicecomb.swagger.generator.core.OperationGenerator;
+import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator;
+import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.parameters.QueryParameter;
+import mockit.Deencapsulation;
+
+public class SpringmvcDefaultParameterProcessorTest {
+  @Test
+  public void processOnSimpleParam() throws NoSuchMethodException {
+    final SwaggerGenerator swaggerGenerator = new 
SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class),
+        TestProvider.class);
+    final Method providerMethod = 
TestProvider.class.getDeclaredMethod("testSimpleParam", String.class);
+    final OperationGenerator operationGenerator = new 
OperationGenerator(swaggerGenerator, providerMethod);
+
+    new SpringmvcDefaultParameterProcessor().process(operationGenerator, 0);
+
+    final List<Parameter> providerParameters = 
operationGenerator.getProviderParameters();
+    Assert.assertEquals(1, providerParameters.size());
+    Parameter parameter = providerParameters.get(0);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("strParam", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    QueryParameter queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("string", queryParameter.getType());
+  }
+
+  @Test
+  public void processOnObjectParam() throws NoSuchMethodException {
+    final OperationGenerator operationGenerator = 
mockOperationGenerator("testObjectParam", "/test", TestParam.class);
+
+    new SpringmvcDefaultParameterProcessor().process(operationGenerator, 0);
+
+    final List<Parameter> providerParameters = 
operationGenerator.getProviderParameters();
+    Assert.assertEquals(2, providerParameters.size());
+    Parameter parameter = providerParameters.get(0);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("name", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    QueryParameter queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("string", queryParameter.getType());
+    parameter = providerParameters.get(1);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("age", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("integer", queryParameter.getType());
+    Assert.assertEquals("int32", queryParameter.getFormat());
+  }
+
+  /**
+   * Map and List param is not supported
+   */
+  @Test
+  public void processOnUnsupportedParam() throws NoSuchMethodException {
+    final SwaggerGenerator swaggerGenerator = new 
SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class),
+        TestProvider.class);
+    final Method providerMethod = 
TestProvider.class.getDeclaredMethod("testUnsupportedParamType",
+        int.class, List.class, Map.class);
+    final OperationGenerator operationGenerator = new 
OperationGenerator(swaggerGenerator, providerMethod);
+
+    try {
+      new SpringmvcDefaultParameterProcessor().process(operationGenerator, 1);
+      fail("an error is expected!");
+    } catch (Error e) {
+      Assert.assertEquals(
+          "cannot process parameter [integerList], 
method=org.apache.servicecomb.swagger.generator.springmvc"
+              + 
".processor.parameter.SpringmvcDefaultParameterProcessorTest$TestProvider:testUnsupportedParamType,
 "
+              + "paramIdx=1, 
type=java.util.List<org.apache.servicecomb.swagger.generator.springmvc.processor.parameter"
+              + ".SpringmvcDefaultParameterProcessorTest$TestParam>",
+          e.getMessage());
+    }
+    try {
+      new SpringmvcDefaultParameterProcessor().process(operationGenerator, 2);
+      fail("an error is expected!");
+    } catch (Error e) {
+      Assert.assertEquals(
+          "cannot process parameter [stringMap], 
method=org.apache.servicecomb.swagger.generator.springmvc"
+              + 
".processor.parameter.SpringmvcDefaultParameterProcessorTest$TestProvider:testUnsupportedParamType,
 "
+              + "paramIdx=2, type=java.util.Map<java.lang.String, 
java.lang.String>",
+          e.getMessage());
+    }
+  }
+
+  @Test
+  public void processOnMultiObjectParamsWithSameFieldName() throws 
NoSuchMethodException {
+    final OperationGenerator operationGenerator = 
mockOperationGenerator("testMultiObjParamsWithSameFiledName", "/test",
+        String.class, TestParam.class, TestParam.class, int.class);
+
+    final SpringmvcDefaultParameterProcessor 
springmvcDefaultParameterProcessor = new SpringmvcDefaultParameterProcessor();
+    springmvcDefaultParameterProcessor.process(operationGenerator, 0);
+    springmvcDefaultParameterProcessor.process(operationGenerator, 1);
+    springmvcDefaultParameterProcessor.process(operationGenerator, 2);
+    springmvcDefaultParameterProcessor.process(operationGenerator, 3);
+
+    final List<Parameter> providerParameters = 
operationGenerator.getProviderParameters();
+    Assert.assertEquals(2, providerParameters.size());
+    Parameter parameter = providerParameters.get(0);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("name", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    QueryParameter queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("string", queryParameter.getType());
+    parameter = providerParameters.get(1);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("age", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("integer", queryParameter.getType());
+    Assert.assertEquals("int32", queryParameter.getFormat());
+  }
+
+  private OperationGenerator mockOperationGenerator(String providerParamName, 
String path, Class<?>... classes)
+      throws NoSuchMethodException {
+    final SwaggerGenerator swaggerGenerator = new 
SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class),
+        TestProvider.class);
+    final Method providerMethod = 
TestProvider.class.getDeclaredMethod(providerParamName, classes);
+    final OperationGenerator operationGenerator = new 
OperationGenerator(swaggerGenerator, providerMethod);
+    Deencapsulation.setField(operationGenerator, "path", path);
+    return operationGenerator;
+  }
+
+  static class TestProvider {
+    public String testSimpleParam(String strParam) {
+      return strParam;
+    }
+
+    public String testObjectParam(TestParam objParam) {
+      return objParam.toString();
+    }
+
+    public String testUnsupportedParamType(int i, List<TestParam> integerList, 
Map<String, String> stringMap) {
+      return null;
+    }
+
+    public String testMultiObjParamsWithSameFiledName(String name, TestParam 
objParam0, TestParam objParam1, int age) {
+      return objParam0 + "-" + objParam1;
+    }
+  }
+
+  static class TestParam {
+    private String name;
+
+    private int age;
+
+    public String getName() {
+      return name;
+    }
+
+    public TestParam setName(String name) {
+      this.name = name;
+      return this;
+    }
+
+    public int getAge() {
+      return age;
+    }
+
+    public TestParam setAge(int age) {
+      this.age = age;
+      return this;
+    }
+  }
+}
\ No newline at end of file
diff --git 
a/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessorTest.java
 
b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessorTest.java
new file mode 100644
index 000000000..dd2992883
--- /dev/null
+++ 
b/swagger/swagger-generator/generator-springmvc/src/test/java/org/apache/servicecomb/swagger/generator/springmvc/processor/parameter/SpringmvcDefaultSimpleParameterProcessorTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.swagger.generator.springmvc.processor.parameter;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.servicecomb.swagger.generator.core.OperationGenerator;
+import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator;
+import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext;
+import 
org.apache.servicecomb.swagger.generator.springmvc.processor.parameter.SpringmvcDefaultParameterProcessorTest.TestProvider;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.parameters.QueryParameter;
+
+public class SpringmvcDefaultSimpleParameterProcessorTest {
+  @Test
+  public void process() throws NoSuchMethodException {
+    final SwaggerGenerator swaggerGenerator = new 
SwaggerGenerator(Mockito.mock(SwaggerGeneratorContext.class),
+        TestProvider.class);
+    final Method providerMethod = 
TestProvider.class.getDeclaredMethod("testSimpleParam", String.class);
+    final OperationGenerator operationGenerator = new 
OperationGenerator(swaggerGenerator, providerMethod);
+
+    new SpringmvcDefaultSimpleParameterProcessor().process(operationGenerator, 
0);
+
+    final List<Parameter> providerParameters = 
operationGenerator.getProviderParameters();
+    Assert.assertEquals(1, providerParameters.size());
+    Parameter parameter = providerParameters.get(0);
+    Assert.assertEquals(QueryParameter.class, parameter.getClass());
+    Assert.assertEquals("strParam", parameter.getName());
+    Assert.assertEquals("query", parameter.getIn());
+    QueryParameter queryParameter = (QueryParameter) parameter;
+    Assert.assertEquals("string", queryParameter.getType());
+  }
+}
diff --git a/swagger/swagger-invocation/invocation-core/pom.xml 
b/swagger/swagger-invocation/invocation-core/pom.xml
index 6dfa293e5..816afbbb2 100644
--- a/swagger/swagger-invocation/invocation-core/pom.xml
+++ b/swagger/swagger-invocation/invocation-core/pom.xml
@@ -47,5 +47,9 @@
       <artifactId>log4j</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-web</artifactId>
+    </dependency>
   </dependencies>
 </project>
\ No newline at end of file
diff --git 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerEnvironment.java
 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerEnvironment.java
index 5224d70a3..e0ba98f39 100644
--- 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerEnvironment.java
+++ 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/SwaggerEnvironment.java
@@ -25,6 +25,8 @@
 import org.apache.commons.lang3.StringUtils;
 import org.apache.servicecomb.foundation.common.utils.BeanUtils;
 import org.apache.servicecomb.foundation.common.utils.ReflectUtils;
+import 
org.apache.servicecomb.swagger.generator.core.CompositeSwaggerGeneratorContext;
+import 
org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperConfig;
 import 
org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerArgumentsMapper;
 import 
org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerArgumentsMapperFactory;
 import 
org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerArgumentsMapper;
@@ -40,11 +42,15 @@
 import org.springframework.stereotype.Component;
 
 import io.swagger.annotations.ApiOperation;
+import io.swagger.models.Operation;
 
 @Component
 public class SwaggerEnvironment {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(SwaggerEnvironment.class);
 
+  @Inject
+  protected CompositeSwaggerGeneratorContext compositeSwaggerGeneratorContext;
+
   @Inject
   private ProducerArgumentsMapperFactory producerArgumentsFactory;
 
@@ -63,6 +69,15 @@ public void setConverterMgr(ConverterMgr converterMgr) {
     producerResponseMapperFactorys.setConverterMgr(converterMgr);
   }
 
+  public CompositeSwaggerGeneratorContext 
getCompositeSwaggerGeneratorContext() {
+    return compositeSwaggerGeneratorContext;
+  }
+
+  public void setCompositeSwaggerGeneratorContext(
+      CompositeSwaggerGeneratorContext compositeSwaggerGeneratorContext) {
+    this.compositeSwaggerGeneratorContext = compositeSwaggerGeneratorContext;
+  }
+
   public ProducerArgumentsMapperFactory getProducerArgumentsFactory() {
     return producerArgumentsFactory;
   }
@@ -101,8 +116,12 @@ public SwaggerConsumer createConsumer(Class<?> 
consumerIntf, Class<?> swaggerInt
         continue;
       }
 
+      ArgumentsMapperConfig config = new ArgumentsMapperConfig();
+      config.setSwaggerMethod(swaggerMethod);
+      config.setProviderMethod(consumerMethod);
+
       ConsumerArgumentsMapper argsMapper =
-          consumerArgumentsFactory.createArgumentsMapper(swaggerMethod, 
consumerMethod);
+          consumerArgumentsFactory.createArgumentsMapper(config);
       ConsumerResponseMapper responseMapper = 
consumerResponseMapperFactorys.createResponseMapper(
           swaggerMethod.getGenericReturnType(),
           consumerMethod.getGenericReturnType());
@@ -129,7 +148,8 @@ protected String findSwaggerMethodName(Method 
consumerMethod) {
     return apiOperationAnnotation.nickname();
   }
 
-  public SwaggerProducer createProducer(Object producerInstance, Class<?> 
swaggerIntf) {
+  public SwaggerProducer createProducer(Object producerInstance, Class<?> 
swaggerIntf,
+      Map<String, Operation> swaggerOperationMap) {
     Class<?> producerCls = BeanUtils.getImplClassFromBean(producerInstance);
     Map<String, Method> visibleProducerMethods = 
retrieveVisibleMethods(producerCls);
 
@@ -148,8 +168,13 @@ public SwaggerProducer createProducer(Object 
producerInstance, Class<?> swaggerI
         throw new Error(msg);
       }
 
-      ProducerArgumentsMapper argsMapper = 
producerArgumentsFactory.createArgumentsMapper(swaggerMethod,
-          producerMethod);
+      ArgumentsMapperConfig config = new ArgumentsMapperConfig();
+      config.setSwaggerMethod(swaggerMethod);
+      config.setProviderMethod(producerMethod);
+      config.setSwaggerOperation(swaggerOperationMap.get(methodName));
+      
config.setSwaggerGeneratorContext(compositeSwaggerGeneratorContext.selectContext(producerCls));
+
+      ProducerArgumentsMapper argsMapper = 
producerArgumentsFactory.createArgumentsMapper(config);
       ProducerResponseMapper responseMapper = 
producerResponseMapperFactorys.createResponseMapper(
           swaggerMethod.getGenericReturnType(),
           producerMethod.getGenericReturnType());
diff --git 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/bootstrap/BootstrapNormal.java
 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/bootstrap/BootstrapNormal.java
index 83e32aa1e..9ed501a58 100644
--- 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/bootstrap/BootstrapNormal.java
+++ 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/engine/bootstrap/BootstrapNormal.java
@@ -20,6 +20,7 @@
 
 import org.apache.servicecomb.swagger.engine.SwaggerBootstrap;
 import org.apache.servicecomb.swagger.engine.SwaggerEnvironment;
+import 
org.apache.servicecomb.swagger.generator.core.CompositeSwaggerGeneratorContext;
 import 
org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerArgumentsMapperFactory;
 import 
org.apache.servicecomb.swagger.invocation.arguments.consumer.ConsumerInvocationContextMapperFactory;
 import 
org.apache.servicecomb.swagger.invocation.arguments.producer.ProducerArgumentsMapperFactory;
@@ -43,6 +44,7 @@ public SwaggerEnvironment boot() {
     env.setConsumerArgumentsFactory(consumerArgumentsFactory);
 
     env.setConverterMgr(converterMgr);
+    env.setCompositeSwaggerGeneratorContext(new 
CompositeSwaggerGeneratorContext());
 
     return env;
   }
diff --git 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperConfig.java
 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperConfig.java
index fcb89d536..da2708308 100644
--- 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperConfig.java
+++ 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperConfig.java
@@ -21,12 +21,20 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.servicecomb.swagger.generator.core.SwaggerGeneratorContext;
+
+import io.swagger.models.Operation;
+
 public class ArgumentsMapperConfig {
   // input
   private Method swaggerMethod;
 
   private Method providerMethod;
 
+  private Operation swaggerOperation;
+
+  private SwaggerGeneratorContext swaggerGeneratorContext;
+
   // output
   private List<ArgumentMapper> argumentMapperList = new ArrayList<>();
 
@@ -46,6 +54,23 @@ public void setProviderMethod(Method providerMethod) {
     this.providerMethod = providerMethod;
   }
 
+  public Operation getSwaggerOperation() {
+    return swaggerOperation;
+  }
+
+  public void setSwaggerOperation(Operation swaggerOperation) {
+    this.swaggerOperation = swaggerOperation;
+  }
+
+  public SwaggerGeneratorContext getSwaggerGeneratorContext() {
+    return swaggerGeneratorContext;
+  }
+
+  public void setSwaggerGeneratorContext(
+      SwaggerGeneratorContext swaggerGeneratorContext) {
+    this.swaggerGeneratorContext = swaggerGeneratorContext;
+  }
+
   public List<ArgumentMapper> getArgumentMapperList() {
     return argumentMapperList;
   }
@@ -57,4 +82,16 @@ public void setArgumentMapperList(List<ArgumentMapper> 
argumentMapperList) {
   public void addArgumentMapper(ArgumentMapper argumentMapper) {
     argumentMapperList.add(argumentMapper);
   }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder("ArgumentsMapperConfig{");
+    sb.append("swaggerMethod=").append(swaggerMethod);
+    sb.append(", providerMethod=").append(providerMethod);
+    sb.append(", swaggerOperation=").append(swaggerOperation);
+    sb.append(", swaggerGeneratorContext=").append(swaggerGeneratorContext);
+    sb.append(", argumentMapperList=").append(argumentMapperList);
+    sb.append('}');
+    return sb.toString();
+  }
 }
diff --git 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperFactory.java
 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperFactory.java
index 8e4f183dc..3d86a4962 100644
--- 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperFactory.java
+++ 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ArgumentsMapperFactory.java
@@ -17,6 +17,7 @@
 
 package org.apache.servicecomb.swagger.invocation.arguments;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
@@ -26,14 +27,30 @@
 import java.util.Map;
 
 import javax.inject.Inject;
+import javax.ws.rs.CookieParam;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
 
+import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils;
 import org.apache.servicecomb.swagger.invocation.InvocationType;
 import org.apache.servicecomb.swagger.invocation.converter.Converter;
 import org.apache.servicecomb.swagger.invocation.converter.ConverterMgr;
 import 
org.apache.servicecomb.swagger.invocation.converter.impl.ConverterCommon;
 import org.springframework.util.TypeUtils;
+import org.springframework.web.bind.annotation.CookieValue;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestAttribute;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RequestPart;
 
-public abstract class ArgumentsMapperFactory {
+
+/**
+ * @param <T> type of the generated ArgumentsMapper
+ */
+public abstract class ArgumentsMapperFactory<T> {
   @Inject
   protected ConverterMgr converterMgr;
 
@@ -59,16 +76,6 @@ protected ContextArgumentMapperFactory findFactory(Type 
type) {
     return null;
   }
 
-  public <T> T createArgumentsMapper(Method swaggerMethod, Method 
providerMethod) {
-    ArgumentsMapperConfig config = new ArgumentsMapperConfig();
-    config.setSwaggerMethod(swaggerMethod);
-    config.setProviderMethod(providerMethod);
-
-    collectArgumentsMapper(config);
-
-    return createArgumentsMapper(config);
-  }
-
   protected void collectArgumentsMapper(ArgumentsMapperConfig config) {
     List<ProviderParameter> providerNormalParams = 
collectContextArgumentsMapper(config);
     if (providerNormalParams.isEmpty()) {
@@ -128,13 +135,70 @@ protected boolean isSwaggerWrapBody(ArgumentsMapperConfig 
config, List<ProviderP
         continue;
       }
 
-      ProviderParameter pp = new ProviderParameter(providerIdx, parameterType);
+      ProviderParameter pp = new ProviderParameter(providerIdx, parameterType,
+          retrieveVisibleParamName(config.getProviderMethod(), providerIdx));
       providerNormalParams.add(pp);
     }
 
     return providerNormalParams;
   }
 
+  /**
+   * Try to get the swagger param name of the corresponding producer/consumer 
method param
+   * @param method producer/consumer method
+   * @param paramIndex index of the producer/consumer method
+   * @return the param name specified by param annotations, or the param name 
defined in code
+   */
+  public static String retrieveVisibleParamName(Method method, int paramIndex) 
{
+    final Annotation[] annotations = 
method.getParameterAnnotations()[paramIndex];
+    String paramName = null;
+    for (Annotation annotation : annotations) {
+      paramName = retrieveVisibleParamName(annotation);
+    }
+    if (null == paramName) {
+      paramName = ParamUtils.getParameterName(method, paramIndex);
+    }
+    return paramName;
+  }
+
+  public static String retrieveVisibleParamName(Annotation annotation) {
+    if (CookieParam.class.isInstance(annotation)) {
+      return ((CookieParam) annotation).value();
+    }
+    if (CookieValue.class.isInstance(annotation)) {
+      return ((CookieValue) annotation).name();
+    }
+    if (FormParam.class.isInstance(annotation)) {
+      return ((FormParam) annotation).value();
+    }
+    if (HeaderParam.class.isInstance(annotation)) {
+      return ((HeaderParam) annotation).value();
+    }
+    if (PathParam.class.isInstance(annotation)) {
+      return ((PathParam) annotation).value();
+    }
+    if (PathVariable.class.isInstance(annotation)) {
+      return ((PathVariable) annotation).value();
+    }
+    if (QueryParam.class.isInstance(annotation)) {
+      return ((QueryParam) annotation).value();
+    }
+    if (RequestAttribute.class.isInstance(annotation)) {
+      return ((RequestAttribute) annotation).name();
+    }
+    if (RequestHeader.class.isInstance(annotation)) {
+      return ((RequestHeader) annotation).name();
+    }
+    if (RequestParam.class.isInstance(annotation)) {
+      return ((RequestParam) annotation).name();
+    }
+    if (RequestPart.class.isInstance(annotation)) {
+      return ((RequestPart) annotation).name();
+    }
+
+    return null;
+  }
+
   protected void collectSwaggerArgumentsMapper(ArgumentsMapperConfig config,
       List<ProviderParameter> providerNormalParams) {
     Method swaggerMethod = config.getSwaggerMethod();
@@ -180,7 +244,7 @@ protected void collectWrapBodyMapper(ArgumentsMapperConfig 
config, List<Provider
     config.addArgumentMapper(bodyFieldArg);
   }
 
-  protected abstract <T> T createArgumentsMapper(ArgumentsMapperConfig config);
+  public abstract T createArgumentsMapper(ArgumentsMapperConfig config);
 
   protected abstract ArgumentMapper createArgumentMapperWithConverter(int 
swaggerIdx, int providerIdx,
       Converter converter);
diff --git 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ProviderParameter.java
 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ProviderParameter.java
index 3382a97e6..299c02f9b 100644
--- 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ProviderParameter.java
+++ 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/ProviderParameter.java
@@ -23,24 +23,51 @@
 
   private Type type;
 
-  public ProviderParameter(int index, Type type) {
+  /**
+   * the param name specified by param annotations(i.e. the param name in 
schema), or the param name defined in code
+   */
+  private String name;
+
+  public ProviderParameter(int index, Type type, String name) {
     this.index = index;
     this.type = type;
+    this.name = name;
   }
 
   public int getIndex() {
     return index;
   }
 
-  public void setIndex(int index) {
+  public ProviderParameter setIndex(int index) {
     this.index = index;
+    return this;
   }
 
   public Type getType() {
     return type;
   }
 
-  public void setType(Type type) {
+  public ProviderParameter setType(Type type) {
     this.type = type;
+    return this;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public ProviderParameter setName(String name) {
+    this.name = name;
+    return this;
+  }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder("ProviderParameter{");
+    sb.append("index=").append(index);
+    sb.append(", type=").append(type);
+    sb.append(", name='").append(name).append('\'');
+    sb.append('}');
+    return sb.toString();
   }
 }
diff --git 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapperFactory.java
 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapperFactory.java
index 7d77890da..54a69ca82 100644
--- 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapperFactory.java
+++ 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/consumer/ConsumerArgumentsMapperFactory.java
@@ -33,7 +33,7 @@
 import org.springframework.stereotype.Component;
 
 @Component
-public class ConsumerArgumentsMapperFactory extends ArgumentsMapperFactory {
+public class ConsumerArgumentsMapperFactory extends 
ArgumentsMapperFactory<ConsumerArgumentsMapper> {
   public ConsumerArgumentsMapperFactory() {
     type = InvocationType.CONSUMER;
   }
@@ -46,8 +46,9 @@ public void setFactoryList(List<ContextArgumentMapperFactory> 
factoryList) {
 
   @SuppressWarnings("unchecked")
   @Override
-  protected <T> T createArgumentsMapper(ArgumentsMapperConfig config) {
-    return (T) new ConsumerArgumentsMapper(config.getArgumentMapperList(),
+  public ConsumerArgumentsMapper createArgumentsMapper(ArgumentsMapperConfig 
config) {
+    collectArgumentsMapper(config);
+    return new ConsumerArgumentsMapper(config.getArgumentMapperList(),
         config.getSwaggerMethod().getParameterCount());
   }
 
diff --git 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperFactory.java
 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperFactory.java
index c3d47eab3..204dea9fa 100644
--- 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperFactory.java
+++ 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerArgumentsMapperFactory.java
@@ -17,23 +17,40 @@
 
 package org.apache.servicecomb.swagger.invocation.arguments.producer;
 
+import java.lang.reflect.Type;
+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 javax.inject.Inject;
 
+import org.apache.servicecomb.swagger.generator.core.utils.ParamUtils;
 import org.apache.servicecomb.swagger.invocation.InvocationType;
 import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper;
 import 
org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperConfig;
 import 
org.apache.servicecomb.swagger.invocation.arguments.ArgumentsMapperFactory;
 import 
org.apache.servicecomb.swagger.invocation.arguments.ContextArgumentMapperFactory;
 import org.apache.servicecomb.swagger.invocation.arguments.FieldInfo;
+import org.apache.servicecomb.swagger.invocation.arguments.ProviderParameter;
 import org.apache.servicecomb.swagger.invocation.converter.Converter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
 
+import io.swagger.converter.ModelConverters;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.parameters.QueryParameter;
+import io.swagger.models.properties.Property;
+import io.swagger.models.properties.RefProperty;
+
 @Component
-public class ProducerArgumentsMapperFactory extends ArgumentsMapperFactory {
+public class ProducerArgumentsMapperFactory extends 
ArgumentsMapperFactory<ProducerArgumentsMapper> {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ProducerArgumentsMapperFactory.class);
+
   public ProducerArgumentsMapperFactory() {
     type = InvocationType.PRODUCER;
   }
@@ -46,11 +63,131 @@ public void 
setFactoryList(List<ContextArgumentMapperFactory> factoryList) {
 
   @SuppressWarnings("unchecked")
   @Override
-  protected <T> T createArgumentsMapper(ArgumentsMapperConfig config) {
-    return (T) new ProducerArgumentsMapper(config.getArgumentMapperList(),
+  public ProducerArgumentsMapper createArgumentsMapper(ArgumentsMapperConfig 
config) {
+    collectArgumentsMapper(config);
+    return new ProducerArgumentsMapper(config.getArgumentMapperList(),
         config.getProviderMethod().getParameterCount());
   }
 
+  @Override
+  protected void collectSwaggerArgumentsMapper(ArgumentsMapperConfig config,
+      List<ProviderParameter> providerNormalParams) {
+    if 
(!config.getSwaggerGeneratorContext().getClass().getCanonicalName().equals(
+        
"org.apache.servicecomb.swagger.generator.springmvc.SpringmvcSwaggerGeneratorContext"))
 {
+      // if this is not a SpringMVC style provider operation, there is no need 
to consider query object param
+      super.collectSwaggerArgumentsMapper(config, providerNormalParams);
+      return;
+    }
+
+    Map<String, ProviderParameter> providerParamMap = 
getProviderParamMap(providerNormalParams);
+    Map<String, ParamWrapper<Parameter>> swaggerParamMap = 
getSwaggerParamMap(config);
+
+    Set<String> queryObjectNames = findSpringMvcQueryObject(providerParamMap, 
swaggerParamMap);
+    if (queryObjectNames.isEmpty()) {
+      // there is no query object param, run as 1-to-1 param mapping mode
+      super.collectSwaggerArgumentsMapper(config, providerNormalParams);
+      return;
+    }
+
+    // There is at lease one query object param, so the param mapping mode 
becomes to M-to-N
+    // try to map params by name
+    generateParamMapperByName(config, providerParamMap, swaggerParamMap, 
queryObjectNames);
+  }
+
+  private void generateParamMapperByName(ArgumentsMapperConfig config, 
Map<String, ProviderParameter> providerParamMap,
+      Map<String, ParamWrapper<Parameter>> swaggerParamMap, Set<String> 
queryObjectNames) {
+    LOGGER.info("mapping query object params: [{}]", queryObjectNames);
+    generateObjectQueryParamMapper(config, providerParamMap, swaggerParamMap, 
queryObjectNames);
+    generateDefaultParamMapper(config, providerParamMap, swaggerParamMap, 
queryObjectNames);
+  }
+
+  /**
+   * Generate default argument mappers. One swagger argument is mapped to one 
producer argument.
+   */
+  private void generateDefaultParamMapper(ArgumentsMapperConfig config, 
Map<String, ProviderParameter> providerParamMap,
+      Map<String, ParamWrapper<Parameter>> swaggerParamMap, Set<String> 
queryObjectNames) {
+    Type[] swaggerParamTypes = 
config.getSwaggerMethod().getGenericParameterTypes();
+    for (Entry<String, ProviderParameter> providerParamEntry : 
providerParamMap.entrySet()) {
+      if (queryObjectNames.contains(providerParamEntry.getKey())) {
+        continue;
+      }
+
+      final int swaggerIdx = 
swaggerParamMap.get(providerParamEntry.getKey()).getIndex();
+      Converter converter = converterMgr.findConverter(type, 
providerParamEntry.getValue().getType(),
+          swaggerParamTypes[swaggerIdx]);
+      ArgumentMapper mapper =
+          createArgumentMapperWithConverter(swaggerIdx, 
providerParamEntry.getValue().getIndex(), converter);
+      config.addArgumentMapper(mapper);
+    }
+  }
+
+  /**
+   * Generate argument mappers for query object params. Collect all query 
params as json and map them to object param.
+   */
+  private void generateObjectQueryParamMapper(ArgumentsMapperConfig config,
+      Map<String, ProviderParameter> providerParamMap, Map<String, 
ParamWrapper<Parameter>> swaggerParamMap,
+      Set<String> queryObjectNames) {
+    // collect all query params
+    Map<String, Integer> querySwaggerParamsIndex = new HashMap<>();
+    for (Entry<String, ParamWrapper<Parameter>> wrapperEntry : 
swaggerParamMap.entrySet()) {
+      if (wrapperEntry.getValue().getParam() instanceof QueryParameter) {
+        querySwaggerParamsIndex.put(wrapperEntry.getKey(), 
wrapperEntry.getValue().getIndex());
+      }
+    }
+    // create mapper for each query objects
+    for (String queryObjectName : queryObjectNames) {
+      final ProviderParameter providerParameter = 
providerParamMap.get(queryObjectName);
+      ArgumentMapper mapper = new 
ProducerSpringMVCQueryObjectMapper(querySwaggerParamsIndex,
+          providerParameter.getIndex(),
+          providerParameter.getType());
+      config.addArgumentMapper(mapper);
+    }
+  }
+
+  private Map<String, ParamWrapper<Parameter>> 
getSwaggerParamMap(ArgumentsMapperConfig config) {
+    Map<String, ParamWrapper<Parameter>> swaggerParamMap =
+        new HashMap<>(config.getSwaggerOperation().getParameters().size());
+    List<Parameter> parameters = config.getSwaggerOperation().getParameters();
+    for (int i = 0; i < parameters.size(); i++) {
+      Parameter parameter = parameters.get(i);
+      swaggerParamMap.put(parameter.getName(), new 
ParamWrapper<>(parameter).setIndex(i));
+    }
+    return swaggerParamMap;
+  }
+
+  private Map<String, ProviderParameter> 
getProviderParamMap(List<ProviderParameter> providerNormalParams) {
+    Map<String, ProviderParameter> providerParamMap = new 
HashMap<>(providerNormalParams.size());
+    providerNormalParams.forEach(
+        providerParameter -> providerParamMap.put(providerParameter.getName(), 
providerParameter));
+    return providerParamMap;
+  }
+
+  /**
+   * Find all query object params
+   * @return the names of the query object params
+   */
+  private Set<String> findSpringMvcQueryObject(Map<String, ProviderParameter> 
providerParamMap,
+      Map<String, ParamWrapper<Parameter>> swaggerParamMap) {
+    // find all reference type producer params, and exclude body param
+    Set<String> queryObjectSet = new HashSet<>();
+
+    for (Entry<String, ProviderParameter> paramEntry : 
providerParamMap.entrySet()) {
+      Type paramType = paramEntry.getValue().getType();
+      Property property = 
ModelConverters.getInstance().readAsProperty(paramType);
+      if (RefProperty.class.isInstance(property)) {
+        queryObjectSet.add(paramEntry.getKey());
+      }
+    }
+
+    for (Entry<String, ParamWrapper<Parameter>> paramEntry : 
swaggerParamMap.entrySet()) {
+      if (ParamUtils.isRealBodyParameter(paramEntry.getValue().getParam())) {
+        queryObjectSet.remove(paramEntry.getKey());
+      }
+    }
+
+    return queryObjectSet;
+  }
+
   @Override
   protected ArgumentMapper createArgumentMapperWithConverter(int swaggerIdx, 
int producerIdx, Converter converter) {
     return new ProducerArgumentSame(swaggerIdx, producerIdx, converter);
@@ -61,4 +198,41 @@ protected ArgumentMapper 
createBodyFieldArgMapper(ArgumentsMapperConfig config,
       Map<Integer, FieldInfo> fieldMap) {
     return new SwaggerArgumentToProducerBodyField(fieldMap);
   }
+
+  public static class ParamWrapper<T> {
+    T param;
+
+    int index;
+
+    public ParamWrapper(T param) {
+      this.param = param;
+    }
+
+    public T getParam() {
+      return param;
+    }
+
+    public ParamWrapper<T> setParam(T param) {
+      this.param = param;
+      return this;
+    }
+
+    public int getIndex() {
+      return index;
+    }
+
+    public ParamWrapper<T> setIndex(int index) {
+      this.index = index;
+      return this;
+    }
+
+    @Override
+    public String toString() {
+      final StringBuilder sb = new StringBuilder("ParamWrapper{");
+      sb.append("param=").append(param);
+      sb.append(", index=").append(index);
+      sb.append('}');
+      return sb.toString();
+    }
+  }
 }
diff --git 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapper.java
 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapper.java
new file mode 100644
index 000000000..bba8b407e
--- /dev/null
+++ 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapper.java
@@ -0,0 +1,61 @@
+/*
+ * 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.swagger.invocation.arguments.producer;
+
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.servicecomb.swagger.invocation.SwaggerInvocation;
+import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper;
+import org.apache.servicecomb.swagger.invocation.converter.Converter;
+import 
org.apache.servicecomb.swagger.invocation.converter.impl.ConverterCommon;
+
+/**
+ * Argument mapper for object params.
+ * <p/>
+ * Collect all query swagger params as json and deserialize to object param.
+ */
+public class ProducerSpringMVCQueryObjectMapper implements ArgumentMapper {
+  private int producerIdx;
+
+  private Map<String, Integer> swaggerParamIndexMap;
+
+  private Converter converter;
+
+  public ProducerSpringMVCQueryObjectMapper(Map<String, Integer> 
swaggerParamIndexMap, int producerIdx,
+      Type producerParamType) {
+    this.producerIdx = producerIdx;
+    this.swaggerParamIndexMap = new HashMap<>();
+    this.swaggerParamIndexMap.putAll(swaggerParamIndexMap);
+    converter = new ConverterCommon(producerParamType);
+  }
+
+  @Override
+  public void mapArgument(SwaggerInvocation invocation, Object[] 
producerArguments) {
+    Map<String, Object> jsonMap = new HashMap<>(swaggerParamIndexMap.size());
+
+    for (Entry<String, Integer> swaggerIndexEntry : 
swaggerParamIndexMap.entrySet()) {
+      jsonMap.put(swaggerIndexEntry.getKey(), 
invocation.getSwaggerArgument(swaggerIndexEntry.getValue()));
+    }
+
+    final Object producerParam = converter.convert(jsonMap);
+    producerArguments[producerIdx] = producerParam;
+  }
+}
diff --git 
a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/engine/SwaggerEnvironmentForTest.java
 
b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/engine/SwaggerEnvironmentForTest.java
index 72eb40db4..b2c6d006c 100644
--- 
a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/engine/SwaggerEnvironmentForTest.java
+++ 
b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/engine/SwaggerEnvironmentForTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.servicecomb.engine;
 
+import java.util.LinkedHashMap;
+
 import org.apache.servicecomb.foundation.common.utils.BeanUtils;
 import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator;
 import org.apache.servicecomb.swagger.engine.SwaggerEnvironment;
@@ -47,6 +49,7 @@ public SwaggerProducer createProducer(Object 
producerInstance) {
 
     SwaggerToClassGenerator swaggerToClassGenerator = new 
SwaggerToClassGenerator(classLoader, swagger,
         producerInstance.getClass().getPackage().getName());
-    return swaggerEnvironment.createProducer(producerInstance, 
swaggerToClassGenerator.convert());
+    return swaggerEnvironment.createProducer(producerInstance, 
swaggerToClassGenerator.convert(),
+        new LinkedHashMap<>());
   }
 }
diff --git 
a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapperTest.java
 
b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapperTest.java
new file mode 100644
index 000000000..fea80f258
--- /dev/null
+++ 
b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/arguments/producer/ProducerSpringMVCQueryObjectMapperTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.swagger.invocation.arguments.producer;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Objects;
+
+import org.apache.servicecomb.swagger.invocation.SwaggerInvocation;
+import org.apache.servicecomb.swagger.invocation.arguments.ArgumentMapper;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ProducerSpringMVCQueryObjectMapperTest {
+
+  @Test
+  public void mapArgument() {
+    final HashMap<String, Integer> swaggerParamIndexMap = new HashMap<>();
+    swaggerParamIndexMap.put("name", 0);
+    swaggerParamIndexMap.put("age", 1);
+    ArgumentMapper argumentMapper = new 
ProducerSpringMVCQueryObjectMapper(swaggerParamIndexMap, 0, TestParam.class);
+    SwaggerInvocation swaggerInvocation = new SwaggerInvocation();
+    swaggerInvocation.setSwaggerArguments(new Object[] {"nameTest", 22});
+
+    final Object[] producerArguments = new Object[1];
+    argumentMapper.mapArgument(swaggerInvocation, producerArguments);
+    Assert.assertEquals(producerArguments[0], new 
TestParam().setName("nameTest").setAge(22));
+  }
+
+  @Test
+  public void mapArgumentOnRecursiveParam() {
+    final HashMap<String, Integer> swaggerParamIndexMap = new HashMap<>();
+    swaggerParamIndexMap.put("num", 0);
+    swaggerParamIndexMap.put("str", 1);
+    swaggerParamIndexMap.put("date", 2);
+    ArgumentMapper argumentMapper = new 
ProducerSpringMVCQueryObjectMapper(swaggerParamIndexMap, 1,
+        RecursiveParam.class);
+    SwaggerInvocation swaggerInvocation = new SwaggerInvocation();
+    final Date testDate = new Date();
+    swaggerInvocation.setSwaggerArguments(new Object[] {2, "str0_0", 
testDate});
+
+    final Object[] producerArguments = new Object[2];
+    argumentMapper.mapArgument(swaggerInvocation, producerArguments);
+    Assert.assertNull(producerArguments[0]);
+    Assert.assertEquals(producerArguments[1], new 
RecursiveParam().setNum(2).setStr("str0_0").setDate(testDate));
+  }
+
+  static class TestParam {
+    private String name;
+
+    private int age;
+
+    public String getName() {
+      return name;
+    }
+
+    public TestParam setName(String name) {
+      this.name = name;
+      return this;
+    }
+
+    public int getAge() {
+      return age;
+    }
+
+    public TestParam setAge(int age) {
+      this.age = age;
+      return this;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      TestParam testParam = (TestParam) o;
+      return age == testParam.age &&
+          Objects.equals(name, testParam.name);
+    }
+
+    @Override
+    public int hashCode() {
+      return Objects.hash(name, age);
+    }
+  }
+
+  static class RecursiveParam {
+
+    private int num;
+
+    private String str;
+
+    private Date date;
+
+    private RecursiveParam recursiveParam;
+
+    public int getNum() {
+      return num;
+    }
+
+    public RecursiveParam setNum(int num) {
+      this.num = num;
+      return this;
+    }
+
+    public String getStr() {
+      return str;
+    }
+
+    public RecursiveParam setStr(String str) {
+      this.str = str;
+      return this;
+    }
+
+    public Date getDate() {
+      return date;
+    }
+
+    public RecursiveParam setDate(Date date) {
+      this.date = date;
+      return this;
+    }
+
+    public RecursiveParam getRecursiveParam() {
+      return recursiveParam;
+    }
+
+    public RecursiveParam setRecursiveParam(
+        RecursiveParam recursiveParam) {
+      this.recursiveParam = recursiveParam;
+      return this;
+    }
+
+    @Override
+    public String toString() {
+      final StringBuilder sb = new StringBuilder("RecursiveParam{");
+      sb.append("num=").append(num);
+      sb.append(", str='").append(str).append('\'');
+      sb.append(", date=").append(date);
+      sb.append(", recursiveParam=").append(recursiveParam);
+      sb.append('}');
+      return sb.toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      if (this == o) {
+        return true;
+      }
+      if (o == null || getClass() != o.getClass()) {
+        return false;
+      }
+      RecursiveParam that = (RecursiveParam) o;
+      return num == that.num &&
+          Objects.equals(str, that.str) &&
+          Objects.equals(date, that.date) &&
+          Objects.equals(recursiveParam, that.recursiveParam);
+    }
+
+    @Override
+    public int hashCode() {
+      return Objects.hash(num, str, date, recursiveParam);
+    }
+  }
+}
\ No newline at end of file


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to