[ 
https://issues.apache.org/jira/browse/SCB-847?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16583279#comment-16583279
 ] 

ASF GitHub Bot commented on SCB-847:
------------------------------------

liubao68 closed pull request #874: [SCB-847]Provide a way to decode user's 
custom error data
URL: https://github.com/apache/incubator-servicecomb-java-chassis/pull/874
 
 
   

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/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapperFactory.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapperFactory.java
index 188d9dec3..c6d5d65c4 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapperFactory.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/RestObjectMapperFactory.java
@@ -23,10 +23,20 @@
 public class RestObjectMapperFactory {
   private static AbstractRestObjectMapper defaultMapper = new 
RestObjectMapper();
 
+  private static AbstractRestObjectMapper consumerWriterMapper = new 
RestObjectMapper();
+
+  public static AbstractRestObjectMapper getConsumerWriterMapper() {
+    return consumerWriterMapper;
+  }
+
   public static AbstractRestObjectMapper getRestObjectMapper() {
     return defaultMapper;
   }
 
+  public static void setConsumerWriterMapper(AbstractRestObjectMapper 
customMapper) {
+    consumerWriterMapper = customMapper;
+  }
+
   public static void setDefaultRestObjectMapper(AbstractRestObjectMapper 
customMapper) {
     defaultMapper = customMapper;
   }
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
index 61f0ea959..ff5f5872d 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/BodyProcessorCreator.java
@@ -68,7 +68,7 @@ public Object getValue(HttpServletRequest request) throws 
Exception {
       contentType = contentType == null ? "" : 
contentType.toLowerCase(Locale.US);
       if (contentType.startsWith(MediaType.MULTIPART_FORM_DATA)
           || contentType.startsWith(MediaType.APPLICATION_FORM_URLENCODED)) {
-        return 
RestObjectMapperFactory.getRestObjectMapper().convertValue(request.getParameterMap(),
 targetType);
+        return convertValue(request.getParameterMap(), targetType);
       }
 
       // for standard HttpServletRequest, getInputStream will never return null
@@ -85,7 +85,8 @@ public Object getValue(HttpServletRequest request) throws 
Exception {
       }
 
       try {
-        return 
RestObjectMapperFactory.getRestObjectMapper().readValue(inputStream, 
targetType);
+        return RestObjectMapperFactory.getRestObjectMapper()
+            .readValue(inputStream, targetType);
       } catch (MismatchedInputException e) {
         // there is no way to detect InputStream is empty, so have to catch 
the exception
         if (!isRequired) {
@@ -100,7 +101,7 @@ public Object getValue(HttpServletRequest request) throws 
Exception {
     public void setValue(RestClientRequest clientRequest, Object arg) throws 
Exception {
       try (BufferOutputStream output = new BufferOutputStream()) {
         clientRequest.putHeader(HttpHeaders.CONTENT_TYPE, 
MediaType.APPLICATION_JSON);
-        RestObjectMapperFactory.getRestObjectMapper().writeValue(output, arg);
+        RestObjectMapperFactory.getConsumerWriterMapper().writeValue(output, 
arg);
         if (arg != null) {
           clientRequest.write(output.getBuffer());
         }
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java
index 7f8a7761a..659637e50 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/CookieProcessorCreator.java
@@ -64,7 +64,8 @@ public Object getValue(HttpServletRequest request) throws 
Exception {
 
     @Override
     public void setValue(RestClientRequest clientRequest, Object arg) throws 
Exception {
-      clientRequest.addCookie(paramPath, 
RestObjectMapperFactory.getRestObjectMapper().convertToString(arg));
+      clientRequest.addCookie(paramPath,
+          
RestObjectMapperFactory.getConsumerWriterMapper().convertToString(arg));
     }
 
     @Override
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java
index 43b458282..810e01814 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/HeaderProcessorCreator.java
@@ -74,7 +74,8 @@ public void setValue(RestClientRequest clientRequest, Object 
arg) throws Excepti
         LOGGER.debug("Header arg is null, will not be set into clientRequest. 
paramPath = [{}]", paramPath);
         return;
       }
-      clientRequest.putHeader(paramPath, 
RestObjectMapperFactory.getRestObjectMapper().convertToString(arg));
+      clientRequest.putHeader(paramPath,
+          
RestObjectMapperFactory.getConsumerWriterMapper().convertToString(arg));
     }
 
     @Override
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessor.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessor.java
index e38f7dc25..e2d8b67b3 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessor.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/ParamValueProcessor.java
@@ -30,7 +30,8 @@
   void setValue(RestClientRequest clientRequest, Object arg) throws Exception;
 
   default Object convertValue(Object value, JavaType targetType) {
-    return RestObjectMapperFactory.getRestObjectMapper().convertValue(value, 
targetType);
+    return RestObjectMapperFactory.getRestObjectMapper()
+        .convertValue(value, targetType);
   }
 
   String getParameterPath();
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceJsonProcessor.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceJsonProcessor.java
index 817aef0e6..d4006c74a 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceJsonProcessor.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/produce/ProduceJsonProcessor.java
@@ -40,7 +40,8 @@ public void doEncodeResponse(OutputStream output, Object 
result) throws Exceptio
 
   @Override
   public Object doDecodeResponse(InputStream input, JavaType type) throws 
Exception {
-    return RestObjectMapperFactory.getRestObjectMapper().readValue(input, 
type);
+    return RestObjectMapperFactory.getRestObjectMapper()
+        .readValue(input, type);
   }
 
   @Override
diff --git 
a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/CustomExceptionToResponseConverter.java
 
b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/CustomExceptionToResponseConverter.java
new file mode 100644
index 000000000..fd2ccd90f
--- /dev/null
+++ 
b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/CustomExceptionToResponseConverter.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.demo.edge.business.error;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.servicecomb.swagger.invocation.Response;
+import org.apache.servicecomb.swagger.invocation.SwaggerInvocation;
+import 
org.apache.servicecomb.swagger.invocation.exception.ExceptionToResponseConverter;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+
+public class CustomExceptionToResponseConverter implements 
ExceptionToResponseConverter<IllegalStateException> {
+  @Override
+  public Class<IllegalStateException> getExceptionClass() {
+    return IllegalStateException.class;
+  }
+
+  @Override
+  public int getOrder() {
+    return 100;
+  }
+
+  @Override
+  public Response convert(SwaggerInvocation swaggerInvocation, 
IllegalStateException e) {
+    IllegalStateErrorData data = new IllegalStateErrorData();
+    data.setId(500);
+    data.setMessage(e.getMessage());
+    data.setState(e.getMessage());
+    InvocationException state = new 
InvocationException(Status.INTERNAL_SERVER_ERROR, data);
+    return Response.failResp(state);
+  }
+}
diff --git 
a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/ErrorData.java
 
b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/ErrorData.java
new file mode 100644
index 000000000..078c19414
--- /dev/null
+++ 
b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/ErrorData.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.demo.edge.business.error;
+
+public class ErrorData {
+  private int id;
+
+  private String message;
+
+  public int getId() {
+    return id;
+  }
+
+  public void setId(int id) {
+    this.id = id;
+  }
+
+  public String getMessage() {
+    return message;
+  }
+
+  public void setMessage(String message) {
+    this.message = message;
+  }
+}
diff --git 
a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/ErrorService.java
 
b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/ErrorService.java
new file mode 100644
index 000000000..8bdba9c2b
--- /dev/null
+++ 
b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/ErrorService.java
@@ -0,0 +1,46 @@
+/*
+ * 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.edge.business.error;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+@RestSchema(schemaId = "error-v2")
+@RequestMapping(path = "/business/v2/error")
+public class ErrorService {
+  @RequestMapping(path = "/add", method = RequestMethod.GET)
+  public int add(int x, int y) {
+    if (x == 99) {
+      throw new NullPointerException("un expected NPE test.");
+    }
+    if (x == 88) {
+      ErrorData data = new ErrorData();
+      data.setId(12);
+      data.setMessage("not allowed id.");
+      throw new InvocationException(Status.FORBIDDEN, data);
+    }
+    if (x == 77) {
+      throw new IllegalStateException("77");
+    }
+    return x + y;
+  }
+}
diff --git 
a/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/IllegalStateErrorData.java
 
b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/IllegalStateErrorData.java
new file mode 100644
index 000000000..d771c7a51
--- /dev/null
+++ 
b/demo/demo-edge/business-2.0.0/src/main/java/org/apache/servicecomb/demo/edge/business/error/IllegalStateErrorData.java
@@ -0,0 +1,50 @@
+/*
+ * 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.edge.business.error;
+
+public class IllegalStateErrorData {
+  private int id;
+
+  private String message;
+
+  private String state;
+
+  public int getId() {
+    return id;
+  }
+
+  public void setId(int id) {
+    this.id = id;
+  }
+
+  public String getMessage() {
+    return message;
+  }
+
+  public void setMessage(String message) {
+    this.message = message;
+  }
+
+  public String getState() {
+    return state;
+  }
+
+  public void setState(String state) {
+    this.state = state;
+  }
+}
diff --git 
a/demo/demo-edge/business-2.0.0/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToResponseConverter
 
b/demo/demo-edge/business-2.0.0/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToResponseConverter
new file mode 100644
index 000000000..9a433318c
--- /dev/null
+++ 
b/demo/demo-edge/business-2.0.0/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToResponseConverter
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.apache.servicecomb.demo.edge.business.error.CustomExceptionToResponseConverter
\ No newline at end of file
diff --git 
a/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java
 
b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java
index 7796de943..95ea17a32 100644
--- 
a/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java
+++ 
b/demo/demo-edge/consumer/src/main/java/org/apache/servicecomb/demo/edge/consumer/Consumer.java
@@ -46,6 +46,8 @@
 import org.springframework.util.Assert;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.HttpServerErrorException;
 import org.springframework.web.client.RestTemplate;
 
 public class Consumer {
@@ -88,6 +90,7 @@ public void run(String prefix) {
     testDependType();
     testDownload();
     testDownloadBigFile();
+    testErrorCode();
 
     invoke("/v1/add", 2, 1, addV1Result);
     invoke("/v1/add", 3, 1, addV1Result);
@@ -158,6 +161,32 @@ protected void testRecursiveSelf() {
     Assert.isNull(response.getField().getField(), "must be null");
   }
 
+  @SuppressWarnings({"unckecked", "rawtypes"})
+  protected void testErrorCode() {
+    String url = edgePrefix + "/v2/error/add";
+
+    int response = template.getForObject(url + "?x=2&y=3", Integer.class);
+    Assert.isTrue(response == 5, "not get 5.");
+
+    Map raw = template.getForObject(url + "?x=99&y=3", Map.class);
+    Assert.isTrue(raw.get("message").equals("Cse Internal Server Error"), 
"x99");
+
+    try {
+      template.getForObject(url + "?x=88&y=3", Map.class);
+      Assert.isTrue(false, "x88");
+    } catch (HttpClientErrorException e) {
+      Assert.isTrue(e.getRawStatusCode() == 403, "x88");
+      
Assert.isTrue(e.getResponseBodyAsString().equals("{\"id\":12,\"message\":\"not 
allowed id.\"}"), "x88");
+    }
+    try {
+      template.getForObject(url + "?x=77&y=3", Map.class);
+      Assert.isTrue(false, "x77");
+    } catch (HttpServerErrorException e) {
+      Assert.isTrue(e.getRawStatusCode() == 500, "x77");
+      
Assert.isTrue(e.getResponseBodyAsString().equals("{\"id\":500,\"message\":\"77\",\"state\":\"77\"}"),
 "x77");
+    }
+  }
+
   protected void testDependType() {
     String url = edgePrefix + "/v2/dependType";
 
diff --git 
a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/CustomResponseMetaMapper.java
 
b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/CustomResponseMetaMapper.java
new file mode 100644
index 000000000..c3eaa5110
--- /dev/null
+++ 
b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/CustomResponseMetaMapper.java
@@ -0,0 +1,46 @@
+/*
+ * 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.edge.service;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.servicecomb.swagger.invocation.response.ResponseMeta;
+import org.apache.servicecomb.swagger.invocation.response.ResponseMetaMapper;
+
+import com.fasterxml.jackson.databind.type.SimpleType;
+
+public class CustomResponseMetaMapper implements ResponseMetaMapper {
+  private final static Map<Integer, ResponseMeta> CODES = new HashMap<>(1);
+
+  static {
+    ResponseMeta meta = new ResponseMeta();
+    meta.setJavaType(SimpleType.constructUnsafe(IllegalStateErrorData.class));
+    CODES.put(500, meta);
+  }
+
+  @Override
+  public int getOrder() {
+    return 100;
+  }
+
+  @Override
+  public Map<Integer, ResponseMeta> getMapper() {
+    return CODES;
+  }
+}
diff --git 
a/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/IllegalStateErrorData.java
 
b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/IllegalStateErrorData.java
new file mode 100644
index 000000000..017183f1c
--- /dev/null
+++ 
b/demo/demo-edge/edge-service/src/main/java/org/apache/servicecomb/demo/edge/service/IllegalStateErrorData.java
@@ -0,0 +1,50 @@
+/*
+ * 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.edge.service;
+
+public class IllegalStateErrorData {
+  private int id;
+
+  private String message;
+
+  private String state;
+
+  public int getId() {
+    return id;
+  }
+
+  public void setId(int id) {
+    this.id = id;
+  }
+
+  public String getMessage() {
+    return message;
+  }
+
+  public void setMessage(String message) {
+    this.message = message;
+  }
+
+  public String getState() {
+    return state;
+  }
+
+  public void setState(String state) {
+    this.state = state;
+  }
+}
diff --git 
a/demo/demo-edge/edge-service/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.ResponseMetaMapper
 
b/demo/demo-edge/edge-service/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.ResponseMetaMapper
new file mode 100644
index 000000000..d8a88a705
--- /dev/null
+++ 
b/demo/demo-edge/edge-service/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.response.ResponseMetaMapper
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+org.apache.servicecomb.demo.edge.service.CustomResponseMetaMapper
\ No newline at end of file
diff --git 
a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/JaxrsClient.java
 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/JaxrsClient.java
index f285d5fc0..f28ffbd8b 100644
--- 
a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/JaxrsClient.java
+++ 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/JaxrsClient.java
@@ -30,10 +30,13 @@
 import org.apache.servicecomb.demo.CodeFirstRestTemplate;
 import org.apache.servicecomb.demo.DemoConst;
 import org.apache.servicecomb.demo.RestObjectMapperWithStringMapper;
+import 
org.apache.servicecomb.demo.RestObjectMapperWithStringMapperNotWriteNull;
 import org.apache.servicecomb.demo.TestMgr;
 import org.apache.servicecomb.demo.compute.Person;
 import org.apache.servicecomb.demo.jaxrs.client.beanParam.BeanParamPojoClient;
 import 
org.apache.servicecomb.demo.jaxrs.client.beanParam.BeanParamRestTemplateClient;
+import 
org.apache.servicecomb.demo.jaxrs.client.pojoDefault.DefaultModelServiceClient;
+import 
org.apache.servicecomb.demo.jaxrs.client.validation.ValidationServiceClient;
 import org.apache.servicecomb.demo.validator.Student;
 import org.apache.servicecomb.foundation.common.utils.BeanUtils;
 import org.apache.servicecomb.foundation.common.utils.Log4jUtils;
@@ -62,6 +65,7 @@ public static void init() throws Exception {
     Log4jUtils.init();
     BeanUtils.init();
     RestObjectMapperFactory.setDefaultRestObjectMapper(new 
RestObjectMapperWithStringMapper());
+    RestObjectMapperFactory.setConsumerWriterMapper(new 
RestObjectMapperWithStringMapperNotWriteNull());
   }
 
   public static void run() throws Exception {
@@ -78,6 +82,8 @@ public static void run() throws Exception {
     beanParamPojoClient.testAll();
     BeanParamRestTemplateClient beanParamRestTemplateClient = new 
BeanParamRestTemplateClient();
     beanParamRestTemplateClient.testAll();
+    DefaultModelServiceClient.run();
+    ValidationServiceClient.run();
   }
 
   private static void testCompute(RestTemplate template) throws Exception {
@@ -179,6 +185,9 @@ private static void testJaxRSDefaultValues(RestTemplate 
template) {
       result = template.getForObject(cseUrlPrefix + "/query3?a=30&b=2", 
String.class);
       TestMgr.check("Hello 302", result);
 
+      result = template.getForObject(cseUrlPrefix + "/query3?a=30", 
String.class);
+      TestMgr.check("Hello 30null", result);
+
       //input values
       headers = new HttpHeaders();
       
headers.setContentType(org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED);
@@ -278,6 +287,7 @@ private static void testRawJsonParam(RestTemplate template, 
String cseUrlPrefix)
         template.postForObject(cseUrlPrefix + "/compute/testrawjson", 
jsonPerson, String.class));
   }
 
+  @SuppressWarnings({"unckecked", "rawtypes"})
   private static void testValidatorAddFail(RestTemplate template, String 
cseUrlPrefix) {
     Map<String, String> params = new HashMap<>();
     params.put("a", "5");
@@ -292,10 +302,11 @@ private static void testValidatorAddFail(RestTemplate 
template, String cseUrlPre
       // Message dependends on locale, so just check the short part.
       // 'must be greater than or equal to 20', propertyPath=add.arg1, 
rootBeanClass=class org.apache.servicecomb.demo.jaxrs.server.Validator, 
messageTemplate='{javax.validation.constraints.Min.message}'}]]
       // ignored
+      Map data = (Map) e.getErrorData();
       TestMgr.check(
-          "CommonExceptionData 
[message=[ConstraintViolationImpl{interpolatedMessage=",
-          e.getErrorData().toString().substring(0,
-              "CommonExceptionData 
[message=[ConstraintViolationImpl{interpolatedMessage=".length()));
+          "[ConstraintViolationImpl{interpolatedMessage=",
+          data.get("message").toString().substring(0,
+              "[ConstraintViolationImpl{interpolatedMessage=".length()));
     }
 
     TestMgr.check(true, isExcep);
@@ -309,6 +320,7 @@ private static void testValidatorAddSuccess(RestTemplate 
template, String cseUrl
     TestMgr.check(25, result);
   }
 
+  @SuppressWarnings({"unckecked", "rawtypes"})
   private static void testValidatorSayHiFail(RestTemplate template, String 
cseUrlPrefix) {
     boolean isExcep = false;
     try {
@@ -318,10 +330,11 @@ private static void testValidatorSayHiFail(RestTemplate 
template, String cseUrlP
       TestMgr.check(400, e.getStatus().getStatusCode());
       TestMgr.check(Status.BAD_REQUEST, e.getReasonPhrase());
       // Message dependends on locale, so just check the short part.
+      Map data = (Map) e.getErrorData();
       TestMgr.check(
-          "CommonExceptionData 
[message=[ConstraintViolationImpl{interpolatedMessage=",
-          e.getErrorData().toString().substring(0,
-              "CommonExceptionData 
[message=[ConstraintViolationImpl{interpolatedMessage=".length()));
+          "[ConstraintViolationImpl{interpolatedMessage=",
+          data.get("message").toString().substring(0,
+              "[ConstraintViolationImpl{interpolatedMessage=".length()));
     }
     TestMgr.check(true, isExcep);
   }
@@ -333,6 +346,7 @@ private static void testValidatorSayHiSuccess(RestTemplate 
template, String cseU
     TestMgr.check("world sayhi", responseEntity.getBody());
   }
 
+  @SuppressWarnings({"unckecked", "rawtypes"})
   private static void testValidatorExchangeFail(RestTemplate template, String 
cseUrlPrefix) {
     HttpHeaders headers = new HttpHeaders();
     headers.add("Accept", MediaType.APPLICATION_JSON);
@@ -351,10 +365,11 @@ private static void 
testValidatorExchangeFail(RestTemplate template, String cseU
       TestMgr.check(400, e.getStatus().getStatusCode());
       TestMgr.check(Status.BAD_REQUEST, e.getReasonPhrase());
       // Message dependends on locale, so just check the short part.
+      Map data = (Map) e.getErrorData();
       TestMgr.check(
-          "CommonExceptionData 
[message=[ConstraintViolationImpl{interpolatedMessage=",
-          e.getErrorData().toString().substring(0,
-              "CommonExceptionData 
[message=[ConstraintViolationImpl{interpolatedMessage=".length()));
+          "[ConstraintViolationImpl{interpolatedMessage",
+          data.get("message").toString().substring(0,
+              "[ConstraintViolationImpl{interpolatedMessage".length()));
     }
     TestMgr.check(true, isExcep);
   }
@@ -429,6 +444,9 @@ private static void 
testSpringMvcDefaultValuesJavaPrimitive(RestTemplate templat
     TestMgr.check("Hello", result);
 
     result = template.postForObject(cseUrlPrefix + "/javaprimitivecomb", 
request, String.class);
-    TestMgr.check("Hello 00.0", result);
+    TestMgr.check("Hello nullnull", result);
+
+    result = template.postForObject(cseUrlPrefix + "/allprimitivetypes", null, 
String.class);
+    TestMgr.check("Hello false,0,0,0,0,0,0.0,0.0,null", result);
   }
 }
diff --git 
a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/pojoDefault/DefaultModel.java
 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/pojoDefault/DefaultModel.java
new file mode 100644
index 000000000..1c5d64e64
--- /dev/null
+++ 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/pojoDefault/DefaultModel.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.demo.jaxrs.client.pojoDefault;
+
+public class DefaultModel {
+  private int index;
+
+  public int getIndex() {
+    return index;
+  }
+
+  public void setIndex(int index) {
+    this.index = index;
+  }
+}
diff --git 
a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/pojoDefault/DefaultModelServiceClient.java
 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/pojoDefault/DefaultModelServiceClient.java
new file mode 100644
index 000000000..f6dedf1ef
--- /dev/null
+++ 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/pojoDefault/DefaultModelServiceClient.java
@@ -0,0 +1,46 @@
+/*
+ * 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.jaxrs.client.pojoDefault;
+
+import org.apache.servicecomb.core.CseContext;
+import org.apache.servicecomb.demo.TestMgr;
+import 
org.apache.servicecomb.demo.jaxrs.server.pojoDefault.DefaultResponseModel;
+import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
+import org.springframework.web.client.RestTemplate;
+
+public class DefaultModelServiceClient {
+  private static RestTemplate template = RestTemplateBuilder.create();
+
+  private static String urlPrefix = "cse://jaxrs/DefaultModelService";
+
+  public static void run() {
+    // highway do not support this feature
+    
CseContext.getInstance().getConsumerProviderManager().setTransport("jaxrs", 
"rest");
+    testDefaultModelService();
+  }
+
+  private static void testDefaultModelService() {
+    DefaultModel model = new DefaultModel();
+    model.setIndex(400);
+    DefaultResponseModel result = template.postForObject(urlPrefix + "/model", 
model, DefaultResponseModel.class);
+    TestMgr.check(result.getAge(), 200);
+    TestMgr.check(result.getIndex(), 400);
+    TestMgr.check(result.getName(), "World");
+    TestMgr.check(result.getDesc(), null);
+  }
+}
diff --git 
a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/validation/ValidationServiceClient.java
 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/validation/ValidationServiceClient.java
new file mode 100644
index 000000000..727a05026
--- /dev/null
+++ 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/client/validation/ValidationServiceClient.java
@@ -0,0 +1,77 @@
+/*
+ * 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.jaxrs.client.validation;
+
+import java.util.ArrayList;
+
+import org.apache.servicecomb.core.CseContext;
+import org.apache.servicecomb.demo.TestMgr;
+import org.apache.servicecomb.demo.jaxrs.server.validation.ValidationModel;
+import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.springframework.web.client.RestTemplate;
+
+public class ValidationServiceClient {
+  private static RestTemplate template = RestTemplateBuilder.create();
+
+  private static String urlPrefix = "cse://jaxrs/ValidationService";
+
+  public static void run() {
+    // highway do not support this feature
+    
CseContext.getInstance().getConsumerProviderManager().setTransport("jaxrs", 
"rest");
+    testValidation();
+  }
+
+  private static void testValidation() {
+    ValidationModel model = new ValidationModel();
+    model.setAge(20);
+    model.setMembers(new ArrayList<>());
+    model.setName("name");
+    ValidationModel result = template.postForObject(urlPrefix + "/validate", 
model, ValidationModel.class);
+    TestMgr.check(result.getAge(), 20);
+    TestMgr.check(result.getName(), "name");
+    TestMgr.check(result.getMembers().size(), 0);
+
+    try {
+      model.setAge(null);
+      template.postForObject(urlPrefix + "/validate", model, 
ValidationModel.class);
+      TestMgr.check(false, true);
+    } catch (InvocationException e) {
+      TestMgr.check(e.getErrorData().toString().contains("age"), true);
+    }
+
+    try {
+      model.setAge(20);
+      model.setMembers(null);
+      template.postForObject(urlPrefix + "/validate", model, 
ValidationModel.class);
+      TestMgr.check(false, true);
+    } catch (InvocationException e) {
+      TestMgr.check(e.getErrorData().toString().contains("member"), true);
+    }
+
+    String strResult = template.getForObject(urlPrefix + 
"/validateQuery?name=", String.class);
+    TestMgr.check(strResult, "");
+
+    try {
+      template.getForObject(urlPrefix + "/validateQuery", String.class);
+      TestMgr.check(false, true);
+    } catch (InvocationException e) {
+      TestMgr.check(e.getErrorData().toString().contains("null"), true);
+    }
+  }
+}
diff --git 
a/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java
 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java
new file mode 100644
index 000000000..6c4350a07
--- /dev/null
+++ 
b/demo/demo-jaxrs/jaxrs-client/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java
@@ -0,0 +1,76 @@
+/*
+ * 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.jaxrs.server.pojoDefault;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.Null;
+
+public class DefaultResponseModel {
+  @Min(20)
+  @Max(2000)
+  @Null
+  private Integer age = 200;
+
+  @Min(2)
+  @Max(30)
+  @Null
+  private String name = "World";
+
+  private int index;
+
+  private String desc = "Hello";
+
+  public Integer getAge() {
+    return age;
+  }
+
+  public void setAge(Integer age) {
+    this.age = age;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+
+  public int getIndex() {
+    return index;
+  }
+
+  public void setIndex(int index) {
+    this.index = index;
+  }
+
+  public String getDesc() {
+    return desc;
+  }
+
+  public void setDesc(String desc) {
+    this.desc = desc;
+  }
+
+  @Override
+  public String toString() {
+    return "index=" + index + ";name=" + name + ";age=" + age;
+  }
+}
diff --git 
a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxRSDefaultValues.java
 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxRSDefaultValues.java
index aa8f461dc..5a2788e64 100644
--- 
a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxRSDefaultValues.java
+++ 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxRSDefaultValues.java
@@ -118,4 +118,26 @@ public String jaxRsJavaPrimitiveStr(@FormParam("b") int b, 
@FormParam("a") Strin
   public String jaxRsJavaPrimitiveCombnation(@QueryParam("a") Integer a, 
@QueryParam("b") Float b) {
     return "Hello " + a + b;
   }
+
+  @Path("/allprimitivetypes")
+  @POST
+  public String allprimitivetypes(@QueryParam("pBoolean") boolean pBoolean,
+      @QueryParam("pChar") char pChar,
+      @QueryParam("pByte") byte pByte,
+      @QueryParam("pShort") short pShort,
+      @QueryParam("pInt") int pInt,
+      @QueryParam("pLong") long pLong,
+      @QueryParam("pFloat") float pFloat,
+      @QueryParam("pDouble") double pDouble,
+      @QueryParam("pDoubleWrap") Double pDoubleWrap) {
+    return "Hello " + pBoolean + ","
+        + pChar + ","
+        + pByte + ","
+        + pShort + ","
+        + pInt + ","
+        + pLong + ","
+        + pFloat + ","
+        + pDouble + ","
+        + pDoubleWrap;
+  }
 }
diff --git 
a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsServer.java
 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsServer.java
index bf5eba5fd..3b2d952a3 100644
--- 
a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsServer.java
+++ 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/JaxrsServer.java
@@ -19,13 +19,16 @@
 
 import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
 import org.apache.servicecomb.demo.RestObjectMapperWithStringMapper;
+import 
org.apache.servicecomb.demo.RestObjectMapperWithStringMapperNotWriteNull;
 import org.apache.servicecomb.foundation.common.utils.BeanUtils;
 import org.apache.servicecomb.foundation.common.utils.Log4jUtils;
 
 public class JaxrsServer {
   public static void main(String[] args) throws Exception {
+    RestObjectMapperFactory.setDefaultRestObjectMapper(new 
RestObjectMapperWithStringMapper());
+    RestObjectMapperFactory.setConsumerWriterMapper(new 
RestObjectMapperWithStringMapperNotWriteNull());
+
     Log4jUtils.init();
     BeanUtils.init();
-    RestObjectMapperFactory.setDefaultRestObjectMapper(new 
RestObjectMapperWithStringMapper());
   }
 }
diff --git 
a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultModelService.java
 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultModelService.java
new file mode 100644
index 000000000..7296a0970
--- /dev/null
+++ 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultModelService.java
@@ -0,0 +1,38 @@
+/*
+ * 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.jaxrs.server.pojoDefault;
+
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+
+@RestSchema(schemaId = "DefaultModelService")
+@Path("DefaultModelService")
+public class DefaultModelService {
+  @Path("/model")
+  @POST
+  public DefaultResponseModel errorCode(DefaultRequestModel request) {
+    DefaultResponseModel model = new DefaultResponseModel();
+    model.setIndex(request.getIndex());
+    model.setAge(request.getAge());
+    model.setName(request.getName());
+    model.setDesc(null);
+    return model;
+  }
+}
diff --git 
a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultRequestModel.java
 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultRequestModel.java
new file mode 100644
index 000000000..0cc535703
--- /dev/null
+++ 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultRequestModel.java
@@ -0,0 +1,76 @@
+/*
+ * 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.jaxrs.server.pojoDefault;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.Null;
+
+public class DefaultRequestModel {
+  @Min(20)
+  @Max(2000)
+  @Null
+  private Integer age = 200;
+
+  @Min(2)
+  @Max(30)
+  @Null
+  private String name = "World";
+
+  private int index;
+
+  private String desc;
+
+  public Integer getAge() {
+    return age;
+  }
+
+  public void setAge(Integer age) {
+    this.age = age;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+
+  public int getIndex() {
+    return index;
+  }
+
+  public void setIndex(int index) {
+    this.index = index;
+  }
+
+  public String getDesc() {
+    return desc;
+  }
+
+  public void setDesc(String desc) {
+    this.desc = desc;
+  }
+
+  @Override
+  public String toString() {
+    return "index=" + index + ";name=" + name + ";age=" + age;
+  }
+}
diff --git 
a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java
 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java
new file mode 100644
index 000000000..bf4288a28
--- /dev/null
+++ 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/pojoDefault/DefaultResponseModel.java
@@ -0,0 +1,76 @@
+/*
+ * 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.jaxrs.server.pojoDefault;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.Null;
+
+public class DefaultResponseModel {
+  @Min(20)
+  @Max(2000)
+  @Null
+  private Integer age = 200;
+
+  @Min(2)
+  @Max(30)
+  @Null
+  private String name = "World";
+
+  private int index;
+
+  private String desc;
+
+  public Integer getAge() {
+    return age;
+  }
+
+  public void setAge(Integer age) {
+    this.age = age;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+
+  public int getIndex() {
+    return index;
+  }
+
+  public void setIndex(int index) {
+    this.index = index;
+  }
+
+  public String getDesc() {
+    return desc;
+  }
+
+  public void setDesc(String desc) {
+    this.desc = desc;
+  }
+
+  @Override
+  public String toString() {
+    return "index=" + index + ";name=" + name + ";age=" + age;
+  }
+}
diff --git 
a/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationService.java
 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationService.java
new file mode 100644
index 000000000..732466957
--- /dev/null
+++ 
b/demo/demo-jaxrs/jaxrs-server/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationService.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.demo.jaxrs.server.validation;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.QueryParam;
+
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+
+@RestSchema(schemaId = "ValidationService")
+@Path("ValidationService")
+public class ValidationService {
+  @Path("/validate")
+  @POST
+  public ValidationModel errorCode(@Valid ValidationModel request) {
+    return request;
+  }
+
+  @Path("/validateQuery")
+  @GET
+  public String queryValidate(@NotNull @QueryParam("name") String name) {
+    return name;
+  }
+}
diff --git 
a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/RestObjectMapperWithStringMapperNotWriteNull.java
 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/RestObjectMapperWithStringMapperNotWriteNull.java
new file mode 100644
index 000000000..9eacb22bb
--- /dev/null
+++ 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/RestObjectMapperWithStringMapperNotWriteNull.java
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+/**
+ *  Demonstrate how to using String as raw type when using RestTemplate to 
invoke a service that use POJO. e.g.
+ *  <p/>
+ *  Provider: <p/>
+ *  <code>
+ *    public Response errorCodeWithHeader(MultiRequest request)
+ *  </code>
+ *   <p/>
+ *  Consumer: <p/>
+ *  <code>
+ *    String stringRequest = "{\"key\":\"testValue\"}";
+ *    template.postForEntity(url, stringRequest, MultiResponse200.class);
+ *  </code>
+ * <p/>
+ *  <b>Caution:</b> json will convert String to object based on String 
constructor, using this feature will make default
+ *  conversion change. You must write  convertValue to check possible types 
using.
+ */
+public class RestObjectMapperWithStringMapperNotWriteNull extends 
RestObjectMapperWithStringMapper {
+  private static final long serialVersionUID = 4279371572149490560L;
+
+  private static Logger LOGGER = 
LoggerFactory.getLogger(RestObjectMapperWithStringMapper.class);
+
+  public RestObjectMapperWithStringMapperNotWriteNull() {
+    super();
+    setSerializationInclusion(Include.NON_NULL);
+  }
+}
diff --git 
a/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationModel.java
 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationModel.java
new file mode 100644
index 000000000..09e26129b
--- /dev/null
+++ 
b/demo/demo-schema/src/main/java/org/apache/servicecomb/demo/jaxrs/server/validation/ValidationModel.java
@@ -0,0 +1,57 @@
+/*
+ * 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.jaxrs.server.validation;
+
+import java.util.List;
+
+import javax.validation.constraints.NotNull;
+
+public class ValidationModel {
+  @NotNull
+  private Integer age;
+
+  @NotNull
+  private List<String> members;
+
+  @NotNull
+  private String name;
+
+  public Integer getAge() {
+    return age;
+  }
+
+  public void setAge(Integer age) {
+    this.age = age;
+  }
+
+  public List<String> getMembers() {
+    return members;
+  }
+
+  public void setMembers(List<String> members) {
+    this.members = members;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+}
diff --git 
a/demo/demo-schema/src/main/resources/microservices/jaxrs/compute.yaml 
b/demo/demo-schema/src/main/resources/microservices/jaxrs/compute.yaml
index fcca77c24..66eb476c5 100644
--- a/demo/demo-schema/src/main/resources/microservices/jaxrs/compute.yaml
+++ b/demo/demo-schema/src/main/resources/microservices/jaxrs/compute.yaml
@@ -197,3 +197,4 @@ definitions:
     properties:
       name:
         type: string
+    x-java-class: "org.apache.servicecomb.demo.compute.Person"
diff --git a/demo/demo-schema/src/main/resources/microservices/pojo/server.yaml 
b/demo/demo-schema/src/main/resources/microservices/pojo/server.yaml
index d7c6a0a65..985fcb71e 100644
--- a/demo/demo-schema/src/main/resources/microservices/pojo/server.yaml
+++ b/demo/demo-schema/src/main/resources/microservices/pojo/server.yaml
@@ -215,3 +215,4 @@ definitions:
         type: integer
       index:
         type: number
+    x-java-class: "org.apache.servicecomb.demo.server.User"
diff --git 
a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/java/org/apache/servicecomb/springboot/jaxrs/client/JaxrsClient.java
 
b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/java/org/apache/servicecomb/springboot/jaxrs/client/JaxrsClient.java
index 2bd333013..3e1ea7822 100644
--- 
a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/java/org/apache/servicecomb/springboot/jaxrs/client/JaxrsClient.java
+++ 
b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-client/src/main/java/org/apache/servicecomb/springboot/jaxrs/client/JaxrsClient.java
@@ -19,6 +19,7 @@
 
 import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
 import org.apache.servicecomb.demo.RestObjectMapperWithStringMapper;
+import 
org.apache.servicecomb.demo.RestObjectMapperWithStringMapperNotWriteNull;
 import org.apache.servicecomb.demo.TestMgr;
 import org.apache.servicecomb.foundation.common.utils.Log4jUtils;
 import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
@@ -30,10 +31,10 @@
 public class JaxrsClient {
 
   public static void main(String[] args) throws Exception {
+    RestObjectMapperFactory.setDefaultRestObjectMapper(new 
RestObjectMapperWithStringMapper());
+    RestObjectMapperFactory.setConsumerWriterMapper(new 
RestObjectMapperWithStringMapperNotWriteNull());
     Log4jUtils.init();
     SpringApplication.run(JaxrsClient.class, args);
-
-    RestObjectMapperFactory.setDefaultRestObjectMapper(new 
RestObjectMapperWithStringMapper());
     org.apache.servicecomb.demo.jaxrs.client.JaxrsClient.run();
     TestMgr.summary();
   }
diff --git 
a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/java/org/apache/servicecomb/springboot/jaxrs/server/JaxrsServer.java
 
b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/java/org/apache/servicecomb/springboot/jaxrs/server/JaxrsServer.java
index 5b4add3f3..fc133f62e 100644
--- 
a/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/java/org/apache/servicecomb/springboot/jaxrs/server/JaxrsServer.java
+++ 
b/demo/demo-spring-boot-provider/demo-spring-boot-jaxrs-server/src/main/java/org/apache/servicecomb/springboot/jaxrs/server/JaxrsServer.java
@@ -19,6 +19,7 @@
 
 import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
 import org.apache.servicecomb.demo.RestObjectMapperWithStringMapper;
+import 
org.apache.servicecomb.demo.RestObjectMapperWithStringMapperNotWriteNull;
 import org.apache.servicecomb.foundation.common.utils.Log4jUtils;
 import org.apache.servicecomb.springboot.starter.provider.EnableServiceComb;
 import org.springframework.boot.SpringApplication;
@@ -28,8 +29,9 @@
 @EnableServiceComb
 public class JaxrsServer {
   public static void main(final String[] args) throws Exception {
+    RestObjectMapperFactory.setDefaultRestObjectMapper(new 
RestObjectMapperWithStringMapper());
+    RestObjectMapperFactory.setConsumerWriterMapper(new 
RestObjectMapperWithStringMapperNotWriteNull());
     Log4jUtils.init();
     SpringApplication.run(JaxrsServer.class, args);
-    RestObjectMapperFactory.setDefaultRestObjectMapper(new 
RestObjectMapperWithStringMapper());
   }
 }
diff --git 
a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/server.yaml
 
b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/server.yaml
index 903bf15c9..3fa0fdab0 100644
--- 
a/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/server.yaml
+++ 
b/demo/demo-spring-boot-transport/demo-spring-boot-pojo-server/src/main/resources/microservices/pojo/server.yaml
@@ -194,3 +194,4 @@ definitions:
         type: number
       index:
         type: number
+    x-java-class: "org.apache.servicecomb.demo.server.User"
\ No newline at end of file
diff --git 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
index a555fc9b5..37aa87054 100644
--- 
a/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
+++ 
b/demo/demo-springmvc/springmvc-client/src/main/java/org/apache/servicecomb/demo/springmvc/client/SpringmvcClient.java
@@ -325,6 +325,9 @@ private static void testSpringMvcDefaultValues(RestTemplate 
template, String mic
     result = template.getForObject(cseUrlPrefix + "/query3?a=30&b=2", 
String.class);
     TestMgr.check("Hello 302", result);
 
+    result = template.getForObject(cseUrlPrefix + "/query3?a=30", 
String.class);
+    TestMgr.check("Hello 30null", result);
+
     //input values
     headers = new HttpHeaders();
     headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
@@ -360,6 +363,9 @@ private static void 
testSpringMvcDefaultValuesJavaPrimitive(RestTemplate templat
     TestMgr.check("Hello", result);
 
     result = template.postForObject(cseUrlPrefix + "/javaprimitivecomb", null, 
String.class);
-    TestMgr.check("Hello 00.0", result);
+    TestMgr.check("Hello nullnull", result);
+
+    result = template.postForObject(cseUrlPrefix + "/allprimitivetypes", null, 
String.class);
+    TestMgr.check("Hello false,0,0,0,0,0,0.0,0.0,null", result);
   }
 }
diff --git 
a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringMvcDefaultValues.java
 
b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringMvcDefaultValues.java
index 1c99505ae..d6b33ebe4 100644
--- 
a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringMvcDefaultValues.java
+++ 
b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/SpringMvcDefaultValues.java
@@ -52,7 +52,8 @@ public String query(@RequestParam(name = "a", defaultValue = 
"20") int a,
   }
 
   @GetMapping("/query2")
-  public String query2(@RequestParam(name = "e", required = false) int e, 
@RequestParam(name = "a", defaultValue = "20") int a,
+  public String query2(@RequestParam(name = "e", required = false) int e,
+      @RequestParam(name = "a", defaultValue = "20") int a,
       @RequestParam(name = "b", defaultValue = "bobo") String b,
       @RequestParam(name = "c", defaultValue = "40") Integer c,
       @Min(value = 20) @Max(value = 30) @RequestParam(name = "d", required = 
false) int d) {
@@ -71,21 +72,44 @@ public String springJavaPrimitiveInt(@RequestParam(name = 
"a", required = false)
   }
 
   @PostMapping("/javaprimitivenumber")
-  public String springJavaPrimitiveNumber(@RequestParam(name = "a", required = 
false) float a, @RequestParam(name = "b", required = false) boolean b) {
+  public String springJavaPrimitiveNumber(@RequestParam(name = "a", required = 
false) float a,
+      @RequestParam(name = "b", required = false) boolean b) {
     return "Hello " + a + b;
   }
 
   @PostMapping("/javaprimitivestr")
-  public String springJavaPrimitiveStr(@RequestParam(name = "a", required = 
false) int a, @RequestParam(name = "b", required = false) String b) {
+  public String springJavaPrimitiveStr(@RequestParam(name = "a", required = 
false) int a,
+      @RequestParam(name = "b", required = false) String b) {
     if (b == null || b.equals("")) {
       return "Hello";
     }
     return "Hello " + b + a;
-
   }
 
   @PostMapping("/javaprimitivecomb")
-  public String springJavaPrimitiveCombination(@RequestParam(name = "a", 
required = false) Integer a, @RequestParam(name = "b", required = false) Float 
b) {
+  public String springJavaPrimitiveCombination(@RequestParam(name = "a", 
required = false) Integer a,
+      @RequestParam(name = "b", required = false) Float b) {
     return "Hello " + a + b;
   }
+
+  @PostMapping("/allprimitivetypes")
+  public String allprimitivetypes(@RequestParam(name = "pBoolean", required = 
false) boolean pBoolean,
+      @RequestParam(name = "pChar", required = false) char pChar,
+      @RequestParam(name = "pByte", required = false) byte pByte,
+      @RequestParam(name = "pShort", required = false) short pShort,
+      @RequestParam(name = "pInt", required = false) int pInt,
+      @RequestParam(name = "pLong", required = false) long pLong,
+      @RequestParam(name = "pFloat", required = false) float pFloat,
+      @RequestParam(name = "pDouble", required = false) double pDouble,
+      @RequestParam(name = "pDoubleWrap", required = false) Double 
pDoubleWrap) {
+    return "Hello " + pBoolean + ","
+        + pChar + ","
+        + pByte + ","
+        + pShort + ","
+        + pInt + ","
+        + pLong + ","
+        + pFloat + ","
+        + pDouble + ","
+        + pDoubleWrap;
+  }
 }
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 8698585c7..376a1b316 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
@@ -277,13 +277,13 @@ protected void scanMethodParameters() {
     Type[] parameterTypes = providerMethod.getGenericParameterTypes();
     for (int paramIdx = 0; paramIdx < parameterTypes.length; paramIdx++) {
       int swaggerParamCount = providerParameters.size();
+      Type type = parameterTypes[paramIdx];
 
       // 根据annotation处理
       Annotation[] paramAnnotations = allAnnotations[paramIdx];
-      processByParameterAnnotation(paramAnnotations, paramIdx);
+      processByParameterAnnotation(paramAnnotations, paramIdx, type);
 
       if (isArgumentNotProcessed(swaggerParamCount)) {
-        Type type = parameterTypes[paramIdx];
         // 是否需要根据参数类型处理,目标场景:httpRequest之类
         processByParameterType(type, paramIdx);
       }
@@ -299,7 +299,8 @@ private boolean isArgumentNotProcessed(int 
swaggerParamCount) {
     return swaggerParamCount == providerParameters.size();
   }
 
-  protected void processByParameterAnnotation(Annotation[] paramAnnotations, 
int paramIdx) {
+  @SuppressWarnings({"rawtypes", "unckecked"})
+  protected void processByParameterAnnotation(Annotation[] paramAnnotations, 
int paramIdx, Type parameterType) {
     String defaultValue = null;
     Parameter parameter = null;
     for (Annotation annotation : paramAnnotations) {
@@ -319,23 +320,16 @@ protected void processByParameterAnnotation(Annotation[] 
paramAnnotations, int p
       if (defaultValue != null) {
         ((AbstractSerializableParameter<?>) 
parameter).setDefaultValue(defaultValue);
       } else if ((((AbstractSerializableParameter<?>) 
parameter).getDefaultValue() == null)
-          && (!((AbstractSerializableParameter<?>) parameter).getRequired())) 
{ //if required false then only take java primitive values as defaults
-        String type = ((AbstractSerializableParameter<?>) parameter).getType();
-        switch (type) {
-          case "integer":
-            defaultValue = "0";
-            break;
-          case "number":
-            defaultValue = "0.0";
-            break;
-          case "string":
-            defaultValue = "";
-            break;
-          case "boolean":
-            defaultValue = "false";
-            break;
-          default:
-            defaultValue = null;
+          && (!((AbstractSerializableParameter<?>) parameter)
+          .getRequired())) { //if required false then only take java primitive 
values as defaults
+        if (parameterType instanceof Class && ((Class) 
parameterType).isPrimitive()) {
+          switch (parameterType.getTypeName()) {
+            case "boolean":
+              defaultValue = "false";
+              break;
+            default:
+              defaultValue = "0";
+          }
         }
         ((AbstractSerializableParameter<?>) 
parameter).setDefaultValue(defaultValue);
       }
diff --git 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMetaMapper.java
 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMetaMapper.java
new file mode 100644
index 000000000..e3577114f
--- /dev/null
+++ 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponseMetaMapper.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.swagger.invocation.response;
+
+import java.util.Map;
+
+public interface ResponseMetaMapper {
+  default int getOrder() {
+    return 0;
+  }
+
+  Map<Integer, ResponseMeta> getMapper();
+}
diff --git 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java
 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java
index 09b96dab5..5c5337569 100644
--- 
a/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java
+++ 
b/swagger/swagger-invocation/invocation-core/src/main/java/org/apache/servicecomb/swagger/invocation/response/ResponsesMeta.java
@@ -23,9 +23,11 @@
 
 import javax.ws.rs.core.Response.Status;
 
+import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils;
 import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator;
 import org.apache.servicecomb.swagger.invocation.context.HttpStatus;
 import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
+import org.apache.servicecomb.swagger.invocation.exception.ExceptionFactory;
 
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.type.SimpleType;
@@ -35,7 +37,12 @@
 import io.swagger.models.Response;
 
 public class ResponsesMeta {
-  private static final JavaType COMMON_EXCEPTION_JAVATYPE = 
SimpleType.constructUnsafe(CommonExceptionData.class);
+  private static final JavaType COMMON_EXCEPTION_JAVA_TYPE = 
SimpleType.constructUnsafe(CommonExceptionData.class);
+
+  private static final JavaType OBJECT_JAVA_TYPE = 
SimpleType.constructUnsafe(Object.class);
+
+  private static final ResponseMetaMapper GLOBAL_DEFAULT_MAPPER = 
SPIServiceUtils
+      .getPriorityHighestService(ResponseMetaMapper.class);
 
   private Map<Integer, ResponseMeta> responseMap = new HashMap<>();
 
@@ -46,6 +53,8 @@
   // 如果不传return类型进来,完全以swagger为标准,会导致生成的class不等于return
   public void init(SwaggerToClassGenerator swaggerToClassGenerator, Operation 
operation, Type returnType) {
     initSuccessResponse(returnType);
+    initInternalErrorResponse();
+    initGlobalDefaultMapper();
 
     for (Entry<String, Response> entry : operation.getResponses().entrySet()) {
       if ("default".equals(entry.getKey())) {
@@ -55,14 +64,15 @@ public void init(SwaggerToClassGenerator 
swaggerToClassGenerator, Operation oper
       }
 
       Integer statusCode = Integer.parseInt(entry.getKey());
-      ResponseMeta responseMeta = responseMap.computeIfAbsent(statusCode, k -> 
new ResponseMeta());
-      responseMeta.init(swaggerToClassGenerator, entry.getValue());
+      ResponseMeta codeMeta = new ResponseMeta();
+      codeMeta.init(swaggerToClassGenerator, entry.getValue());
+      ResponseMeta responseMeta = responseMap.put(statusCode, codeMeta);
     }
 
     if (defaultResponse == null) {
       // swagger中没有定义default,加上default专用于处理exception
       ResponseMeta responseMeta = new ResponseMeta();
-      responseMeta.setJavaType(COMMON_EXCEPTION_JAVATYPE);
+      responseMeta.setJavaType(OBJECT_JAVA_TYPE);
 
       defaultResponse = responseMeta;
     }
@@ -74,6 +84,22 @@ protected void initSuccessResponse(Type returnType) {
     responseMap.put(Status.OK.getStatusCode(), successResponse);
   }
 
+  protected void initInternalErrorResponse() {
+    ResponseMeta internalErrorResponse = new ResponseMeta();
+    internalErrorResponse.setJavaType(COMMON_EXCEPTION_JAVA_TYPE);
+    responseMap.put(ExceptionFactory.CONSUMER_INNER_STATUS_CODE, 
internalErrorResponse);
+    responseMap.put(ExceptionFactory.PRODUCER_INNER_STATUS_CODE, 
internalErrorResponse);
+  }
+
+  protected void initGlobalDefaultMapper() {
+    if (GLOBAL_DEFAULT_MAPPER != null) {
+      Map<Integer, ResponseMeta> mappers = GLOBAL_DEFAULT_MAPPER.getMapper();
+      if (mappers != null) {
+        responseMap.putAll(mappers);
+      }
+    }
+  }
+
   public ResponseMeta findResponseMeta(int statusCode) {
     ResponseMeta responseMeta = responseMap.get(statusCode);
     if (responseMeta == null) {
diff --git 
a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java
 
b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java
index 6b03522cd..695504094 100644
--- 
a/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java
+++ 
b/swagger/swagger-invocation/invocation-core/src/test/java/org/apache/servicecomb/swagger/invocation/response/TestResponsesMeta.java
@@ -19,7 +19,6 @@
 import org.apache.servicecomb.swagger.converter.SwaggerToClassGenerator;
 import org.apache.servicecomb.swagger.generator.core.SwaggerGenerator;
 import 
org.apache.servicecomb.swagger.generator.core.unittest.UnitTestSwaggerUtils;
-import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -55,10 +54,13 @@ public void test() {
     meta.init(swaggerToClassGenerator, operation, int.class);
 
     ResponseMeta resp = meta.findResponseMeta(200);
-    Assert.assertEquals(int.class, resp.getJavaType().getRawClass());
+    // Response is based on swagger type and is Integer type.
+    Assert.assertEquals(Integer.class, resp.getJavaType().getRawClass());
 
     resp = meta.findResponseMeta(201);
-    Assert.assertEquals(int.class, resp.getJavaType().getRawClass());
+    // Response is based on swagger type and is Integer type. For this test 
case there is one problem need to discuss.
+    // If SUCCESS family, do we should use OK response type?
+    Assert.assertEquals(Integer.class, resp.getJavaType().getRawClass());
 
     resp = meta.findResponseMeta(400);
     Assert.assertEquals(String.class, resp.getJavaType().getRawClass());
@@ -68,6 +70,7 @@ public void test() {
     Assert.assertEquals(Integer.class, 
resp.getHeaders().get("h1").getRawClass());
 
     resp = meta.findResponseMeta(500);
-    Assert.assertEquals(CommonExceptionData.class, 
resp.getJavaType().getRawClass());
+    // changed to Object for new version to keep user defined error data not 
lose and can be parsed.
+    Assert.assertEquals(Object.class, resp.getJavaType().getRawClass());
   }
 }
diff --git 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
index 7d540784a..60921c506 100644
--- 
a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
+++ 
b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/http/DefaultHttpClientFilter.java
@@ -23,13 +23,13 @@
 
 import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.common.rest.codec.produce.ProduceProcessor;
+import 
org.apache.servicecomb.common.rest.codec.produce.ProduceProcessorManager;
 import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
 import org.apache.servicecomb.common.rest.filter.HttpClientFilter;
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.definition.OperationMeta;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletRequestEx;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
-import org.apache.servicecomb.swagger.invocation.InvocationType;
 import org.apache.servicecomb.swagger.invocation.Response;
 import org.apache.servicecomb.swagger.invocation.response.ResponseMeta;
 import org.slf4j.Logger;
@@ -74,6 +74,8 @@ protected Response extractResponse(Invocation invocation, 
HttpServletResponseEx
     RestOperationMeta swaggerRestOperation = 
operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION);
     ProduceProcessor produceProcessor = 
findProduceProcessor(swaggerRestOperation, responseEx);
     if (produceProcessor == null) {
+      // This happens outside the runtime such as Servlet filter response. 
Here we give a default json parser to it
+      // and keep user data not get lose.
       String msg =
           String.format("method %s, path %s, statusCode %d, reasonPhrase %s, 
response content-type %s is not supported",
               swaggerRestOperation.getHttpMethod(),
@@ -81,8 +83,8 @@ protected Response extractResponse(Invocation invocation, 
HttpServletResponseEx
               responseEx.getStatus(),
               responseEx.getStatusType().getReasonPhrase(),
               responseEx.getHeader(HttpHeaders.CONTENT_TYPE));
-      LOGGER.error(msg);
-      return Response.createFail(InvocationType.CONSUMER, msg);
+      LOGGER.warn(msg);
+      produceProcessor = ProduceProcessorManager.DEFAULT_PROCESSOR;
     }
 
     try {
diff --git 
a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestDefaultHttpClientFilter.java
 
b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestDefaultHttpClientFilter.java
index 3279ab393..d14bc1da4 100644
--- 
a/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestDefaultHttpClientFilter.java
+++ 
b/transports/transport-rest/transport-rest-client/src/test/java/org/apache/servicecomb/transport/rest/client/http/TestDefaultHttpClientFilter.java
@@ -31,6 +31,7 @@
 import org.apache.servicecomb.common.rest.definition.RestOperationMeta;
 import org.apache.servicecomb.core.Invocation;
 import org.apache.servicecomb.core.definition.OperationMeta;
+import org.apache.servicecomb.foundation.common.utils.JsonUtils;
 import org.apache.servicecomb.foundation.vertx.http.HttpServletResponseEx;
 import org.apache.servicecomb.foundation.vertx.http.ReadStreamPart;
 import org.apache.servicecomb.swagger.invocation.Response;
@@ -48,6 +49,7 @@
 import io.vertx.core.buffer.impl.BufferImpl;
 import io.vertx.core.http.CaseInsensitiveHeaders;
 import mockit.Expectations;
+import mockit.Injectable;
 import mockit.Mock;
 import mockit.MockUp;
 import mockit.Mocked;
@@ -172,29 +174,38 @@ ProduceProcessor findProduceProcessor(RestOperationMeta 
restOperation, HttpServl
   public void testAfterReceiveResponseNullProduceProcessor(@Mocked Invocation 
invocation,
       @Mocked HttpServletResponseEx responseEx,
       @Mocked OperationMeta operationMeta,
-      @Mocked RestOperationMeta swaggerRestOperation) {
+      @Mocked RestOperationMeta swaggerRestOperation,
+      @Injectable ResponseMeta responseMeta) throws Exception {
+    CommonExceptionData data = new CommonExceptionData("abcd");
     new Expectations() {
       {
         invocation.getOperationMeta();
         result = operationMeta;
         operationMeta.getExtData(RestConst.SWAGGER_REST_OPERATION);
         result = swaggerRestOperation;
+        operationMeta.findResponseMeta(403);
+        result = responseMeta;
+        responseMeta.getJavaType();
+        result = SimpleType.constructUnsafe(CommonExceptionData.class);
         responseEx.getStatus();
-        result = 200;
+        result = 403;
+        responseEx.getStatusType();
+        result = Status.FORBIDDEN;
+        responseEx.getBodyBuffer();
+        result = Buffer.buffer(JsonUtils.writeValueAsString(data).getBytes());
       }
     };
 
     Response response = filter.afterReceiveResponse(invocation, responseEx);
-    Assert.assertEquals(490, response.getStatusCode());
-    Assert.assertEquals(ExceptionFactory.CONSUMER_INNER_REASON_PHRASE, 
response.getReasonPhrase());
+    Assert.assertEquals(403, response.getStatusCode());
+    Assert.assertEquals("Forbidden", response.getReasonPhrase());
     Assert.assertEquals(InvocationException.class, 
response.<InvocationException>getResult().getClass());
     InvocationException invocationException = response.getResult();
     Assert.assertEquals(
-        490,
+        403,
         invocationException.getStatusCode());
     Assert.assertEquals(
-        "CommonExceptionData [message=method null, path null, statusCode 200, 
reasonPhrase null, "
-            + "response content-type null is not supported]",
+        "CommonExceptionData [message=abcd]",
         invocationException.getErrorData().toString());
   }
 


 

----------------------------------------------------------------
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:
[email protected]


> Provide a way to decode user's custom error data
> ------------------------------------------------
>
>                 Key: SCB-847
>                 URL: https://issues.apache.org/jira/browse/SCB-847
>             Project: Apache ServiceComb
>          Issue Type: New Feature
>          Components: Java-Chassis
>            Reporter: liubao
>            Assignee: liubao
>            Priority: Major
>
> Now ServiceComb can only decode two types of response:
>  # specified in service
>  # CommonExceptionData
> Users may need to return custom response error data. 



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to