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 8b1a170  org.apache.juneau.http tests.
8b1a170 is described below

commit 8b1a17079b2f8956ce4665d76c8203a3dc5ba420
Author: JamesBognar <[email protected]>
AuthorDate: Fri Jul 10 16:57:58 2020 -0400

    org.apache.juneau.http tests.
---
 .../org/apache/juneau/http/BasicHttpResource.java  |  31 ++++-
 .../org/apache/juneau/http/BasicNameValuePair.java |   4 +-
 .../org/apache/juneau/http/ReaderResource.java     |  20 +++
 .../org/apache/juneau/http/SerializedHeader.java   |  72 ++++++++--
 .../juneau/http/SerializedHeaderBuilder.java       | 128 ------------------
 .../juneau/http/SerializedNameValuePair.java       |  89 +++++++++---
 .../http/SerializedNameValuePairBuilder.java       | 138 -------------------
 .../org/apache/juneau/http/StreamResource.java     |  18 +++
 .../org/apache/juneau/http/BasicHeader_Test.java   |   4 +-
 .../apache/juneau/http/BasicHttpResource_Test.java | 102 ++++++++++++++
 .../juneau/http/BasicNameValuePair_Test.java       |   4 +-
 .../apache/juneau/http/ReaderResource_Test.java    |  90 ++++++++++++-
 .../apache/juneau/http/StreamResource_Test.java    | 113 ++++++++++++++++
 .../juneau/rest/client2/RestClient_Body_Test.java  | 150 +++++++++++++++++++++
 .../rest/client2/RestClient_FormData_Test.java     |   2 +-
 .../rest/client2/RestClient_Headers_Test.java      |   4 +-
 .../org/apache/juneau/rest/client2/RestClient.java |   8 +-
 .../juneau/rest/client2/RestClientBuilder.java     |   8 +-
 .../apache/juneau/rest/mock2/MockRestClient.java   |  13 +-
 19 files changed, 676 insertions(+), 322 deletions(-)

diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicHttpResource.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicHttpResource.java
index c9b4ce4..cea51c9 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicHttpResource.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicHttpResource.java
@@ -41,6 +41,26 @@ public class BasicHttpResource extends AbstractHttpEntity 
implements HttpResourc
        }
 
        /**
+        * Creator.
+        *
+        * @param content
+        *      The content.
+        *      <br>Can be any of the following:
+        *      <ul>
+        *              <li><c>InputStream</c>
+        *              <li><c>Reader</c> - Converted to UTF-8 bytes.
+        *              <li><c>File</c>
+        *              <li><c>CharSequence</c> - Converted to UTF-8 bytes.
+        *              <li><c><jk>byte</jk>[]</c>.
+        *      </ul>
+        * </ul>
+        * @return A new empty {@link ReaderResource} object.
+        */
+       public static BasicHttpResource of(Object content) {
+               return new BasicHttpResource().content(content);
+       }
+
+       /**
         * Constructor.
         */
        public BasicHttpResource() {
@@ -181,7 +201,7 @@ public class BasicHttpResource extends AbstractHttpEntity 
implements HttpResourc
         * @return The header value or <jk>null</jk> if header was not found.
         */
        public String getStringHeader(String name) {
-               Header h = getFirstHeader(name);
+               Header h = getLastHeader(name);
                return h == null ? null : h.getValue();
        }
 
@@ -240,10 +260,8 @@ public class BasicHttpResource extends AbstractHttpEntity 
implements HttpResourc
        @Override
        public long getContentLength() {
                try {
-                       doCache();
-               } catch (IOException e) {
-                       throw new RuntimeException(e);
-               }
+                       tryCache();
+               } catch (IOException e) {}
                if (content instanceof byte[])
                        return ((byte[])content).length;
                if (content instanceof File)
@@ -255,6 +273,7 @@ public class BasicHttpResource extends AbstractHttpEntity 
implements HttpResourc
 
        @Override
        public InputStream getContent() throws IOException, 
UnsupportedOperationException {
+               tryCache();
                if (content == null)
                        return null;
                if (content instanceof File)
@@ -280,7 +299,7 @@ public class BasicHttpResource extends AbstractHttpEntity 
implements HttpResourc
                return (content instanceof InputStream || content instanceof 
Reader);
        }
 
-       private void doCache() throws IOException {
+       private void tryCache() throws IOException {
                if (cache)
                        if (content instanceof File || content instanceof 
InputStream || content instanceof Reader)
                                content = IOUtils.readBytes(content);
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicNameValuePair.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicNameValuePair.java
index b47d3b0..51f52f7 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicNameValuePair.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicNameValuePair.java
@@ -34,8 +34,8 @@ import org.apache.juneau.svl.*;
  */
 @BeanIgnore
 public class BasicNameValuePair implements NameValuePair, Headerable {
-       private String name;
-       private Object value;
+       private final String name;
+       private final Object value;
 
        /**
         * Convenience creator.
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
index c1d1595..86148fd 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResource.java
@@ -49,6 +49,26 @@ public class ReaderResource extends BasicHttpResource {
        }
 
        /**
+        * Creator.
+        *
+        * @param content
+        *      The content.
+        *      <br>Can be any of the following:
+        *      <ul>
+        *              <li><c>InputStream</c>
+        *              <li><c>Reader</c> - Converted to UTF-8 bytes.
+        *              <li><c>File</c>
+        *              <li><c>CharSequence</c> - Converted to UTF-8 bytes.
+        *              <li><c><jk>byte</jk>[]</c>.
+        *      </ul>
+        * </ul>
+        * @return A new empty {@link ReaderResource} object.
+        */
+       public static ReaderResource of(Object content) {
+               return new ReaderResource().content(content);
+       }
+
+       /**
         * Constructor.
         */
        public ReaderResource() {
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeader.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeader.java
index bd4ee05..5e0b97c 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeader.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeader.java
@@ -39,18 +39,27 @@ import org.apache.juneau.urlencoding.*;
 public class SerializedHeader extends BasicStringHeader implements 
NameValuePairable {
        private static final long serialVersionUID = 1L;
 
-       private Object value;
+       private final Object value;
        private HttpPartSerializerSession serializer;
-       private HttpPartSchema schema;
+       private HttpPartSchema schema = HttpPartSchema.DEFAULT;
        private boolean skipIfEmpty;
 
        /**
-        * Instantiates a new builder for this object.
+        * Instantiates a new instance of this object.
         *
-        * @return A new builder for this object.
+        * @return A new instance of this object.
         */
-       public static SerializedHeaderBuilder create() {
-               return new SerializedHeaderBuilder();
+       public static SerializedHeader of(String name, Object value) {
+               return new SerializedHeader(name, value, null, null, false);
+       }
+
+       /**
+        * Instantiates a new instance of this object.
+        *
+        * @return A new instance of this object.
+        */
+       public static SerializedHeader of(String name, Supplier<?> value) {
+               return new SerializedHeader(name, value, null, null, false);
        }
 
        /**
@@ -69,18 +78,57 @@ public class SerializedHeader extends BasicStringHeader 
implements NameValuePair
         * @param skipIfEmpty If value is a blank string, the value should 
return as <jk>null</jk>.
         */
        public SerializedHeader(String name, Object value, 
HttpPartSerializerSession serializer, HttpPartSchema schema, boolean 
skipIfEmpty) {
-               super(name, null);
+               super(name, value);
                this.value = value;
                this.serializer = serializer;
                this.schema = schema == null ? HttpPartSchema.DEFAULT : schema;
                this.skipIfEmpty = skipIfEmpty;
        }
 
-       SerializedHeader(SerializedHeaderBuilder b) {
-               super(b.name, null);
-               this.value = b.value;
-               this.serializer = b.serializer;
-               this.schema = b.schema == null ? HttpPartSchema.DEFAULT : 
b.schema;
+       /**
+        * Sets the serializer to use for serializing the value to a string 
value.
+        *
+        * @param value The new value for this property.
+        * @return This object (for method chaining).
+        */
+       public SerializedHeader serializer(HttpPartSerializer value) {
+               if (value != null)
+                       return serializer(value.createPartSession(null));
+               return this;
+       }
+
+       /**
+        * Sets the serializer to use for serializing the value to a string 
value.
+        *
+        * @param value The new value for this property.
+        * @return This object (for method chaining).
+        */
+       public SerializedHeader serializer(HttpPartSerializerSession value) {
+               return serializer(value, true);
+       }
+
+       /**
+        * Sets the serializer to use for serializing the value to a string 
value.
+        *
+        * @param value The new value for this property.
+        * @param overwrite If <jk>true</jk>, overwrites the existing value if 
the old value is <jk>null</jk>.
+        * @return This object (for method chaining).
+        */
+       public SerializedHeader serializer(HttpPartSerializerSession value, 
boolean overwrite) {
+               if (overwrite || serializer == null)
+                       this.serializer = value;
+               return this;
+       }
+
+       /**
+        * Sets the schema object that defines the format of the output.
+        *
+        * @param value The new value for this property.
+        * @return This object (for method chaining).
+        */
+       public SerializedHeader schema(HttpPartSchema value) {
+               this.schema = value;
+               return this;
        }
 
        @Override /* NameValuePair */
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeaderBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeaderBuilder.java
deleted file mode 100644
index 473ed9a..0000000
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedHeaderBuilder.java
+++ /dev/null
@@ -1,128 +0,0 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.http;
-
-import java.util.function.*;
-
-import org.apache.http.*;
-import org.apache.juneau.httppart.*;
-
-/**
- * Builder for {@link SerializedHeader} objects.
- */
-public class SerializedHeaderBuilder implements Headerable, NameValuePairable {
-       String name;
-       Object value;
-       HttpPartSerializerSession serializer;
-       HttpPartSchema schema;
-
-       /**
-        * Sets the parameter name.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedHeaderBuilder name(String value) {
-               this.name = value;
-               return this;
-       }
-
-       /**
-        * Sets the POJO to serialize to the parameter value.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedHeaderBuilder value(Object value) {
-               this.value = value;
-               return this;
-       }
-
-       /**
-        * Sets the POJO supplier to serialize to the parameter value.
-        * <p>
-        * Value is re-evaluated on each call to {@link Header#getValue()}.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedHeaderBuilder value(Supplier<?> value) {
-               this.value = value;
-               return this;
-       }
-
-       /**
-        * Sets the serializer to use for serializing the value to a string 
value.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedHeaderBuilder serializer(HttpPartSerializer value) {
-               if (value != null)
-                       return serializer(value.createPartSession(null));
-               return this;
-       }
-
-       /**
-        * Sets the serializer to use for serializing the value to a string 
value.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedHeaderBuilder serializer(HttpPartSerializerSession 
value) {
-               return serializer(value, true);
-       }
-
-       /**
-        * Sets the serializer to use for serializing the value to a string 
value.
-        *
-        * @param value The new value for this property.
-        * @param overwrite If <jk>true</jk>, overwrites the existing value if 
the old value is <jk>null</jk>.
-        * @return This object (for method chaining).
-        */
-       public SerializedHeaderBuilder serializer(HttpPartSerializerSession 
value, boolean overwrite) {
-               if (overwrite || serializer == null)
-                       this.serializer = value;
-               return this;
-       }
-
-       /**
-        * Sets the schema object that defines the format of the output.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedHeaderBuilder schema(HttpPartSchema value) {
-               this.schema = value;
-               return this;
-       }
-
-       /**
-        * Creates the new {@link SerializedHeader}
-        *
-        * @return The new {@link SerializedHeader}
-        */
-       public SerializedHeader build() {
-               return new SerializedHeader(this);
-       }
-
-       @Override /* Headerable */
-       public Header asHeader() {
-               return build();
-       }
-
-       @Override /* Headerable */
-       public Header asNameValuePair() {
-               return build();
-       }
-}
\ No newline at end of file
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePair.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePair.java
index caa4b3a..4d366d2 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePair.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePair.java
@@ -36,19 +36,28 @@ import org.apache.juneau.urlencoding.*;
  * </p>
  */
 public class SerializedNameValuePair extends BasicNameValuePair implements 
Headerable {
-       private Object value;
+       private final Object value;
        private HttpPartType type;
        private HttpPartSerializerSession serializer;
-       private HttpPartSchema schema;
+       private HttpPartSchema schema = HttpPartSchema.DEFAULT;
        private boolean skipIfEmpty;
 
        /**
-        * Instantiates a new builder for this object.
+        * Instantiates a new instance of this object.
         *
-        * @return A new builder for this object.
+        * @return A new instance of this object.
         */
-       public static SerializedNameValuePairBuilder create() {
-               return new SerializedNameValuePairBuilder();
+       public static SerializedNameValuePair of(String name, Object value) {
+               return new SerializedNameValuePair(name, value, null, null, 
null, false);
+       }
+
+       /**
+        * Instantiates a new instance of this object.
+        *
+        * @return A new instance of this object.
+        */
+       public static SerializedNameValuePair of(String name, Supplier<?> 
value) {
+               return new SerializedNameValuePair(name, value, null, null, 
null, false);
        }
 
        /**
@@ -67,7 +76,7 @@ public class SerializedNameValuePair extends 
BasicNameValuePair implements Heade
         * @param skipIfEmpty If value is a blank string, the value should 
return as <jk>null</jk>.
         */
        public SerializedNameValuePair(String name, Object value, HttpPartType 
type, HttpPartSerializerSession serializer, HttpPartSchema schema, boolean 
skipIfEmpty) {
-               super(name, null);
+               super(name, value);
                this.value = value;
                this.type = type;
                this.serializer = serializer;
@@ -75,19 +84,69 @@ public class SerializedNameValuePair extends 
BasicNameValuePair implements Heade
                this.skipIfEmpty = skipIfEmpty;
        }
 
+       /**
+        * Sets the HTTP part type.
+        *
+        * @param value The new value for this property.
+        * @return This object (for method chaining).
+        */
+       public SerializedNameValuePair type(HttpPartType value) {
+               this.type = value;
+               return this;
+       }
+
+       /**
+        * Sets the serializer to use for serializing the value to a string 
value.
+        *
+        * @param value The new value for this property.
+        * @return This object (for method chaining).
+        */
+       public SerializedNameValuePair serializer(HttpPartSerializer value) {
+               if (value != null)
+                       return serializer(value.createPartSession(null));
+               return this;
+       }
+
+       /**
+        * Sets the serializer to use for serializing the value to a string 
value.
+        *
+        * @param value The new value for this property.
+        * @return This object (for method chaining).
+        */
+       public SerializedNameValuePair serializer(HttpPartSerializerSession 
value) {
+               return serializer(value, true);
+       }
+
+       /**
+        * Sets the serializer to use for serializing the value to a string 
value.
+        *
+        * @param value The new value for this property.
+        * @param overwrite If <jk>true</jk>, overwrites the existing value if 
the old value is <jk>null</jk>.
+        * @return This object (for method chaining).
+        */
+       public SerializedNameValuePair serializer(HttpPartSerializerSession 
value, boolean overwrite) {
+               if (overwrite || serializer == null)
+                       this.serializer = value;
+               return this;
+       }
+
+       /**
+        * Sets the schema object that defines the format of the output.
+        *
+        * @param value The new value for this property.
+        * @return This object (for method chaining).
+        */
+       public SerializedNameValuePair schema(HttpPartSchema value) {
+               this.schema = value;
+               return this;
+       }
+
+
        @Override /* Headerable */
        public SerializedHeader asHeader() {
                return new SerializedHeader(getName(), value, serializer, 
schema, skipIfEmpty);
        }
 
-       SerializedNameValuePair(SerializedNameValuePairBuilder b) {
-               super(b.name, null);
-               this.value = b.value;
-               this.type = b.type;
-               this.serializer = b.serializer;
-               this.schema = b.schema == null ? HttpPartSchema.DEFAULT : 
b.schema;
-       }
-
        @Override /* NameValuePair */
        public String getValue() {
                try {
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePairBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePairBuilder.java
deleted file mode 100644
index f51a5da..0000000
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/SerializedNameValuePairBuilder.java
+++ /dev/null
@@ -1,138 +0,0 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.http;
-
-import java.util.function.*;
-
-import org.apache.http.*;
-import org.apache.juneau.httppart.*;
-
-/**
- * Builder for {@link SerializedNameValuePair} objects.
- */
-public class SerializedNameValuePairBuilder implements NameValuePairable, 
Headerable {
-       String name;
-       Object value;
-       HttpPartType type;
-       HttpPartSerializerSession serializer;
-       HttpPartSchema schema;
-
-       /**
-        * Sets the parameter name.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedNameValuePairBuilder name(String value) {
-               this.name = value;
-               return this;
-       }
-
-       /**
-        * Sets the POJO to serialize to the parameter value.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedNameValuePairBuilder value(Object value) {
-               this.value = value;
-               return this;
-       }
-
-       /**
-        * Sets the POJO to serialize to the parameter value.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedNameValuePairBuilder value(Supplier<Object> value) {
-               this.value = value;
-               return this;
-       }
-
-       /**
-        * Sets the HTTP part type.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedNameValuePairBuilder type(HttpPartType value) {
-               this.type = value;
-               return this;
-       }
-
-       /**
-        * Sets the serializer to use for serializing the value to a string 
value.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedNameValuePairBuilder serializer(HttpPartSerializer 
value) {
-               if (value != null)
-                       return serializer(value.createPartSession(null));
-               return this;
-       }
-
-       /**
-        * Sets the serializer to use for serializing the value to a string 
value.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedNameValuePairBuilder 
serializer(HttpPartSerializerSession value) {
-               return serializer(value, true);
-       }
-
-       /**
-        * Sets the serializer to use for serializing the value to a string 
value.
-        *
-        * @param value The new value for this property.
-        * @param overwrite If <jk>true</jk>, overwrites the existing value if 
the old value is <jk>null</jk>.
-        * @return This object (for method chaining).
-        */
-       public SerializedNameValuePairBuilder 
serializer(HttpPartSerializerSession value, boolean overwrite) {
-               if (overwrite || serializer == null)
-                       this.serializer = value;
-               return this;
-       }
-
-       /**
-        * Sets the schema object that defines the format of the output.
-        *
-        * @param value The new value for this property.
-        * @return This object (for method chaining).
-        */
-       public SerializedNameValuePairBuilder schema(HttpPartSchema value) {
-               this.schema = value;
-               return this;
-       }
-
-       /**
-        * Creates the new {@link SerializedNameValuePair}
-        *
-        * @return The new {@link SerializedNameValuePair}
-        */
-       public SerializedNameValuePair build() {
-               return new SerializedNameValuePair(this);
-       }
-
-       @Override /* NameValuePairable */
-       public NameValuePair asNameValuePair() {
-               return build();
-       }
-
-       @Override /* Headerable */
-       public Header asHeader() {
-               return build().asHeader();
-       }
-}
\ No newline at end of file
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
index 2115ec1..1dfad8f 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResource.java
@@ -48,6 +48,24 @@ public class StreamResource extends BasicHttpResource {
        }
 
        /**
+        * Creator.
+        *
+        * @param content
+        *      The content.
+        *      <br>Can be any of the following:
+        *      <ul>
+        *              <li><c>InputStream</c>
+        *              <li><c>File</c>
+        *              <li><c><jk>byte</jk>[]</c>.
+        *      </ul>
+        * </ul>
+        * @return A new empty {@link ReaderResource} object.
+        */
+       public static StreamResource of(Object content) {
+               return new StreamResource().content(content);
+       }
+
+       /**
         * Constructor.
         */
        public StreamResource() {
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/BasicHeader_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/BasicHeader_Test.java
index 92ed4a0..eba86ca 100644
--- 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/BasicHeader_Test.java
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/BasicHeader_Test.java
@@ -60,9 +60,9 @@ public class BasicHeader_Test {
        @Test
        public void a03_cast() {
                BasicNameValuePair x1 = pair("X1","1");
-               SerializedNameValuePairBuilder x2 = 
SerializedNameValuePair.create().name("X2").value("2");
+               SerializedNameValuePair x2 = 
SerializedNameValuePair.of("X2","2");
                Header x3 = header("X3","3");
-               SerializedHeaderBuilder x4 = 
SerializedHeader.create().name("X4").value("4");
+               SerializedHeader x4 = SerializedHeader.of("X4","4");
                Map.Entry<String,Object> x5 = 
AMap.of("X5",(Object)"5").entrySet().iterator().next();
                org.apache.http.message.BasicNameValuePair x6 = new 
org.apache.http.message.BasicNameValuePair("X6","6");
                NameValuePairable x7 = new NameValuePairable() {
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/BasicHttpResource_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/BasicHttpResource_Test.java
new file mode 100644
index 0000000..a6a71c6
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/BasicHttpResource_Test.java
@@ -0,0 +1,102 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.http;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.apache.juneau.http.BasicHttpResource.*;
+import static org.junit.Assert.*;
+
+import java.io.*;
+
+import org.junit.*;
+
+public class BasicHttpResource_Test {
+       @Test
+       public void a01_basic() throws Exception {
+               BasicHttpResource x = create();
+               File f = File.createTempFile("test", "txt");
+
+               assertNull(x.getContentType());
+               assertNull(x.getContent());
+               assertNull(x.getContentEncoding());
+               assertList(x.getHeaders()).isSize(0);
+
+               x = of("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of(new StringReader("foo"));
+               assertStream(x.getContent()).string().is("foo");
+               assertFalse(x.isRepeatable());
+               assertTrue(x.isStreaming());
+
+               x = of("foo".getBytes());
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of(new ByteArrayInputStream("foo".getBytes()));
+               assertStream(x.getContent()).string().is("foo");
+               assertFalse(x.isRepeatable());
+               assertTrue(x.isStreaming());
+
+               x = of(null);
+               assertStream(x.getContent()).string().doesNotExist();
+               assertFalse(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of(f);
+               assertStream(x.getContent()).string().isEmpty();
+               assertTrue(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of("foo").cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of(new StringReader("foo")).cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of("foo".getBytes()).cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of(new ByteArrayInputStream("foo".getBytes())).cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of(null).cache();
+               assertStream(x.getContent()).string().doesNotExist();
+               assertStream(x.getContent()).string().doesNotExist();
+               assertTrue(x.isRepeatable());
+
+               assertLong(of("foo").getContentLength()).is(3l);
+               assertLong(of("foo".getBytes()).getContentLength()).is(3l);
+               assertLong(of(f).getContentLength()).is(0l);
+
+               x = of("foo").header("Foo","bar").header("Foo","baz");
+               assertString(x.getStringHeader("Foo")).is("baz");
+               assertString(x.getStringHeader("Bar")).doesNotExist();
+               assertString(x.getFirstHeader("Foo").toString()).is("Foo: bar");
+               assertString(x.getLastHeader("Foo").toString()).is("Foo: baz");
+               assertObject(x.getFirstHeader("Bar")).doesNotExist();
+               assertObject(x.getLastHeader("Bar")).doesNotExist();
+               assertObject(x.getHeaders()).json().is("['Foo: bar','Foo: 
baz']");
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/BasicNameValuePair_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/BasicNameValuePair_Test.java
index f64173a..699baea 100644
--- 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/BasicNameValuePair_Test.java
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/BasicNameValuePair_Test.java
@@ -59,9 +59,9 @@ public class BasicNameValuePair_Test {
        @Test
        public void a03_cast() {
                BasicNameValuePair x1 = pair("X1","1");
-               SerializedNameValuePairBuilder x2 = 
SerializedNameValuePair.create().name("X2").value("2");
+               SerializedNameValuePair x2 = 
SerializedNameValuePair.of("X2","2");
                Header x3 = header("X3","3");
-               SerializedHeaderBuilder x4 = 
SerializedHeader.create().name("X4").value("4");
+               SerializedHeader x4 = SerializedHeader.of("X4","4");
                Map.Entry<String,Object> x5 = 
AMap.of("X5",(Object)"5").entrySet().iterator().next();
                org.apache.http.message.BasicNameValuePair x6 = new 
org.apache.http.message.BasicNameValuePair("X6","6");
                NameValuePairable x7 = new NameValuePairable() {
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/ReaderResource_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/ReaderResource_Test.java
index 6fe733a..dbfcc94 100644
--- 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/ReaderResource_Test.java
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/ReaderResource_Test.java
@@ -16,6 +16,10 @@ import static org.apache.juneau.assertions.Assertions.*;
 import static org.junit.Assert.*;
 import static org.junit.runners.MethodSorters.*;
 
+import static org.apache.juneau.http.ReaderResource.*;
+
+import java.io.*;
+
 import org.junit.*;
 
 @FixMethodOrder(NAME_ASCENDING)
@@ -23,11 +27,87 @@ public class ReaderResource_Test {
 
        @Test
        public void a01_basic() throws Exception {
-               ReaderResource rr = ReaderResource.create();
+               ReaderResource x = create();
+               File f = File.createTempFile("test","txt");
+
+               assertNull(x.getContentType());
+               assertNull(x.getContent());
+               assertNull(x.getContentEncoding());
+               assertList(x.getHeaders()).isSize(0);
+
+               of("foo").assertString().is("foo");
+               of(new StringReader("foo")).assertString().is("foo");
+               of("foo".getBytes()).assertString().is("foo");
+               of(new 
ByteArrayInputStream("foo".getBytes())).assertString().is("foo");
+               of(null).assertString().doesNotExist();
+               of(f).assertString().isEmpty();
+
+               x = of("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of(new StringReader("foo"));
+               assertStream(x.getContent()).string().is("foo");
+               assertFalse(x.isRepeatable());
+               assertTrue(x.isStreaming());
+
+               x = of("foo".getBytes());
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of(new ByteArrayInputStream("foo".getBytes()));
+               assertStream(x.getContent()).string().is("foo");
+               assertFalse(x.isRepeatable());
+               assertTrue(x.isStreaming());
+
+               x = of(null);
+               assertStream(x.getContent()).string().doesNotExist();
+               assertFalse(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of(f);
+               assertStream(x.getContent()).string().isEmpty();
+               assertTrue(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of("foo").cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of(new StringReader("foo")).cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of("foo".getBytes()).cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of(new ByteArrayInputStream("foo".getBytes())).cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of(null).cache();
+               assertStream(x.getContent()).string().doesNotExist();
+               assertStream(x.getContent()).string().doesNotExist();
+               assertTrue(x.isRepeatable());
+
+               assertLong(of("foo").getContentLength()).is(3l);
+               assertLong(of("foo".getBytes()).getContentLength()).is(3l);
+               assertLong(of(f).getContentLength()).is(0l);
 
-               assertNull(rr.getContentType());
-               assertNull(rr.getContent());
-               assertNull(rr.getContentEncoding());
-               assertList(rr.getHeaders()).isSize(0);
+               x = of("foo").header("Foo","bar").header("Foo","baz");
+               assertString(x.getStringHeader("Foo")).is("baz");
+               assertString(x.getStringHeader("Bar")).doesNotExist();
+               assertString(x.getFirstHeader("Foo").toString()).is("Foo: bar");
+               assertString(x.getLastHeader("Foo").toString()).is("Foo: baz");
+               assertObject(x.getFirstHeader("Bar")).doesNotExist();
+               assertObject(x.getLastHeader("Bar")).doesNotExist();
+               assertObject(x.getHeaders()).json().is("['Foo: bar','Foo: 
baz']");
        }
 }
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/StreamResource_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/StreamResource_Test.java
new file mode 100644
index 0000000..d332514
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/http/StreamResource_Test.java
@@ -0,0 +1,113 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.http;
+
+import static org.apache.juneau.assertions.Assertions.*;
+import static org.junit.Assert.*;
+import static org.junit.runners.MethodSorters.*;
+
+import static org.apache.juneau.http.StreamResource.*;
+
+import java.io.*;
+
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class StreamResource_Test {
+
+       @Test
+       public void a01_basic() throws Exception {
+               StreamResource x = create();
+               File f = File.createTempFile("test","txt");
+
+               assertNull(x.getContentType());
+               assertNull(x.getContent());
+               assertNull(x.getContentEncoding());
+               assertList(x.getHeaders()).isSize(0);
+
+               of("foo").assertBytes().string().is("foo");
+               of(new StringReader("foo")).assertBytes().string().is("foo");
+               of("foo".getBytes()).assertBytes().string().is("foo");
+               of(new 
ByteArrayInputStream("foo".getBytes())).assertBytes().string().is("foo");
+               of(null).assertBytes().string().isEmpty();
+               of(f).assertBytes().string().isEmpty();
+
+               x = of("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of(new StringReader("foo"));
+               assertStream(x.getContent()).string().is("foo");
+               assertFalse(x.isRepeatable());
+               assertTrue(x.isStreaming());
+
+               x = of("foo".getBytes());
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of(new ByteArrayInputStream("foo".getBytes()));
+               assertStream(x.getContent()).string().is("foo");
+               assertFalse(x.isRepeatable());
+               assertTrue(x.isStreaming());
+
+               x = of(null);
+               assertStream(x.getContent()).string().doesNotExist();
+               assertFalse(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of(f);
+               assertStream(x.getContent()).string().isEmpty();
+               assertTrue(x.isRepeatable());
+               assertFalse(x.isStreaming());
+
+               x = of("foo").cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of(new StringReader("foo")).cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of("foo".getBytes()).cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of(new ByteArrayInputStream("foo".getBytes())).cache();
+               assertStream(x.getContent()).string().is("foo");
+               assertStream(x.getContent()).string().is("foo");
+               assertTrue(x.isRepeatable());
+
+               x = of(null).cache();
+               assertStream(x.getContent()).string().doesNotExist();
+               assertStream(x.getContent()).string().doesNotExist();
+               assertTrue(x.isRepeatable());
+
+               assertLong(of("foo").getContentLength()).is(3l);
+               assertLong(of("foo".getBytes()).getContentLength()).is(3l);
+               assertLong(of(f).getContentLength()).is(0l);
+
+               x = of("foo").header("Foo","bar").header("Foo","baz");
+               assertString(x.getStringHeader("Foo")).is("baz");
+               assertString(x.getStringHeader("Bar")).doesNotExist();
+               assertString(x.getFirstHeader("Foo").toString()).is("Foo: bar");
+               assertString(x.getLastHeader("Foo").toString()).is("Foo: baz");
+               assertObject(x.getFirstHeader("Bar")).doesNotExist();
+               assertObject(x.getLastHeader("Bar")).doesNotExist();
+               assertObject(x.getHeaders()).json().is("['Foo: bar','Foo: 
baz']");
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Body_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Body_Test.java
new file mode 100644
index 0000000..99a8bd3
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Body_Test.java
@@ -0,0 +1,150 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.rest.client2;
+
+import static org.junit.runners.MethodSorters.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.http.*;
+import org.apache.juneau.http.*;
+import org.apache.juneau.http.header.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.mock2.*;
+import org.junit.*;
+
+@FixMethodOrder(NAME_ASCENDING)
+public class RestClient_Body_Test {
+
+       @Rest
+       public static class A extends BasicRest {
+               @RestMethod
+               public Reader post(org.apache.juneau.rest.RestRequest req) 
throws IOException {
+                       return new StringReader(req.toString());
+               }
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Method tests
+       
//------------------------------------------------------------------------------------------------------------------
+
+       @Test
+       public void a01_ReaderResource() throws Exception {
+               ReaderResource x1 = ReaderResource.create().content("foo");
+               client().build().post("/", x1).run()
+                       .getBody().assertString().contains("foo", 
"Content-Length: 3")
+                       
.getBody().assertString().doesNotContain("Content-Encoding","Content-Type","Transfer-Encoding")
+               ;
+
+               ReaderResource x2 = 
ReaderResource.create().content("foo").contentType("text/plain").contentEncoding("identity");
+               client().build().post("/",x2).run()
+                       
.getBody().assertString().contains("foo","Content-Length: 3","Content-Encoding: 
identity","Content-Type: text/plain")
+               ;
+
+               ReaderResource x3 = 
ReaderResource.create().content("foo").contentType(contentType("text/plain")).contentEncoding(contentEncoding("identity")).chunked();
+               client().build().post("/",x3).run()
+                       
.getBody().assertString().contains("foo","Content-Encoding: 
identity","Content-Type: text/plain","Transfer-Encoding: chunked")
+               ;
+
+               ReaderResource x4 = new 
ReaderResource(contentType("text/plain"), contentEncoding("identity"), "foo");
+               client().build().post("/",x4).run()
+                       
.getBody().assertString().contains("foo","Content-Length: 3","Content-Encoding: 
identity","Content-Type: text/plain")
+               ;
+
+               ReaderResource x5 = 
ReaderResource.of("foo").header("Foo","bar").header(header("Baz","qux"));
+               client().build().post("/",x5).run()
+                       .getBody().assertString().contains("Foo: bar","Baz: 
qux")
+               ;
+
+               ReaderResource x6 = 
ReaderResource.of("foo").headers(Arrays.asList(header("Foo","bar"),header("Baz","qux")));
+               client().build().post("/",x6).run()
+                       .getBody().assertString().contains("Foo: bar","Baz: 
qux")
+               ;
+
+               ReaderResource x7 = ReaderResource.of(new StringReader("foo"));
+               
client().build().post("/",x7).run().getBody().assertString().contains("foo");
+
+               ReaderResource x8 = ReaderResource.of(new 
StringReader("foo")).cache();
+               
client().build().post("/",x8).run().getBody().assertString().contains("foo");
+               
client().build().post("/",x8).run().getBody().assertString().contains("foo");
+
+               ReaderResource x9 = ReaderResource.of(null);
+               
client().build().post("/",x9).run().getBody().assertString().contains("HTTP 
POST");
+       }
+
+       @Test
+       public void a02_StreamResource() throws Exception {
+               StreamResource x1 = StreamResource.create().content("foo");
+               client().build().post("/", x1).run()
+                       .getBody().assertString().contains("foo", 
"Content-Length: 3")
+                       
.getBody().assertString().doesNotContain("Content-Encoding","Content-Type","Transfer-Encoding")
+               ;
+
+               StreamResource x2 = 
StreamResource.create().content("foo").contentType("text/plain").contentEncoding("identity");
+               client().build().post("/",x2).run()
+                       
.getBody().assertString().contains("foo","Content-Length: 3","Content-Encoding: 
identity","Content-Type: text/plain")
+               ;
+
+               StreamResource x3 = 
StreamResource.create().content("foo").contentType(contentType("text/plain")).contentEncoding(contentEncoding("identity")).chunked();
+               client().build().post("/",x3).run()
+                       
.getBody().assertString().contains("foo","Content-Encoding: 
identity","Content-Type: text/plain","Transfer-Encoding: chunked")
+               ;
+
+               StreamResource x4 = new 
StreamResource(contentType("text/plain"), contentEncoding("identity"), "foo");
+               client().build().post("/",x4).run()
+                       
.getBody().assertString().contains("foo","Content-Length: 3","Content-Encoding: 
identity","Content-Type: text/plain")
+               ;
+
+               StreamResource x5 = 
StreamResource.of("foo").header("Foo","bar").header(header("Baz","qux"));
+               client().build().post("/",x5).run()
+                       .getBody().assertString().contains("Foo: bar","Baz: 
qux")
+               ;
+
+               StreamResource x6 = 
StreamResource.of("foo").headers(Arrays.asList(header("Foo","bar"),header("Baz","qux")));
+               client().build().post("/",x6).run()
+                       .getBody().assertString().contains("Foo: bar","Baz: 
qux")
+               ;
+
+               StreamResource x7 = StreamResource.of(new StringReader("foo"));
+               
client().build().post("/",x7).run().getBody().assertString().contains("foo");
+
+               StreamResource x8 = StreamResource.of(new 
StringReader("foo")).cache();
+               
client().build().post("/",x8).run().getBody().assertString().contains("foo");
+               
client().build().post("/",x8).run().getBody().assertString().contains("foo");
+
+               StreamResource x9 = StreamResource.of(null);
+               
client().build().post("/",x9).run().getBody().assertString().contains("HTTP 
POST");
+       }
+
+       
//------------------------------------------------------------------------------------------------------------------
+       // Helper methods.
+       
//------------------------------------------------------------------------------------------------------------------
+
+       private static RestClientBuilder client() {
+               return MockRestClient.create(A.class).simpleJson();
+       }
+
+       private static Header header(String name, Object val) {
+               return BasicHeader.of(name,val);
+       }
+
+       private static ContentType contentType(String val) {
+               return ContentType.of(val);
+       }
+
+       private static ContentEncoding contentEncoding(String val) {
+               return ContentEncoding.of(val);
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_FormData_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_FormData_Test.java
index 8546ab4..31aae74 100644
--- 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_FormData_Test.java
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_FormData_Test.java
@@ -101,7 +101,7 @@ public class RestClient_FormData_Test {
                
client().build().post("/formData").formDatas(pair(null,"foo")).run().assertBody().is("null=foo");
                
client().build().post("/formData").formDatas(pair(null,null)).run().assertBody().is("");
 
-               
client().formDatas(SerializedHeader.create().name("foo").value("bar")).build().post("/formData").run().assertBody().is("foo=bar");
+               
client().formDatas(SerializedHeader.of("foo","bar")).build().post("/formData").run().assertBody().is("foo=bar");
 
                
assertThrown(()->client().build().post("/formData").formDatas("bad")).is("Invalid
 type passed to formDatas(): java.lang.String");
                
assertThrown(()->client().formDatas(pair("foo","bar"),"baz")).is("Invalid type 
passed to formData():  java.lang.String");
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Headers_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Headers_Test.java
index 7da1316..1ad982e 100644
--- 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Headers_Test.java
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_Headers_Test.java
@@ -110,8 +110,8 @@ public class RestClient_Headers_Test {
                
checkFooClient().headers(OMap.of("Foo","bar")).build().get("/headers").headers(OMap.of("Foo","baz")).run().assertBody().is("['bar','baz']");
                
checkFooClient().headers(AMap.of("Foo","bar")).build().get("/headers").headers(AMap.of("Foo","baz")).run().assertBody().is("['bar','baz']");
                
checkFooClient().headers(pair("Foo","bar")).build().get("/headers").headers(pair("Foo","baz")).run().assertBody().is("['bar','baz']");
-               
checkFooClient().headers(SerializedNameValuePair.create().name("Foo").value("Bar").serializer(OpenApiSerializer.DEFAULT)).build().get("/headers").headers(SerializedNameValuePair.create().name("Foo").value("Baz").serializer(OpenApiSerializer.DEFAULT)).debug().run().assertBody().is("['Bar','Baz']");
-               
checkFooClient().headers(SerializedHeader.create().name("Foo").value("Bar").serializer(OpenApiSerializer.DEFAULT)).build().get("/headers").headers(SerializedHeader.create().name("Foo").value("Baz").serializer(OpenApiSerializer.DEFAULT)).debug().run().assertBody().is("['Bar','Baz']");
+               
checkFooClient().headers(SerializedNameValuePair.of("Foo","Bar").serializer(OpenApiSerializer.DEFAULT)).build().get("/headers").headers(SerializedNameValuePair.of("Foo","Baz").serializer(OpenApiSerializer.DEFAULT)).debug().run().assertBody().is("['Bar','Baz']");
+               
checkFooClient().headers(SerializedHeader.of("Foo","Bar").serializer(OpenApiSerializer.DEFAULT)).build().get("/headers").headers(SerializedHeader.of("Foo","Baz").serializer(OpenApiSerializer.DEFAULT)).debug().run().assertBody().is("['Bar','Baz']");
                checkFooClient().headers((Object)new 
Header[]{header("Foo","bar")}).build().get("/headers").headers((Object)new 
Header[]{header("Foo","baz")}).debug().run().assertBody().is("['bar','baz']");
                
checkFooClient().headers(HeaderSupplier.of(header("Foo","bar"))).build().get("/headers").headers(HeaderSupplier.of(header("Foo","baz"))).run().assertBody().is("['bar','baz']");
                
checkFooClient().headers(AList.of(header("Foo","bar"))).build().get("/headers").headers(AList.of(header("Foo","baz"))).run().assertBody().is("['bar','baz']");
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
index 8325854..ad4a25d 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
@@ -2098,10 +2098,10 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
        }
 
        private static Object buildBuilders(Object o, HttpPartSerializerSession 
ss) {
-               if (o instanceof SerializedHeaderBuilder)
-                       return ((SerializedHeaderBuilder)o).serializer(ss, 
false).build();
-               if (o instanceof SerializedNameValuePairBuilder)
-                       return 
((SerializedNameValuePairBuilder)o).serializer(ss, false).build();
+               if (o instanceof SerializedHeader)
+                       return ((SerializedHeader)o).serializer(ss, false);
+               if (o instanceof SerializedNameValuePair)
+                       return ((SerializedNameValuePair)o).serializer(ss, 
false);
                return o;
        }
 
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java
index 6951e4f..e41f116 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java
@@ -5775,11 +5775,11 @@ public class RestClientBuilder extends 
BeanContextBuilder {
                return (Map<Object,Object>)o;
        }
 
-       private static SerializedNameValuePairBuilder 
serializedNameValuePair(Object key, Object value, HttpPartType type, 
HttpPartSerializer serializer, HttpPartSchema schema) {
-               return key == null ? null : 
SerializedNameValuePair.create().name(stringify(key)).value(value).type(type).serializer(serializer).schema(schema);
+       private static SerializedNameValuePair serializedNameValuePair(Object 
key, Object value, HttpPartType type, HttpPartSerializer serializer, 
HttpPartSchema schema) {
+               return key == null ? null : 
SerializedNameValuePair.of(stringify(key),value).type(type).serializer(serializer).schema(schema);
        }
 
-       private static SerializedHeaderBuilder serializedHeader(Object key, 
Object value, HttpPartSerializer serializer, HttpPartSchema schema) {
-               return key == null ? null : 
SerializedHeader.create().name(stringify(key)).value(value).serializer(serializer).schema(schema);
+       private static SerializedHeader serializedHeader(Object key, Object 
value, HttpPartSerializer serializer, HttpPartSchema schema) {
+               return key == null ? null : 
SerializedHeader.of(stringify(key),value).serializer(serializer).schema(schema);
        }
 }
diff --git 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java
 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java
index 2f5fb3b..6f05db4 100644
--- 
a/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java
+++ 
b/juneau-rest/juneau-rest-mock/src/main/java/org/apache/juneau/rest/mock2/MockRestClient.java
@@ -737,7 +737,18 @@ public class MockRestClient extends RestClient implements 
HttpClientConnection {
 
        @Override /* HttpClientConnection */
        public void sendRequestEntity(HttpEntityEnclosingRequest request) 
throws HttpException, IOException {
-               sreq.get().body(request.getEntity() == null ? "" : 
IOUtils.readBytes(request.getEntity().getContent(), 1024));
+               byte[] body = new byte[0];
+               HttpEntity entity = request.getEntity();
+               if (entity != null) {
+                       long length = entity.getContentLength();
+                       if (length < 0)
+                               length = 1024;
+                       try (InputStream is = entity.getContent()) {
+                               if (is != null)
+                                       body = IOUtils.readBytes(is, 
(int)Math.min(length, 1024));
+                       }
+               }
+               sreq.get().body(body);
        }
 
        @Override /* HttpClientConnection */

Reply via email to