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

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new aef9541  Tests
aef9541 is described below

commit aef95412a63fd686695a4e21f5845ae6534f04e3
Author: JamesBognar <[email protected]>
AuthorDate: Mon Aug 27 17:09:13 2018 -0400

    Tests
---
 .../http/annotation/AnnotationUtilsTest.java       |   2 +-
 .../org/apache/juneau/testutils/TestUtils.java     |  16 +++
 .../src/main/java/org/apache/juneau/ObjectMap.java |  30 +++---
 .../juneau/http/annotation/AnnotationUtils.java    |   6 +-
 .../org/apache/juneau/httppart/HttpPartSchema.java |  46 +++++++--
 .../juneau/httppart/HttpPartSchemaBuilder.java     |  18 ++--
 .../org/apache/juneau/rest/client/RestCall.java    | 114 ++++++++++++++++-----
 .../rest/client/SerializedNameValuePair.java       |   2 +-
 .../rest/client/remote/FormDataAnnotationTest.java | 109 ++++++++++++++++----
 .../rest/client/remote/HeaderAnnotationTest.java   |  67 ++++++++++++
 .../rest/client/remote/PathAnnotationTest.java     |   1 +
 .../rest/client/remote/QueryAnnotationTest.java    |  66 ++++++++++++
 12 files changed, 391 insertions(+), 86 deletions(-)

diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/http/annotation/AnnotationUtilsTest.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/http/annotation/AnnotationUtilsTest.java
index b1ab4d7..6c213fc 100644
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/http/annotation/AnnotationUtilsTest.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/http/annotation/AnnotationUtilsTest.java
@@ -107,7 +107,7 @@ public class AnnotationUtilsTest {
        public void testAllEmpty2() {
                assertTrue(allEmpty(new String[0],new String[0]));
                assertTrue(allEmpty(null,new String[0]));
-               assertTrue(allEmpty(null,new String[]{""}));
+               assertFalse(allEmpty(null,new String[]{""}));
                assertFalse(allEmpty(null,new String[]{"x"}));
        }
 
diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java
index 1e813e8..cc2a215 100644
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java
@@ -27,6 +27,7 @@ import javax.xml.transform.stream.*;
 import javax.xml.validation.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.transforms.*;
@@ -487,6 +488,21 @@ public class TestUtils {
                                throw new ComparisonFailure("Text did not 
contain expected substring.", toString(substring), toString(value));
        }
 
+       public static final void assertContains(Exception e, 
String...substrings) {
+               for (String substring : substrings) {
+                       Throwable e2 = e;
+                       boolean found = false;
+                       while (e2 != null && ! found) {
+                               found |= contains(e2.getMessage(), substring);
+                               e2 = e2.getCause();
+                       }
+                       if (! found) {
+                               e.printStackTrace();
+                               throw new ComparisonFailure("Exception message 
did not contain expected substring.", toString(substring), 
StringUtils.getStackTrace(e));
+                       }
+               }
+       }
+
        /**
         * Creates a ClassMeta for the given types.
         */
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java
index 0f5d0d6..8e579b0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ObjectMap.java
@@ -328,47 +328,45 @@ public class ObjectMap extends 
LinkedHashMap<String,Object> {
        }
 
        /**
-        * Convenience method for adding an entry to this map.
-        *
-        * <p>
-        * A no-op if the value is <jk>null</jk> or an empty 
string/map/collection.
+        * Conditionally appends a value to this map.
         *
+        * @param flag The boolean value that must be <jk>true</jk> in order to 
add this entry..
         * @param key The key.
         * @param value The value.
         * @return This object (for method chaining).
         */
-       public ObjectMap appendSkipEmpty(String key, Object value) {
-               return appendIf(true, true, true, key, value);
+       public ObjectMap appendIf(boolean flag, String key, Object value) {
+               if (flag)
+                       put(key, value);
+               return this;
        }
 
        /**
         * Convenience method for adding an entry to this map.
         *
         * <p>
-        * A no-op if the value is <jk>false</jk>.
+        * A no-op if the value is <jk>null</jk> or an empty 
string/map/collection.
         *
         * @param key The key.
         * @param value The value.
         * @return This object (for method chaining).
         */
-       public ObjectMap appendSkipFalse(String key, boolean value) {
-               if (value)
-                       append(key, value);
-               return this;
+       public ObjectMap appendSkipEmpty(String key, Object value) {
+               return appendIf(true, true, true, key, value);
        }
 
        /**
         * Convenience method for adding an entry to this map.
         *
         * <p>
-        * A no-op if the value is <code>-1</code>.
+        * A no-op if the value is <jk>false</jk>.
         *
         * @param key The key.
         * @param value The value.
         * @return This object (for method chaining).
         */
-       public ObjectMap appendSkipMinusOne(String key, long value) {
-               if (value != -1)
+       public ObjectMap appendSkipFalse(String key, boolean value) {
+               if (value)
                        append(key, value);
                return this;
        }
@@ -383,8 +381,8 @@ public class ObjectMap extends LinkedHashMap<String,Object> 
{
         * @param value The value.
         * @return This object (for method chaining).
         */
-       public ObjectMap appendSkipMinusOne(String key, int value) {
-               if (value != -1)
+       public ObjectMap appendSkipMinusOne(String key, Number value) {
+               if (value != null && value.intValue() != -1)
                        append(key, value);
                return this;
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
index 4cc2a5e..a917cc1 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
@@ -246,14 +246,14 @@ public class AnnotationUtils {
        }
 
        /**
-        * Returns <jk>true</jk> if all the specified strings are empty or null.
+        * Returns <jk>true</jk> if all the specified string arrays are empty.
         *
         * @param strings The strings to test.
-        * @return <jk>true</jk> if all the specified strings are empty or null.
+        * @return <jk>true</jk> if all the specified string arrays are empty.
         */
        protected static boolean allEmpty(String[]...strings) {
                for (String[] s : strings)
-                       if (s != null && s.length > 0 && ! allEmpty(s))
+                       if (s != null && s.length > 0)
                                return false;
                return true;
        }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
index ae2f4e7..c8e618b 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchema.java
@@ -1312,16 +1312,40 @@ public class HttpPartSchema {
 
        @Override
        public String toString() {
-               return toString(new StringBuilder()).toString();
-       }
-
-       private StringBuilder toString(StringBuilder sb) {
-               ObjectMap m = new ObjectMap();
-               m.appendSkipEmpty("name", name);
-               m.appendSkipEmpty("type", type);
-               m.appendSkipEmpty("format", format);
-               sb.append(m.toString());
-               return sb;
+               try {
+                       ObjectMap m = new ObjectMap()
+                               .appendSkipEmpty("name", name)
+                               .appendSkipEmpty("type", type)
+                               .appendSkipEmpty("format", format)
+                               .appendSkipEmpty("codes", codes)
+                               .appendSkipEmpty("default", _default)
+                               .appendSkipEmpty("enum", _enum)
+                               .appendSkipEmpty("properties", properties)
+                               .appendSkipFalse("allowEmptyValue", 
allowEmptyValue)
+                               .appendSkipFalse("exclusiveMaximum", 
exclusiveMaximum)
+                               .appendSkipFalse("exclusiveMinimum", 
exclusiveMinimum)
+                               .appendSkipFalse("required", required)
+                               .appendSkipFalse("uniqueItems", uniqueItems)
+                               .appendSkipFalse("skipIfEmpty", skipIfEmpty)
+                               .appendIf(collectionFormat != 
CollectionFormat.NO_COLLECTION_FORMAT, "collectionFormat", collectionFormat)
+                               .appendSkipEmpty("pattern", pattern)
+                               .appendSkipNull("items", items)
+                               .appendSkipNull("additionalProperties", 
additionalProperties)
+                               .appendSkipMinusOne("maximum", maximum)
+                               .appendSkipMinusOne("minimum", minimum)
+                               .appendSkipMinusOne("multipleOf", multipleOf)
+                               .appendSkipMinusOne("maxLength", maxLength)
+                               .appendSkipMinusOne("minLength", minLength)
+                               .appendSkipMinusOne("maxItems", maxItems)
+                               .appendSkipMinusOne("minItems", minItems)
+                               .appendSkipMinusOne("maxProperties", 
maxProperties)
+                               .appendSkipMinusOne("minProperties", 
minProperties)
+                               .append("parsedType", parsedType)
+                       ;
+                       return m.toString();
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       return "";
+               }
        }
-
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
index ba6e593..ffc3b9e 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
@@ -136,7 +136,7 @@ public class HttpPartSchemaBuilder {
                allowEmptyValue(a.allowEmptyValue());
                items(a.items());
                collectionFormat(a.collectionFormat());
-               _default(joinnl(a._default()));
+               _default(a._default().length == 0 ? null : 
joinnl(a._default()));
                maximum(HttpPartSchema.toNumber(a.maximum()));
                exclusiveMaximum(a.exclusiveMaximum());
                minimum(HttpPartSchema.toNumber(a.minimum()));
@@ -163,7 +163,7 @@ public class HttpPartSchemaBuilder {
                format(a.format());
                items(a.items());
                collectionFormat(a.collectionFormat());
-               _default(joinnl(a._default()));
+               _default(a._default().length == 0 ? null : 
joinnl(a._default()));
                maximum(HttpPartSchema.toNumber(a.maximum()));
                exclusiveMaximum(a.exclusiveMaximum());
                minimum(HttpPartSchema.toNumber(a.minimum()));
@@ -190,7 +190,7 @@ public class HttpPartSchemaBuilder {
                allowEmptyValue(a.allowEmptyValue());
                items(a.items());
                collectionFormat(a.collectionFormat());
-               _default(joinnl(a._default()));
+               _default(a._default().length == 0 ? null : 
joinnl(a._default()));
                maximum(HttpPartSchema.toNumber(a.maximum()));
                exclusiveMaximum(a.exclusiveMaximum());
                minimum(HttpPartSchema.toNumber(a.minimum()));
@@ -218,7 +218,7 @@ public class HttpPartSchemaBuilder {
                allowEmptyValue(a.allowEmptyValue());
                items(a.items());
                collectionFormat(a.collectionFormat());
-               _default(joinnl(a._default()));
+               _default(a._default().length == 0 ? null : 
joinnl(a._default()));
                maximum(HttpPartSchema.toNumber(a.maximum()));
                exclusiveMaximum(a.exclusiveMaximum());
                minimum(HttpPartSchema.toNumber(a.minimum()));
@@ -280,7 +280,7 @@ public class HttpPartSchemaBuilder {
                format(a.format());
                items(a.items());
                collectionFormat(a.collectionFormat());
-               _default(joinnl(a._default()));
+               _default(a._default().length == 0 ? null : 
joinnl(a._default()));
                maximum(HttpPartSchema.toNumber(a.maximum()));
                exclusiveMaximum(a.exclusiveMaximum());
                minimum(HttpPartSchema.toNumber(a.minimum()));
@@ -301,7 +301,7 @@ public class HttpPartSchemaBuilder {
                format(a.format());
                items(HttpPartSchema.toObjectMap(a.items()));
                collectionFormat(a.collectionFormat());
-               _default(joinnl(a._default()));
+               _default(a._default().length == 0 ? null : 
joinnl(a._default()));
                maximum(HttpPartSchema.toNumber(a.maximum()));
                exclusiveMaximum(a.exclusiveMaximum());
                minimum(HttpPartSchema.toNumber(a.minimum()));
@@ -322,7 +322,7 @@ public class HttpPartSchemaBuilder {
                format(a.format());
                items(a.items());
                collectionFormat(a.collectionFormat());
-               _default(joinnl(a._default()));
+               _default(a._default().length == 0 ? null : 
joinnl(a._default()));
                maximum(HttpPartSchema.toNumber(a.maximum()));
                exclusiveMaximum(a.exclusiveMaximum());
                minimum(HttpPartSchema.toNumber(a.minimum()));
@@ -819,11 +819,11 @@ public class HttpPartSchemaBuilder {
         *
         * @param value
         *      The new value for this property.
-        *      <br>Ignored if value is <jk>null</jk> or empty.
+        *      <br>Ignored if value is <jk>null</jk>.
         * @return This object (for method chaining).
         */
        public HttpPartSchemaBuilder _default(String value) {
-               if (isNotEmpty(value))
+               if (value != null)
                        this._default = value;
                return this;
        }
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
index b08c1f0..c14490f 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
@@ -219,22 +219,34 @@ public final class RestCall extends BeanSession 
implements Closeable {
        public RestCall query(String name, Object value, boolean skipIfEmpty, 
HttpPartSerializer serializer, HttpPartSchema schema) throws RestCallException {
                if (serializer == null)
                        serializer = client.getPartSerializer();
+               if (schema == null)
+                       schema = HttpPartSchema.DEFAULT;
                boolean isMulti = isEmpty(name) || "*".equals(name) || value 
instanceof NameValuePairs;
                if (! isMulti) {
-                       if (value != null && ! (ObjectUtils.isEmpty(value) && 
skipIfEmpty))
+                       if (canAdd(value, schema, skipIfEmpty))
                                try {
-                                       uriBuilder.addParameter(name, 
serializer.createPartSession().serialize(QUERY, schema, value));
+                                       uriBuilder.addParameter(name, 
serializer.serialize(QUERY, schema, value));
                                } catch (SchemaValidationException e) {
                                        throw new RestCallException(e, 
"Validation error on request query parameter ''{0}''=''{1}''", name, value);
                                } catch (SerializeException e) {
                                        throw new RestCallException(e, 
"Serialization error on request query parameter ''{0}''", name);
                                }
                } else if (value instanceof NameValuePairs) {
-                       for (NameValuePair p : (NameValuePairs)value)
-                               query(p.getName(), p.getValue(), skipIfEmpty, 
serializer, schema);
+                       for (NameValuePair p : (NameValuePairs)value) {
+                               String n = p.getName();
+                               String v = p.getValue();
+                               HttpPartSchema s = schema.getProperty(n);
+                               if (canAdd(v, s, skipIfEmpty))
+                                       query(n, v, skipIfEmpty, serializer, s);
+                       }
                } else if (value instanceof Map) {
-                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet())
-                               query(p.getKey(), p.getValue(), skipIfEmpty, 
serializer, schema);
+                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet()) {
+                               String n = p.getKey();
+                               Object v = p.getValue();
+                               HttpPartSchema s = schema.getProperty(n);
+                               if (canAdd(v, s, skipIfEmpty))
+                                       query(n, v, skipIfEmpty, serializer, s);
+                       }
                } else if (isBean(value)) {
                        return query(name, toBeanMap(value), skipIfEmpty, 
serializer, schema);
                } else if (value instanceof Reader || value instanceof 
InputStream) {
@@ -342,17 +354,28 @@ public final class RestCall extends BeanSession 
implements Closeable {
                        formData = new NameValuePairs();
                if (serializer == null)
                        serializer = client.getPartSerializer();
+               if (schema == null)
+                       schema = HttpPartSchema.DEFAULT;
                boolean isMulti = isEmpty(name) || "*".equals(name) || value 
instanceof NameValuePairs;
                if (! isMulti) {
-                       if (value != null && ! (ObjectUtils.isEmpty(value) && 
skipIfEmpty))
+                       if (canAdd(value, schema, skipIfEmpty))
                                formData.add(new SerializedNameValuePair(name, 
value, serializer, schema));
                } else if (value instanceof NameValuePairs) {
-                       for (NameValuePair p : (NameValuePairs)value)
-                               if (p.getValue() != null && ! 
(isEmpty(p.getValue()) && skipIfEmpty))
+                       for (NameValuePair p : (NameValuePairs)value) {
+                               String n = p.getName();
+                               String v = p.getValue();
+                               HttpPartSchema s = schema.getProperty(n);
+                               if (canAdd(v, s, skipIfEmpty))
                                        formData.add(p);
+                       }
                } else if (value instanceof Map) {
-                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet())
-                               formData(p.getKey(), p.getValue(), skipIfEmpty, 
serializer, schema);
+                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet()) {
+                               String n = p.getKey();
+                               Object v = p.getValue();
+                               HttpPartSchema s = schema.getProperty(n);
+                               if (canAdd(v, s, skipIfEmpty))
+                                       formData(n, v, skipIfEmpty, serializer, 
s);
+                       }
                } else if (isBean(value)) {
                        return formData(name, toBeanMap(value), skipIfEmpty, 
serializer, schema);
                } else if (value instanceof Reader || value instanceof 
InputStream) {
@@ -456,6 +479,8 @@ public final class RestCall extends BeanSession implements 
Closeable {
                String path = uriBuilder.getPath();
                if (serializer == null)
                        serializer = client.getPartSerializer();
+               if (schema == null)
+                       schema = HttpPartSchema.DEFAULT;
                boolean isMulti = isEmpty(name) || "*".equals(name) || value 
instanceof NameValuePairs;
                if (! isMulti) {
                        String var = "{" + name + "}";
@@ -464,9 +489,9 @@ public final class RestCall extends BeanSession implements 
Closeable {
                        try {
                                String p = null;
                                if (name.equals("/*"))
-                                       p = path.replaceAll("\\/\\*$", 
serializer.createPartSession().serialize(PATH, schema, value));
+                                       p = path.replaceAll("\\/\\*$", 
serializer.serialize(PATH, schema, value));
                                else
-                                       p = path.replace(var, 
serializer.createPartSession().serialize(PATH, schema, value));
+                                       p = path.replace(var, 
serializer.serialize(PATH, schema, value));
                                uriBuilder.setPath(p);
                        } catch (SchemaValidationException e) {
                                throw new RestCallException(e, "Validation 
error on request path parameter ''{0}''=''{1}''", name, value);
@@ -474,11 +499,19 @@ public final class RestCall extends BeanSession 
implements Closeable {
                                throw new RestCallException(e, "Serialization 
error on request path parameter ''{0}''", name);
                        }
                } else if (value instanceof NameValuePairs) {
-                       for (NameValuePair p : (NameValuePairs)value)
-                               path(p.getName(), p.getValue(), serializer, 
schema);
+                       for (NameValuePair p : (NameValuePairs)value) {
+                               String n = p.getName();
+                               String v = p.getValue();
+                               HttpPartSchema s = schema.getProperty(n);
+                               path(n, v, serializer, s);
+                       }
                } else if (value instanceof Map) {
-                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet())
-                               path(p.getKey(), p.getValue(), serializer, 
schema);
+                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet()) {
+                               String n = p.getKey();
+                               Object v = p.getValue();
+                               HttpPartSchema s = schema.getProperty(n);
+                               path(n, v, serializer, s);
+                       }
                } else if (isBean(value)) {
                        return path(name, toBeanMap(value), serializer, schema);
                } else if (value != null) {
@@ -637,22 +670,34 @@ public final class RestCall extends BeanSession 
implements Closeable {
        public RestCall header(String name, Object value, boolean skipIfEmpty, 
HttpPartSerializer serializer, HttpPartSchema schema) throws RestCallException {
                if (serializer == null)
                        serializer = client.getPartSerializer();
+               if (schema == null)
+                       schema = HttpPartSchema.DEFAULT;
                boolean isMulti = isEmpty(name) || "*".equals(name) || value 
instanceof NameValuePairs;
                if (! isMulti) {
-                       if (value != null && ! (ObjectUtils.isEmpty(value) && 
skipIfEmpty))
+                       if (canAdd(value, schema, skipIfEmpty))
                                try {
-                                       request.setHeader(name, 
serializer.createPartSession().serialize(HEADER, schema, value));
+                                       request.setHeader(name, 
serializer.serialize(HEADER, schema, value));
                                } catch (SchemaValidationException e) {
                                        throw new RestCallException(e, 
"Validation error on request header parameter ''{0}''=''{1}''", name, value);
                                } catch (SerializeException e) {
                                        throw new RestCallException(e, 
"Serialization error on request header parameter ''{0}''", name);
                                }
                } else if (value instanceof NameValuePairs) {
-                       for (NameValuePair p : (NameValuePairs)value)
-                               header(p.getName(), p.getValue(), skipIfEmpty, 
serializer, schema);
+                       for (NameValuePair p : (NameValuePairs)value) {
+                               String n = p.getName();
+                               String v = p.getValue();
+                               HttpPartSchema s = schema.getProperty(n);
+                               if (canAdd(v, s, skipIfEmpty))
+                                       header(n, v, skipIfEmpty, serializer, 
s);
+                       }
                } else if (value instanceof Map) {
-                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet())
-                               header(p.getKey(), p.getValue(), skipIfEmpty, 
serializer, schema);
+                       for (Map.Entry<String,Object> p : ((Map<String,Object>) 
value).entrySet()) {
+                               String n = p.getKey();
+                               Object v = p.getValue();
+                               HttpPartSchema s = schema.getProperty(n);
+                               if (canAdd(v, s, skipIfEmpty))
+                                       header(n, v, skipIfEmpty, serializer, 
s);
+                       }
                } else if (isBean(value)) {
                        return header(name, toBeanMap(value), skipIfEmpty, 
serializer, schema);
                } else {
@@ -2345,4 +2390,27 @@ public final class RestCall extends BeanSession 
implements Closeable {
                header("Debug", true);
                return this;
        }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // Utility methods
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       /**
+        * Specifies that the following value can be added as an HTTP part.
+        */
+       private boolean canAdd(Object value, HttpPartSchema schema, boolean 
skipIfEmpty) {
+               if (value != null) {
+                       if (ObjectUtils.isEmpty(value) && skipIfEmpty)
+                               return false;
+                       return true;
+               }
+               if (schema == null)
+                       return false;
+               String def = schema.getDefault();
+               if (def == null)
+                       return false;
+               if (StringUtils.isEmpty(def) && skipIfEmpty)
+                       return false;
+               return true;
+       }
 }
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/SerializedNameValuePair.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/SerializedNameValuePair.java
index 6c920d9..fd1573f 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/SerializedNameValuePair.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/SerializedNameValuePair.java
@@ -65,7 +65,7 @@ public final class SerializedNameValuePair implements 
NameValuePair {
        @Override /* NameValuePair */
        public String getValue() {
                try {
-                       return 
serializer.createPartSession().serialize(HttpPartType.FORMDATA, schema, value);
+                       return serializer.serialize(HttpPartType.FORMDATA, 
schema, value);
                } catch (SchemaValidationException e) {
                        throw new FormattedRuntimeException(e, "Validation 
error on request form-data parameter ''{0}''=''{1}''", name, value);
                } catch (SerializeException e) {
diff --git 
a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
 
b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
index f98a1fc..549a3fb 100644
--- 
a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
+++ 
b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/FormDataAnnotationTest.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.rest.client.remote;
 
 import static org.junit.Assert.*;
+import static org.apache.juneau.testutils.TestUtils.*;
 
 import java.io.*;
 import java.util.*;
@@ -59,7 +60,7 @@ public class FormDataAnnotationTest {
        private static MockRest a = MockRest.create(A.class);
 
        @RemoteResource
-       public static interface A01 {
+       public static interface AR {
                @RemoteMethod(path="a") String postA01(@FormData("x") int b);
                @RemoteMethod(path="a") String postA02(@FormData("x") float b);
                @RemoteMethod(path="a") String postA03a(@FormData("x") Bean b);
@@ -82,86 +83,150 @@ public class FormDataAnnotationTest {
                @RemoteMethod(path="a") String postA09b(@FormData 
NameValuePairs b);
        }
 
-       private static A01 a01 = 
RestClient.create().mockHttpConnection(a).build().getRemoteResource(A01.class);
+       private static AR ar = 
RestClient.create().mockHttpConnection(a).build().getRemoteResource(AR.class);
 
        @Test
        public void a01_int() throws Exception {
-               assertEquals("{x:'1'}", a01.postA01(1));
+               assertEquals("{x:'1'}", ar.postA01(1));
        }
        @Test
        public void a02_float() throws Exception {
-               assertEquals("{x:'1.0'}", a01.postA02(1));
+               assertEquals("{x:'1.0'}", ar.postA02(1));
        }
        @Test
        public void a03a_Bean() throws Exception {
-               assertEquals("{x:'(f=1)'}", a01.postA03a(Bean.create()));
+               assertEquals("{x:'(f=1)'}", ar.postA03a(Bean.create()));
        }
        @Test
        public void a03b_Bean() throws Exception {
-               assertEquals("{f:'1'}", a01.postA03b(Bean.create()));
+               assertEquals("{f:'1'}", ar.postA03b(Bean.create()));
        }
        @Test
        public void a03c_Bean() throws Exception {
-               assertEquals("{f:'1'}", a01.postA03c(Bean.create()));
+               assertEquals("{f:'1'}", ar.postA03c(Bean.create()));
        }
        @Test
        public void a04a_BeanArray() throws Exception {
-               assertEquals("{x:'(f=1),(f=1)'}", a01.postA04a(new 
Bean[]{Bean.create(),Bean.create()}));
+               assertEquals("{x:'(f=1),(f=1)'}", ar.postA04a(new 
Bean[]{Bean.create(),Bean.create()}));
        }
        @Test
        public void a04b_BeanArray() throws Exception {
-               assertEquals("{x:'@((f=1),(f=1))'}", a01.postA04b(new 
Bean[]{Bean.create(),Bean.create()}));
+               assertEquals("{x:'@((f=1),(f=1))'}", ar.postA04b(new 
Bean[]{Bean.create(),Bean.create()}));
        }
        @Test
        public void a05a_ListOfBeans() throws Exception {
-               assertEquals("{x:'(f=1),(f=1)'}", 
a01.postA05a(AList.create(Bean.create(),Bean.create())));
+               assertEquals("{x:'(f=1),(f=1)'}", 
ar.postA05a(AList.create(Bean.create(),Bean.create())));
        }
        @Test
        public void a05b_ListOfBeans() throws Exception {
-               assertEquals("{x:'@((f=1),(f=1))'}", 
a01.postA05b(AList.create(Bean.create(),Bean.create())));
+               assertEquals("{x:'@((f=1),(f=1))'}", 
ar.postA05b(AList.create(Bean.create(),Bean.create())));
        }
        @Test
        public void a06a_MapOfBeans() throws Exception {
-               assertEquals("{x:'(k1=(f=1))'}", 
a01.postA06a(AMap.create("k1",Bean.create())));
+               assertEquals("{x:'(k1=(f=1))'}", 
ar.postA06a(AMap.create("k1",Bean.create())));
        }
        @Test
        public void a06b_MapOfBeans() throws Exception {
-               assertEquals("{k1:'(f=1)'}", 
a01.postA06b(AMap.create("k1",Bean.create())));
+               assertEquals("{k1:'(f=1)'}", 
ar.postA06b(AMap.create("k1",Bean.create())));
        }
        @Test
        public void a06c_MapOfBeans() throws Exception {
-               assertEquals("{k1:'(f=1)'}", 
a01.postA06c(AMap.create("k1",Bean.create())));
+               assertEquals("{k1:'(f=1)'}", 
ar.postA06c(AMap.create("k1",Bean.create())));
        }
        @Test
        public void a06d_MapOfBeans() throws Exception {
-               assertEquals("{x:'(k1=(f=1))'}", 
a01.postA06d(AMap.create("k1",Bean.create())));
+               assertEquals("{x:'(k1=(f=1))'}", 
ar.postA06d(AMap.create("k1",Bean.create())));
        }
        @Test
        public void a06e_MapOfBeans() throws Exception {
-               assertEquals("{k1:'(f=1)'}", 
a01.postA06e(AMap.create("k1",Bean.create())));
+               assertEquals("{k1:'(f=1)'}", 
ar.postA06e(AMap.create("k1",Bean.create())));
        }
        @Test
        public void a07a_Reader() throws Exception {
-               assertEquals("{x:'1'}", a01.postA07a(new StringReader("x=1")));
+               assertEquals("{x:'1'}", ar.postA07a(new StringReader("x=1")));
        }
        @Test
        public void a07b_Reader() throws Exception {
-               assertEquals("{x:'1'}", a01.postA07b(new StringReader("x=1")));
+               assertEquals("{x:'1'}", ar.postA07b(new StringReader("x=1")));
        }
        @Test
        public void a08a_InputStream() throws Exception {
-               assertEquals("{x:'1'}", a01.postA08a(new 
StringInputStream("x=1")));
+               assertEquals("{x:'1'}", ar.postA08a(new 
StringInputStream("x=1")));
        }
        @Test
        public void a08b_InputStream() throws Exception {
-               assertEquals("{x:'1'}", a01.postA08b(new 
StringInputStream("x=1")));
+               assertEquals("{x:'1'}", ar.postA08b(new 
StringInputStream("x=1")));
        }
        @Test
        public void a09a_NameValuePairs() throws Exception {
-               assertEquals("{foo:'bar'}", a01.postA09a(new 
NameValuePairs().append("foo", "bar")));
+               assertEquals("{foo:'bar'}", ar.postA09a(new 
NameValuePairs().append("foo", "bar")));
        }
        @Test
        public void a09b_NameValuePairs() throws Exception {
-               assertEquals("{foo:'bar'}", a01.postA09b(new 
NameValuePairs().append("foo", "bar")));
+               assertEquals("{foo:'bar'}", ar.postA09b(new 
NameValuePairs().append("foo", "bar")));
+       }
+
+       
//=================================================================================================================
+       // @FormData(_default)
+       
//=================================================================================================================
+
+       @RestResource
+       public static class B {
+               @RestMethod
+               public String post(@FormData("*") ObjectMap m) {
+                       return m.toString();
+               }
+       }
+       private static MockRest b = MockRest.create(B.class);
+
+       @RemoteResource
+       public static interface BR {
+               @RemoteMethod(path="/") String 
postB01(@FormData(name="x",_default="foo") String b);
+               @RemoteMethod(path="/") String 
postB02(@FormData(name="x",_default="foo",allowEmptyValue=true) String b);
+               @RemoteMethod(path="/") String 
postB03(@FormData(name="x",_default="") String b);
+               @RemoteMethod(path="/") String 
postB04(@FormData(name="x",_default="",allowEmptyValue=true) String b);
+       }
+
+       private static BR br = 
RestClient.create().mockHttpConnection(b).build().getRemoteResource(BR.class);
+
+       @Test
+       public void b01a_default() throws Exception {
+               assertEquals("{x:'foo'}", br.postB01(null));
+       }
+       @Test
+       public void b01b_default_emptyString() throws Exception {
+               try {
+                       br.postB01("");
+               } catch (Exception e) {
+                       assertContains(e, "Empty value not allowed");
+               }
+       }
+       @Test
+       public void b02a_default_allowEmptyValue() throws Exception {
+               assertEquals("{x:'foo'}", br.postB02(null));
+       }
+       @Test
+       public void b02b_default_allowEmptyValue_emptyString() throws Exception 
{
+               assertEquals("{x:''}", br.postB02(""));
+       }
+       @Test
+       public void b03a_defaultIsBlank() throws Exception {
+               assertEquals("{x:''}", br.postB03(null));
+       }
+       @Test
+       public void b03b_defaultIsBlank_emptyString() throws Exception {
+               try {
+                       br.postB03("");
+               } catch (Exception e) {
+                       assertContains(e, "Empty value not allowed");
+               }
+       }
+       @Test
+       public void b04a_defaultIsBlank_allowEmptyValue() throws Exception {
+               assertEquals("{x:''}", br.postB04(null));
+       }
+       @Test
+       public void b04b_defaultIsBlank_allowEmptyValue_emptyString() throws 
Exception {
+               assertEquals("{x:''}", br.postB04(""));
        }
 }
diff --git 
a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
 
b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
index 046843d..099bbc0 100644
--- 
a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
+++ 
b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/HeaderAnnotationTest.java
@@ -12,7 +12,9 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest.client.remote;
 
+import static org.apache.juneau.testutils.TestUtils.*;
 import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
 
 import java.util.*;
 
@@ -142,4 +144,69 @@ public class HeaderAnnotationTest {
        public void a09b_NameValuePairs() throws Exception {
                assertEquals("{foo:'bar'}", a01.getA09b(new 
NameValuePairs().append("foo", "bar")));
        }
+
+       
//=================================================================================================================
+       // @Header(_default)
+       
//=================================================================================================================
+
+       @RestResource
+       public static class B {
+               @RestMethod
+               public String get(@Header("*") ObjectMap m) {
+                       
m.removeAll("Accept-Encoding","Connection","Host","User-Agent");
+                       return m.toString();
+               }
+       }
+       private static MockRest b = MockRest.create(B.class);
+
+       @RemoteResource
+       public static interface BR {
+               @RemoteMethod(path="/") String 
getB01(@Header(name="x",_default="foo") String b);
+               @RemoteMethod(path="/") String 
getB02(@Header(name="x",_default="foo",allowEmptyValue=true) String b);
+               @RemoteMethod(path="/") String 
getB03(@Header(name="x",_default="") String b);
+               @RemoteMethod(path="/") String 
getB04(@Header(name="x",_default="",allowEmptyValue=true) String b);
+       }
+
+       private static BR br = 
RestClient.create().mockHttpConnection(b).build().getRemoteResource(BR.class);
+
+       @Test
+       public void b01a_default() throws Exception {
+               assertEquals("{x:'foo'}", br.getB01(null));
+       }
+       @Test
+       public void b01b_default_emptyString() throws Exception {
+               try {
+                       br.getB01("");
+               } catch (Exception e) {
+                       assertContains(e, "Empty value not allowed");
+               }
+       }
+       @Test
+       public void b02a_default_allowEmptyValue() throws Exception {
+               assertEquals("{x:'foo'}", br.getB02(null));
+       }
+       @Test
+       public void b02b_default_allowEmptyValue_emptyString() throws Exception 
{
+               assertEquals("{x:''}", br.getB02(""));
+       }
+       @Test
+       public void b03a_defaultIsBlank() throws Exception {
+               assertEquals("{x:''}", br.getB03(null));
+       }
+       @Test
+       public void b03b_defaultIsBlank_emptyString() throws Exception {
+               try {
+                       br.getB03("");
+               } catch (Exception e) {
+                       assertContains(e, "Empty value not allowed");
+               }
+       }
+       @Test
+       public void b04a_defaultIsBlank_allowEmptyValue() throws Exception {
+               assertEquals("{x:''}", br.getB04(null));
+       }
+       @Test
+       public void b04b_defaultIsBlank_allowEmptyValue_emptyString() throws 
Exception {
+               assertEquals("{x:''}", br.getB04(""));
+       }
 }
diff --git 
a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
 
b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
index 91701ef..38b3989 100644
--- 
a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
+++ 
b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/PathAnnotationTest.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.rest.client.remote;
 
 import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
 
 import java.util.*;
 
diff --git 
a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
 
b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
index 46ed0ee..d1a3697 100644
--- 
a/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
+++ 
b/juneau-rest/juneau-rest-client/src/test/java/org/apache/juneau/rest/client/remote/QueryAnnotationTest.java
@@ -12,7 +12,9 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest.client.remote;
 
+import static org.apache.juneau.testutils.TestUtils.*;
 import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
 
 import java.io.*;
 import java.util.*;
@@ -162,4 +164,68 @@ public class QueryAnnotationTest {
        public void a09b_NameValuePairs() throws Exception {
                assertEquals("{foo:'bar'}", a01.getA09b(new 
NameValuePairs().append("foo", "bar")));
        }
+
+       
//=================================================================================================================
+       // @Query(_default)
+       
//=================================================================================================================
+
+       @RestResource
+       public static class B {
+               @RestMethod
+               public String get(@Query("*") ObjectMap m) {
+                       return m.toString();
+               }
+       }
+       private static MockRest b = MockRest.create(B.class);
+
+       @RemoteResource
+       public static interface BR {
+               @RemoteMethod(path="/") String 
getB01(@Query(name="x",_default="foo") String b);
+               @RemoteMethod(path="/") String 
getB02(@Query(name="x",_default="foo",allowEmptyValue=true) String b);
+               @RemoteMethod(path="/") String 
getB03(@Query(name="x",_default="") String b);
+               @RemoteMethod(path="/") String 
getB04(@Query(name="x",_default="",allowEmptyValue=true) String b);
+       }
+
+       private static BR br = 
RestClient.create().mockHttpConnection(b).build().getRemoteResource(BR.class);
+
+       @Test
+       public void b01a_default() throws Exception {
+               assertEquals("{x:'foo'}", br.getB01(null));
+       }
+       @Test
+       public void b01b_default_emptyString() throws Exception {
+               try {
+                       br.getB01("");
+               } catch (Exception e) {
+                       assertContains(e, "Empty value not allowed");
+               }
+       }
+       @Test
+       public void b02a_default_allowEmptyValue() throws Exception {
+               assertEquals("{x:'foo'}", br.getB02(null));
+       }
+       @Test
+       public void b02b_default_allowEmptyValue_emptyString() throws Exception 
{
+               assertEquals("{x:''}", br.getB02(""));
+       }
+       @Test
+       public void b03a_defaultIsBlank() throws Exception {
+               assertEquals("{x:''}", br.getB03(null));
+       }
+       @Test
+       public void b03b_defaultIsBlank_emptyString() throws Exception {
+               try {
+                       br.getB03("");
+               } catch (Exception e) {
+                       assertContains(e, "Empty value not allowed");
+               }
+       }
+       @Test
+       public void b04a_defaultIsBlank_allowEmptyValue() throws Exception {
+               assertEquals("{x:''}", br.getB04(null));
+       }
+       @Test
+       public void b04b_defaultIsBlank_allowEmptyValue_emptyString() throws 
Exception {
+               assertEquals("{x:''}", br.getB04(""));
+       }
 }

Reply via email to