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

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

commit ea5e6ae676fe810e52c767b8e5a964d7874b60f1
Author: weichao666 <[email protected]>
AuthorDate: Fri Nov 23 14:25:50 2018 +0800

    [SCB-925] Springmvc, when have defaultValue, required should be false,when 
param not exist,should check isRequired
---
 .../rest/codec/param/AbstractParamProcessor.java   |  9 +++-
 .../rest/codec/param/CookieProcessorCreator.java   | 38 +++++++++-----
 .../rest/codec/param/FormProcessorCreator.java     | 39 ++++++++++----
 .../rest/codec/param/HeaderProcessorCreator.java   | 38 ++++++++++----
 .../rest/codec/param/PathProcessorCreator.java     |  6 +--
 .../rest/codec/param/QueryProcessorCreator.java    | 28 +++++++---
 .../rest/codec/param/TestCookieProcessor.java      | 56 ++++++++++++++++++--
 .../common/rest/codec/param/TestFormProcessor.java | 33 ++++++++++--
 .../rest/codec/param/TestHeaderProcessor.java      | 50 ++++++++++++++++--
 .../common/rest/codec/param/TestPathProcessor.java |  2 +-
 .../rest/codec/param/TestQueryProcessor.java       | 40 ++++++++++++++-
 .../main/resources/microservices/pojo/server.yaml  |  2 +-
 .../springmvc/server/SpringMvcDefaultValues.java   |  2 +-
 .../servicecomb/it/testcase/TestDefaultValue.java  | 60 +++++++++++++++++-----
 .../tests/SpringMvcIntegrationTestBase.java        | 14 +++--
 .../parameter/AbstractParameterProcessor.java      |  5 +-
 .../annotation/CookieValueAnnotationProcessor.java |  6 +++
 .../RequestHeaderAnnotationProcessor.java          |  9 +++-
 .../RequestParamAnnotationProcessor.java           | 10 +++-
 19 files changed, 360 insertions(+), 87 deletions(-)

diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/AbstractParamProcessor.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/AbstractParamProcessor.java
index 509e03e..147aa0a 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/AbstractParamProcessor.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/AbstractParamProcessor.java
@@ -26,17 +26,24 @@ public abstract class AbstractParamProcessor implements 
ParamValueProcessor {
 
   protected Object defaultValue;
 
+  protected boolean required = false;
+
   public Object getDefaultValue() {
     return defaultValue;
   }
 
-  public AbstractParamProcessor(String paramPath, JavaType targetType, Object 
defaultValue) {
+  public AbstractParamProcessor(String paramPath, JavaType targetType, Object 
defaultValue, boolean required) {
     this.paramPath = paramPath;
     this.targetType = targetType;
     this.defaultValue = defaultValue;
+    this.required = required;
   }
 
   public String getParameterPath() {
     return paramPath;
   }
+
+  public boolean isRequired() {
+    return required;
+  }
 }
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 659637e..894a379 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
@@ -21,9 +21,12 @@ import java.lang.reflect.Type;
 
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Response.Status;
 
 import org.apache.servicecomb.common.rest.codec.RestClientRequest;
 import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+import org.springframework.util.ObjectUtils;
 
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.type.TypeFactory;
@@ -35,33 +38,41 @@ public class CookieProcessorCreator implements 
ParamValueProcessorCreator {
   public static final String PARAMTYPE = "cookie";
 
   public static class CookieProcessor extends AbstractParamProcessor {
-    public CookieProcessor(String paramPath, JavaType targetType, Object 
defaultValue) {
-      super(paramPath, targetType, defaultValue);
+    public CookieProcessor(String paramPath, JavaType targetType, Object 
defaultValue, boolean required) {
+      super(paramPath, targetType, defaultValue, required);
     }
 
     @Override
     public Object getValue(HttpServletRequest request) throws Exception {
       Cookie[] cookies = request.getCookies();
-      if (cookies == null) {
-        return null;
+      Object value = null;
+      if (cookies == null || cookies.length == 0) {
+        value = checkRequiredAndDefaultValue(value);
+        return convertValue(value, targetType);
       }
 
-      String value = null;
       for (Cookie cookie : cookies) {
         if (paramPath.equals(cookie.getName())) {
           value = cookie.getValue();
-          if (value == null) {
-            Object defaultValue = getDefaultValue();
-            if (defaultValue != null) {
-              value = defaultValue.toString();
-            }
-          }
         }
       }
-
+      if (value == null) {
+        value = checkRequiredAndDefaultValue(value);
+      }
       return convertValue(value, targetType);
     }
 
+    private Object checkRequiredAndDefaultValue(Object value) {
+      if (isRequired()) {
+        throw new InvocationException(Status.BAD_REQUEST, "Parameter is not 
valid, required is true");
+      }
+      Object defaultValue = getDefaultValue();
+      if (defaultValue != null) {
+        return defaultValue;
+      }
+      return value;
+    }
+
     @Override
     public void setValue(RestClientRequest clientRequest, Object arg) throws 
Exception {
       clientRequest.addCookie(paramPath,
@@ -81,6 +92,7 @@ public class CookieProcessorCreator implements 
ParamValueProcessorCreator {
   @Override
   public ParamValueProcessor create(Parameter parameter, Type 
genericParamType) {
     JavaType targetType = 
TypeFactory.defaultInstance().constructType(genericParamType);
-    return new CookieProcessor(parameter.getName(), targetType, 
((CookieParameter) parameter).getDefaultValue());
+    return new CookieProcessor(parameter.getName(), targetType, 
((CookieParameter) parameter).getDefaultValue(),
+        parameter.getRequired());
   }
 }
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java
index 81cf912..7e4f448 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/FormProcessorCreator.java
@@ -22,9 +22,11 @@ import java.util.Map;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.Part;
+import javax.ws.rs.core.Response.Status;
 
 import org.apache.servicecomb.common.rest.RestConst;
 import org.apache.servicecomb.common.rest.codec.RestClientRequest;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.type.TypeFactory;
@@ -37,8 +39,8 @@ public class FormProcessorCreator implements 
ParamValueProcessorCreator {
   public static final String PARAMTYPE = "formData";
 
   public static class FormProcessor extends AbstractParamProcessor {
-    public FormProcessor(String paramPath, JavaType targetType, Object 
defaultValue) {
-      super(paramPath, targetType, defaultValue);
+    public FormProcessor(String paramPath, JavaType targetType, Object 
defaultValue, boolean required) {
+      super(paramPath, targetType, defaultValue, required);
     }
 
     @Override
@@ -50,20 +52,33 @@ public class FormProcessorCreator implements 
ParamValueProcessorCreator {
       }
 
       if (targetType.isContainerType()) {
-        return convertValue(request.getParameterValues(paramPath), targetType);
+        Object values = request.getParameterValues(paramPath);
+        //Even if the paramPath does not exist, it won't be null at now, may 
be optimized in the future
+        if (values == null) {
+          values = checkRequiredAndDefaultValue(values);
+        }
+        return convertValue(values, targetType);
       }
 
       Object value = request.getParameter(paramPath);
       if (value == null) {
-        Object defaultValue = getDefaultValue();
-        if (defaultValue != null) {
-          value = defaultValue;
-        }
+        value = checkRequiredAndDefaultValue(value);
       }
 
       return convertValue(value, targetType);
     }
 
+    private Object checkRequiredAndDefaultValue(Object values) {
+      if (isRequired()) {
+        throw new InvocationException(Status.BAD_REQUEST, "Parameter is not 
valid, required is true");
+      }
+      Object defaultValue = getDefaultValue();
+      if (defaultValue != null) {
+        return defaultValue;
+      }
+      return values;
+    }
+
     @Override
     public void setValue(RestClientRequest clientRequest, Object arg) {
       clientRequest.addForm(paramPath, arg);
@@ -84,9 +99,11 @@ public class FormProcessorCreator implements 
ParamValueProcessorCreator {
     JavaType targetType = 
TypeFactory.defaultInstance().constructType(genericParamType);
 
     if (isPart(parameter)) {
-      return new PartProcessor(parameter.getName(), targetType, 
((FormParameter) parameter).getDefaultValue());
+      return new PartProcessor(parameter.getName(), targetType, 
((FormParameter) parameter).getDefaultValue(),
+          parameter.getRequired());
     }
-    return new FormProcessor(parameter.getName(), targetType, ((FormParameter) 
parameter).getDefaultValue());
+    return new FormProcessor(parameter.getName(), targetType, ((FormParameter) 
parameter).getDefaultValue(),
+        parameter.getRequired());
   }
 
   private boolean isPart(Parameter parameter) {
@@ -94,8 +111,8 @@ public class FormProcessorCreator implements 
ParamValueProcessorCreator {
   }
 
   private static class PartProcessor extends AbstractParamProcessor {
-    PartProcessor(String paramPath, JavaType targetType, Object defaultValue) {
-      super(paramPath, targetType, defaultValue);
+    PartProcessor(String paramPath, JavaType targetType, Object defaultValue, 
boolean required) {
+      super(paramPath, targetType, defaultValue, required);
     }
 
     @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 810e018..d946afd 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
@@ -22,9 +22,11 @@ import java.util.Collections;
 import java.util.Enumeration;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Response.Status;
 
 import org.apache.servicecomb.common.rest.codec.RestClientRequest;
 import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,33 +42,46 @@ public class HeaderProcessorCreator implements 
ParamValueProcessorCreator {
   public static final String PARAMTYPE = "header";
 
   public static class HeaderProcessor extends AbstractParamProcessor {
-    public HeaderProcessor(String paramPath, JavaType targetType, Object 
defaultValue) {
-      super(paramPath, targetType, defaultValue);
+    public HeaderProcessor(String paramPath, JavaType targetType, Object 
defaultValue, boolean required) {
+      super(paramPath, targetType, defaultValue, required);
     }
 
     @Override
     public Object getValue(HttpServletRequest request) throws Exception {
       Object value = null;
       if (targetType.isContainerType()) {
-        Enumeration<String> headerValues = request.getHeaders(paramPath);
+        Enumeration<?> headerValues = request.getHeaders(paramPath);
+        //Even if the paramPath does not exist, it won't be null at now, may 
be optimized in the future
         if (headerValues == null) {
-          return null;
+          Object obj = checkRequiredAndDefaultValue(headerValues);
+          if (obj instanceof Enumeration) {
+            headerValues = (Enumeration<?>) obj;
+          }
+        }
+        if (headerValues != null) {
+          value = Collections.list(headerValues);
         }
-
-        value = Collections.list(headerValues);
       } else {
         value = request.getHeader(paramPath);
         if (value == null) {
-          Object defaultValue = getDefaultValue();
-          if (defaultValue != null) {
-            value = defaultValue;
-          }
+          value = checkRequiredAndDefaultValue(value);
         }
       }
 
       return convertValue(value, targetType);
     }
 
+    private Object checkRequiredAndDefaultValue(Object headerValue) {
+      if (isRequired()) {
+        throw new InvocationException(Status.BAD_REQUEST, "Parameter is not 
valid, required is true");
+      }
+      Object defaultValue = getDefaultValue();
+      if (defaultValue != null) {
+        return defaultValue;
+      }
+      return headerValue;
+    }
+
     @Override
     public void setValue(RestClientRequest clientRequest, Object arg) throws 
Exception {
       if (null == arg) {
@@ -91,6 +106,7 @@ public class HeaderProcessorCreator implements 
ParamValueProcessorCreator {
   @Override
   public ParamValueProcessor create(Parameter parameter, Type 
genericParamType) {
     JavaType targetType = 
TypeFactory.defaultInstance().constructType(genericParamType);
-    return new HeaderProcessor(parameter.getName(), targetType, 
((HeaderParameter) parameter).getDefaultValue());
+    return new HeaderProcessor(parameter.getName(), targetType, 
((HeaderParameter) parameter).getDefaultValue(),
+        parameter.getRequired());
   }
 }
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java
index dbf459c..6f5f3fd 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/PathProcessorCreator.java
@@ -36,8 +36,8 @@ public class PathProcessorCreator implements 
ParamValueProcessorCreator {
   public static final String PARAMTYPE = "path";
 
   public static class PathProcessor extends AbstractParamProcessor {
-    public PathProcessor(String paramPath, JavaType targetType, Object 
defaultValue) {
-      super(paramPath, targetType, defaultValue);
+    public PathProcessor(String paramPath, JavaType targetType, Object 
defaultValue, boolean required) {
+      super(paramPath, targetType, defaultValue, required);
     }
 
     @Override
@@ -73,6 +73,6 @@ public class PathProcessorCreator implements 
ParamValueProcessorCreator {
   @Override
   public ParamValueProcessor create(Parameter parameter, Type 
genericParamType) {
     JavaType targetType = 
TypeFactory.defaultInstance().constructType(genericParamType);
-    return new PathProcessor(parameter.getName(), targetType, ((PathParameter) 
parameter).getDefaultValue());
+    return new PathProcessor(parameter.getName(), targetType, ((PathParameter) 
parameter).getDefaultValue(), true);
   }
 }
diff --git 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java
 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java
index 952c649..b449ae2 100644
--- 
a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java
+++ 
b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/QueryProcessorCreator.java
@@ -20,10 +20,12 @@ package org.apache.servicecomb.common.rest.codec.param;
 import java.lang.reflect.Type;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Response.Status;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.servicecomb.common.rest.codec.RestClientRequest;
 import 
org.apache.servicecomb.swagger.converter.property.SwaggerParamCollectionFormat;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 
 import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.type.TypeFactory;
@@ -46,8 +48,9 @@ public class QueryProcessorCreator implements 
ParamValueProcessorCreator {
 
     private SwaggerParamCollectionFormat collectionFormat;
 
-    public QueryProcessor(String paramPath, JavaType targetType, Object 
defaultValue, String collectionFormat) {
-      super(paramPath, targetType, defaultValue);
+    public QueryProcessor(String paramPath, JavaType targetType, Object 
defaultValue, boolean required,
+        String collectionFormat) {
+      super(paramPath, targetType, defaultValue, required);
       if (StringUtils.isNoneEmpty(collectionFormat)) {
         this.collectionFormat = 
SwaggerParamCollectionFormat.valueOf(collectionFormat.toUpperCase());
       }
@@ -59,6 +62,10 @@ public class QueryProcessorCreator implements 
ParamValueProcessorCreator {
       if (targetType.isContainerType()
           && SwaggerParamCollectionFormat.MULTI.equals(collectionFormat)) {
         value = request.getParameterValues(paramPath);
+        //Even if the paramPath does not exist, it won't be null at now, may 
be optimized in the future
+        if (value == null) {
+          value = checkRequiredAndDefaultValue(value);
+        }
       } else {
         value = request.getParameter(paramPath);
         // make some old systems happy
@@ -68,10 +75,7 @@ public class QueryProcessorCreator implements 
ParamValueProcessorCreator {
           }
         }
         if (value == null) {
-          Object defaultValue = getDefaultValue();
-          if (!ignoreDefaultValue && defaultValue != null) {
-            value = defaultValue;
-          }
+          value = checkRequiredAndDefaultValue(value);
         }
         if (null != collectionFormat) {
           value = collectionFormat.splitParam((String) value);
@@ -81,6 +85,17 @@ public class QueryProcessorCreator implements 
ParamValueProcessorCreator {
       return convertValue(value, targetType);
     }
 
+    private Object checkRequiredAndDefaultValue(Object value) {
+      if (isRequired()) {
+        throw new InvocationException(Status.BAD_REQUEST, "Parameter is not 
valid, required is true");
+      }
+      Object defaultValue = getDefaultValue();
+      if (!ignoreDefaultValue && defaultValue != null) {
+        return defaultValue;
+      }
+      return value;
+    }
+
     @Override
     public void setValue(RestClientRequest clientRequest, Object arg) throws 
Exception {
       // query不需要set
@@ -105,6 +120,7 @@ public class QueryProcessorCreator implements 
ParamValueProcessorCreator {
     QueryParameter queryParameter = (QueryParameter) parameter;
     JavaType targetType = 
TypeFactory.defaultInstance().constructType(genericParamType);
     return new QueryProcessor(parameter.getName(), targetType, 
queryParameter.getDefaultValue(),
+        parameter.getRequired(),
         queryParameter.getCollectionFormat());
   }
 }
diff --git 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessor.java
 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessor.java
index 3705434..4628b58 100644
--- 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessor.java
+++ 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestCookieProcessor.java
@@ -45,7 +45,11 @@ public class TestCookieProcessor {
   RestClientRequest clientRequest;
 
   private CookieProcessor createProcessor(String name, Class<?> type) {
-    return new CookieProcessor(name, 
TypeFactory.defaultInstance().constructType(type), null);
+    return new CookieProcessor(name, 
TypeFactory.defaultInstance().constructType(type), null, true);
+  }
+
+  private CookieProcessor createProcessor(String name, Class<?> type, String 
defaultValue, boolean required) {
+    return new CookieProcessor(name, 
TypeFactory.defaultInstance().constructType(type), defaultValue, required);
   }
 
   private void createClientRequest() {
@@ -67,8 +71,12 @@ public class TestCookieProcessor {
     };
 
     CookieProcessor processor = createProcessor("c1", String.class);
-    Object value = processor.getValue(request);
-    Assert.assertNull(value);
+    try {
+      processor.getValue(request);
+      Assert.assertEquals("required is true, throw exception", "not throw 
exception");
+    } catch (Exception e) {
+      Assert.assertTrue(e.getMessage().contains("Parameter is not valid, 
required is true"));
+    }
   }
 
   @Test
@@ -82,8 +90,12 @@ public class TestCookieProcessor {
     };
 
     CookieProcessor processor = createProcessor("c2", String.class);
-    Object value = processor.getValue(request);
-    Assert.assertNull(value);
+    try {
+      processor.getValue(request);
+      Assert.assertEquals("required is true, throw exception", "not throw 
exception");
+    } catch (Exception e) {
+      Assert.assertTrue(e.getMessage().contains("Parameter is not valid, 
required is true"));
+    }
   }
 
   @Test
@@ -101,6 +113,40 @@ public class TestCookieProcessor {
     Assert.assertEquals("c1v", value);
   }
 
+  @Test
+  public void testGetValueRequiredTrue() throws Exception {
+    Cookie[] cookies = new Cookie[] {new Cookie("c1", null)};
+    new Expectations() {
+      {
+        request.getCookies();
+        result = cookies;
+      }
+    };
+
+    CookieProcessor processor = createProcessor("c1", String.class);
+    try {
+      processor.getValue(request);
+      Assert.assertEquals("required is true, throw exception", "not throw 
exception");
+    } catch (Exception e) {
+      Assert.assertTrue(e.getMessage().contains("Parameter is not valid, 
required is true"));
+    }
+  }
+
+  @Test
+  public void testGetValueRequiredFalse() throws Exception {
+    Cookie[] cookies = new Cookie[] {new Cookie("c1", null)};
+    new Expectations() {
+      {
+        request.getCookies();
+        result = cookies;
+      }
+    };
+
+    CookieProcessor processor = createProcessor("c1", String.class, "test", 
false);
+    Object result = processor.getValue(request);
+    Assert.assertEquals("test", result);
+  }
+
   @SuppressWarnings("deprecation")
   @Test
   public void testGetValueCookiesDate() throws Exception {
diff --git 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessor.java
 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessor.java
index a756940..35f869d 100644
--- 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessor.java
+++ 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestFormProcessor.java
@@ -48,7 +48,7 @@ public class TestFormProcessor {
   RestClientRequest clientRequest;
 
   private FormProcessor createProcessor(String name, Class<?> type) {
-    return new FormProcessor(name, 
TypeFactory.defaultInstance().constructType(type), null);
+    return new FormProcessor(name, 
TypeFactory.defaultInstance().constructType(type), null, true);
   }
 
   private void createClientRequest() {
@@ -118,8 +118,30 @@ public class TestFormProcessor {
     };
 
     ParamValueProcessor processor = createProcessor("name", String[].class);
-    String[] value = (String[]) processor.getValue(request);
-    Assert.assertNull(value);
+    try {
+      processor.getValue(request);
+      Assert.assertEquals("required is true, throw exception", "not throw 
exception");
+    } catch (Exception e) {
+      Assert.assertTrue(e.getMessage().contains("Parameter is not valid, 
required is true"));
+    }
+  }
+
+  @Test
+  public void testGetValueNull() throws Exception {
+    new Expectations() {
+      {
+        request.getParameter("name");
+        result = null;
+      }
+    };
+
+    ParamValueProcessor processor = createProcessor("name", String.class);
+    try {
+      processor.getValue(request);
+      Assert.assertEquals("required is true, throw exception", "not throw 
exception");
+    } catch (Exception e) {
+      Assert.assertTrue(e.getMessage().contains("Parameter is not valid, 
required is true"));
+    }
   }
 
   @Test
@@ -148,7 +170,7 @@ public class TestFormProcessor {
 
     ParamValueProcessor processor =
         new FormProcessor("name", 
TypeFactory.defaultInstance().constructCollectionType(List.class, String.class),
-            null);
+            null, true);
     Object value = processor.getValue(request);
     Assert.assertThat((List<String>) value, Matchers.contains("value"));
   }
@@ -164,7 +186,8 @@ public class TestFormProcessor {
     };
 
     ParamValueProcessor processor =
-        new FormProcessor("name", 
TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class), 
null);
+        new FormProcessor("name", 
TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class), 
null,
+            true);
     Object value = processor.getValue(request);
     Assert.assertThat((Set<String>) value, Matchers.contains("value"));
   }
diff --git 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java
 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java
index 667e53b..70b605b 100644
--- 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java
+++ 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestHeaderProcessor.java
@@ -49,7 +49,11 @@ public class TestHeaderProcessor {
   RestClientRequest clientRequest;
 
   private HeaderProcessor createProcessor(String name, Class<?> type) {
-    return new HeaderProcessor(name, 
TypeFactory.defaultInstance().constructType(type), null);
+    return new HeaderProcessor(name, 
TypeFactory.defaultInstance().constructType(type), null, true);
+  }
+
+  private HeaderProcessor createProcessor(String name, Class<?> type, String 
defaultValue, boolean required) {
+    return new HeaderProcessor(name, 
TypeFactory.defaultInstance().constructType(type), defaultValue, required);
   }
 
   private void createClientRequest() {
@@ -103,8 +107,44 @@ public class TestHeaderProcessor {
     };
 
     HeaderProcessor processor = createProcessor("h1", String[].class);
-    String[] value = (String[]) processor.getValue(request);
-    Assert.assertNull(value);
+    try {
+      processor.getValue(request);
+      Assert.assertEquals("required is true, throw exception", "not throw 
exception");
+    } catch (Exception e) {
+      Assert.assertTrue(e.getMessage().contains("Parameter is not valid, 
required is true"));
+    }
+  }
+
+  @Test
+  public void testGetValueRequiredTrue() throws Exception {
+    new Expectations() {
+      {
+        request.getHeader("h1");
+        result = null;
+      }
+    };
+
+    HeaderProcessor processor = createProcessor("h1", String.class);
+    try {
+      processor.getValue(request);
+      Assert.assertEquals("required is true, throw exception", "not throw 
exception");
+    } catch (Exception e) {
+      Assert.assertTrue(e.getMessage().contains("Parameter is not valid, 
required is true"));
+    }
+  }
+
+  @Test
+  public void testGetValueRequiredFalse() throws Exception {
+    new Expectations() {
+      {
+        request.getHeader("h1");
+        result = null;
+      }
+    };
+
+    HeaderProcessor processor = createProcessor("h1", String.class, "test", 
false);
+    Object value = processor.getValue(request);
+    Assert.assertEquals("test", value);
   }
 
   @Test
@@ -133,7 +173,7 @@ public class TestHeaderProcessor {
 
     HeaderProcessor processor =
         new HeaderProcessor("h1", 
TypeFactory.defaultInstance().constructCollectionType(List.class, String.class),
-            null);
+            null, true);
     Object value = processor.getValue(request);
     Assert.assertThat((List<String>) value, Matchers.contains("h1v"));
   }
@@ -149,7 +189,7 @@ public class TestHeaderProcessor {
     };
 
     HeaderProcessor processor =
-        new HeaderProcessor("h1", 
TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class), 
null);
+        new HeaderProcessor("h1", 
TypeFactory.defaultInstance().constructCollectionType(Set.class, String.class), 
null, true);
     Object value = processor.getValue(request);
     Assert.assertThat((Set<String>) value, Matchers.contains("h1v"));
   }
diff --git 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessor.java
 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessor.java
index 19cd51f..19cca94 100644
--- 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessor.java
+++ 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestPathProcessor.java
@@ -41,7 +41,7 @@ public class TestPathProcessor {
   ParamValueProcessor processor;
 
   private void createProcessor(String name, Class<?> type) {
-    processor = new PathProcessor(name, 
TypeFactory.defaultInstance().constructType(type), null);
+    processor = new PathProcessor(name, 
TypeFactory.defaultInstance().constructType(type), null, true);
   }
 
   private void prepareGetValue(String name, Class<?> type) {
diff --git 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessor.java
 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessor.java
index ec896a2..c7e6d5b 100644
--- 
a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessor.java
+++ 
b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestQueryProcessor.java
@@ -34,7 +34,13 @@ public class TestQueryProcessor {
   HttpServletRequest request;
 
   private ParamValueProcessor createProcessor(String name, Class<?> type, 
String collectionFormat) {
-    return new QueryProcessor(name, 
TypeFactory.defaultInstance().constructType(type), null, collectionFormat);
+    return new QueryProcessor(name, 
TypeFactory.defaultInstance().constructType(type), null, true, 
collectionFormat);
+  }
+
+  private ParamValueProcessor createProcessor(String name, Class<?> type, 
String defaultValue, boolean required,
+      String collectionFormat) {
+    return new QueryProcessor(name, 
TypeFactory.defaultInstance().constructType(type), defaultValue, required,
+        collectionFormat);
   }
 
   @Test
@@ -84,4 +90,36 @@ public class TestQueryProcessor {
     ParamValueProcessor processor = createProcessor("name", String.class, 
"multi");
     Assert.assertEquals("query", processor.getProcessorType());
   }
+
+  @Test
+  public void testGetValueRequiredTrue() throws Exception {
+    new Expectations() {
+      {
+        request.getParameter("name");
+        result = null;
+      }
+    };
+
+    ParamValueProcessor processor = createProcessor("name", String.class, 
"multi");
+    try {
+      processor.getValue(request);
+      Assert.assertEquals("required is true, throw exception", "not throw 
exception");
+    } catch (Exception e) {
+      Assert.assertTrue(e.getMessage().contains("Parameter is not valid, 
required is true"));
+    }
+  }
+
+  @Test
+  public void testGetValueRequiredFalse() throws Exception {
+    new Expectations() {
+      {
+        request.getParameter("name");
+        result = null;
+      }
+    };
+
+    ParamValueProcessor processor = createProcessor("name", String.class, 
"test", false, "multi");
+    Object result = processor.getValue(request);
+    Assert.assertEquals("test", result);
+  }
 }
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 985fcb7..15b1d82 100644
--- a/demo/demo-schema/src/main/resources/microservices/pojo/server.yaml
+++ b/demo/demo-schema/src/main/resources/microservices/pojo/server.yaml
@@ -57,7 +57,7 @@ paths:
       parameters:
         - name: code
           in: query
-          required: true
+          required: false
           type: string
       responses:
         200:
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 d6b33eb..3e91509 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
@@ -61,7 +61,7 @@ public class SpringMvcDefaultValues {
   }
 
   @GetMapping("/query3")
-  public String query3(@RequestParam("a") @Min(value = 20) int a, 
@RequestParam("b") String b) {
+  public String query3(@RequestParam("a") @Min(value = 20) int a, 
@RequestParam(name = "b", required = false) String b) {
     return "Hello " + a + b;
   }
 
diff --git 
a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultValue.java
 
b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultValue.java
index d4ad947..1c172ee 100644
--- 
a/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultValue.java
+++ 
b/integration-tests/it-consumer/src/main/java/org/apache/servicecomb/it/testcase/TestDefaultValue.java
@@ -349,35 +349,62 @@ public class TestDefaultValue {
 
   @Test
   public void intForm_require_springmvc_intf() {
-    assertEquals(defaultInt, 
consumersSpringmvc.getIntf().intFormRequire(null));
+    try {
+      consumersSpringmvc.getIntf().intFormRequire(null);
+      assertEquals("required is true, throw exception", "but not throw 
exception");
+    } catch (Exception e) {
+      assertEquals(true, e.getMessage().contains("Parameter is not valid"));
+    }
   }
 
   @Test
   public void doubleForm_require_springmvc_intf() {
-    assertEquals(defaultDouble, 
consumersSpringmvc.getIntf().doubleFormRequire(null), 0.0);
+    try {
+      consumersSpringmvc.getIntf().doubleFormRequire(null);
+      assertEquals("required is true, throw exception", "but not throw 
exception");
+    } catch (Exception e) {
+      assertEquals(true, e.getMessage().contains("Parameter is not valid"));
+    }
   }
 
   @Test
   public void stringForm_require_springmvc_intf() {
-    assertEquals(defaultStr, 
consumersSpringmvc.getIntf().stringFormRequire(null));
+    try {
+      consumersSpringmvc.getIntf().stringFormRequire(null);
+      assertEquals("required is true, throw exception", "but not throw 
exception");
+    } catch (Exception e) {
+      assertEquals(true, e.getMessage().contains("Parameter is not valid"));
+    }
   }
 
   @Test
   public void intForm_require_springmvc_rt() {
-    assertEquals(defaultInt,
-        (int) 
consumersSpringmvc.getSCBRestTemplate().postForObject("/intFormRequire", null, 
int.class));
+    try {
+      consumersSpringmvc.getSCBRestTemplate().postForObject("/intFormRequire", 
null, int.class);
+      assertEquals("required is true, throw exception", "but not throw 
exception");
+    } catch (Exception e) {
+      assertEquals(true, e.getMessage().contains("Parameter is not valid"));
+    }
   }
 
   @Test
   public void doubleForm_require_springmvc_rt() {
-    assertEquals(defaultDouble,
-        
consumersSpringmvc.getSCBRestTemplate().postForObject("/doubleFormRequire", 
null, double.class), 0.0);
+    try {
+      
consumersSpringmvc.getSCBRestTemplate().postForObject("/doubleFormRequire", 
null, double.class);
+      assertEquals("required is true, throw exception", "but not throw 
exception");
+    } catch (Exception e) {
+      assertEquals(true, e.getMessage().contains("Parameter is not valid"));
+    }
   }
 
   @Test
   public void stringForm_require_springmvc_rt() {
-    assertEquals(defaultStr,
-        
consumersSpringmvc.getSCBRestTemplate().postForObject("/stringFormRequire", 
null, String.class));
+    try {
+      
consumersSpringmvc.getSCBRestTemplate().postForObject("/stringFormRequire", 
null, String.class);
+      assertEquals("required is true, throw exception", "but not throw 
exception");
+    } catch (Exception e) {
+      assertEquals(true, e.getMessage().contains("Parameter is not valid"));
+    }
   }
 
   //float
@@ -472,12 +499,21 @@ public class TestDefaultValue {
 
   @Test
   public void floatForm_require_springmvc_intf() {
-    assertEquals(defaultFloat, 
consumersSpringmvc.getIntf().floatFormRequire(null), 0.0f);
+    try {
+      consumersSpringmvc.getIntf().floatFormRequire(null);
+      assertEquals("required is true, throw exception", "but not throw 
exception");
+    } catch (Exception e) {
+      assertEquals(true, e.getMessage().contains("Parameter is not valid"));
+    }
   }
 
   @Test
   public void floatForm_require_springmvc_rt() {
-    assertEquals(defaultFloat,
-        
consumersSpringmvc.getSCBRestTemplate().postForObject("/floatFormRequire", 
null, float.class), 0.0f);
+    try {
+      
consumersSpringmvc.getSCBRestTemplate().postForObject("/floatFormRequire", 
null, float.class);
+      assertEquals("required is true, throw exception", "but not throw 
exception");
+    } catch (Exception e) {
+      assertEquals(true, e.getMessage().contains("Parameter is not valid"));
+    }
   }
 }
diff --git 
a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcIntegrationTestBase.java
 
b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcIntegrationTestBase.java
index c153a5a..c84ef3e 100644
--- 
a/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcIntegrationTestBase.java
+++ 
b/integration-tests/springmvc-tests/springmvc-tests-common/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcIntegrationTestBase.java
@@ -48,6 +48,7 @@ import org.apache.servicecomb.demo.compute.Person;
 import org.apache.servicecomb.demo.server.User;
 import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
 import 
org.apache.servicecomb.provider.springmvc.reference.async.CseAsyncRestTemplate;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
 import org.junit.ClassRule;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -66,6 +67,7 @@ import org.springframework.util.MultiValueMap;
 import org.springframework.util.concurrent.ListenableFuture;
 import org.springframework.util.concurrent.ListenableFutureCallback;
 import org.springframework.web.client.AsyncRestTemplate;
+import org.springframework.web.client.RestClientException;
 import org.springframework.web.client.RestTemplate;
 
 @Ignore
@@ -321,10 +323,14 @@ public class SpringMvcIntegrationTestBase {
     HttpHeaders headers = new HttpHeaders();
     headers.setContentType(MediaType.MULTIPART_FORM_DATA);
 
-    ResponseEntity<String> response = restTemplate
-        .postForEntity(codeFirstUrl + "uploadWithoutAnnotation", new 
HttpEntity<>(map, headers), String.class);
-    assertThat(response.getStatusCodeValue(), is(590));
-    assertThat(response.getBody(), is("CommonExceptionData [message=Cse 
Internal Server Error]"));
+    ResponseEntity<String> response = null;
+    try {
+      response = restTemplate
+          .postForEntity(codeFirstUrl + "uploadWithoutAnnotation", new 
HttpEntity<>(map, headers), String.class);
+      assertEquals("required is true, throw exception", "but not throw 
exception");
+    } catch (RestClientException e) {
+      assertEquals("400 Bad Request",e.getMessage());
+    }
   }
 
   @Test
diff --git 
a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/AbstractParameterProcessor.java
 
b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/AbstractParameterProcessor.java
index 04d992c..54ec775 100644
--- 
a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/AbstractParameterProcessor.java
+++ 
b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/generator/core/processor/parameter/AbstractParameterProcessor.java
@@ -59,10 +59,9 @@ public abstract class AbstractParameterProcessor<T extends 
AbstractSerializableP
 
   protected void setParameterDefaultValue(Object annotation, T parameter) {
     String defaultValue = getAnnotationParameterDefaultValue(annotation);
-      if (StringUtils.isNotEmpty(defaultValue)) {
-        parameter.setDefaultValue(defaultValue);
+    if (StringUtils.isNotEmpty(defaultValue)) {
+      parameter.setDefaultValue(defaultValue);
     }
-
   }
 
   protected String getAnnotationParameterDefaultValue(Object annotation) {
diff --git 
a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/CookieValueAnnotationProcessor.java
 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/CookieValueAnnotationProcessor.java
index f96802d..7fb4d91 100644
--- 
a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/CookieValueAnnotationProcessor.java
+++ 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/CookieValueAnnotationProcessor.java
@@ -19,6 +19,7 @@ package 
org.apache.servicecomb.swagger.generator.springmvc.processor.annotation;
 
 import org.apache.servicecomb.swagger.generator.core.OperationGenerator;
 import 
org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor;
+import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.CookieValue;
 import org.springframework.web.bind.annotation.ValueConstants;
 
@@ -44,6 +45,11 @@ public class CookieValueAnnotationProcessor extends 
AbstractParameterProcessor<C
       CookieParameter parameter) {
     super.fillParameter(annotation, operationGenerator, paramIdx, parameter);
 
+    Object defaultValue = parameter.getDefaultValue();
+    if (!ObjectUtils.isEmpty(defaultValue)) {
+      parameter.setRequired(false);
+      return;
+    }
     CookieValue cookie = (CookieValue) annotation;
     parameter.setRequired(cookie.required());
   }
diff --git 
a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestHeaderAnnotationProcessor.java
 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestHeaderAnnotationProcessor.java
index d34c296..63be305 100644
--- 
a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestHeaderAnnotationProcessor.java
+++ 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestHeaderAnnotationProcessor.java
@@ -19,6 +19,7 @@ package 
org.apache.servicecomb.swagger.generator.springmvc.processor.annotation;
 
 import org.apache.servicecomb.swagger.generator.core.OperationGenerator;
 import 
org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor;
+import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.RequestHeader;
 import org.springframework.web.bind.annotation.ValueConstants;
 
@@ -44,10 +45,15 @@ public class RequestHeaderAnnotationProcessor extends 
AbstractParameterProcessor
       HeaderParameter parameter) {
     super.fillParameter(annotation, operationGenerator, paramIdx, parameter);
 
+    Object defaultValue = parameter.getDefaultValue();
+    if (!ObjectUtils.isEmpty(defaultValue)) {
+      parameter.setRequired(false);
+      return;
+    }
     RequestHeader requestHeader = (RequestHeader) annotation;
     parameter.setRequired(requestHeader.required());
   }
-  
+
   @Override
   protected String getAnnotationParameterDefaultValue(Object annotation) {
     String defaultValue = ((RequestHeader) annotation).defaultValue();
@@ -56,5 +62,4 @@ public class RequestHeaderAnnotationProcessor extends 
AbstractParameterProcessor
     }
     return defaultValue;
   }
-  
 }
diff --git 
a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestParamAnnotationProcessor.java
 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestParamAnnotationProcessor.java
index 8ad9a4b..828a782 100644
--- 
a/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestParamAnnotationProcessor.java
+++ 
b/swagger/swagger-generator/generator-springmvc/src/main/java/org/apache/servicecomb/swagger/generator/springmvc/processor/annotation/RequestParamAnnotationProcessor.java
@@ -17,13 +17,14 @@
 
 package 
org.apache.servicecomb.swagger.generator.springmvc.processor.annotation;
 
+import io.swagger.models.parameters.QueryParameter;
+
 import org.apache.servicecomb.swagger.generator.core.OperationGenerator;
 import 
org.apache.servicecomb.swagger.generator.core.processor.parameter.AbstractParameterProcessor;
+import org.springframework.util.ObjectUtils;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ValueConstants;
 
-import io.swagger.models.parameters.QueryParameter;
-
 public class RequestParamAnnotationProcessor extends 
AbstractParameterProcessor<QueryParameter> {
   @Override
   public QueryParameter createParameter() {
@@ -44,6 +45,11 @@ public class RequestParamAnnotationProcessor extends 
AbstractParameterProcessor<
       QueryParameter parameter) {
     super.fillParameter(annotation, operationGenerator, paramIdx, parameter);
 
+    Object defaultValue = parameter.getDefaultValue();
+    if (!ObjectUtils.isEmpty(defaultValue)) {
+      parameter.setRequired(false);
+      return;
+    }
     RequestParam requestParam = (RequestParam) annotation;
     parameter.setRequired(requestParam.required());
   }

Reply via email to