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 4a901aa  RestClient tests.
4a901aa is described below

commit 4a901aa977fd6126cfbff67709fcf3d32267010d
Author: JamesBognar <[email protected]>
AuthorDate: Thu Jun 11 11:57:28 2020 -0400

    RestClient tests.
---
 .../org/apache/juneau/BasicRuntimeException.java   |   4 +
 .../apache/juneau/assertions/FluentAssertion.java  |  14 +-
 .../org/apache/juneau/http/ReaderResource.java     | 137 +-----------------
 .../apache/juneau/http/ReaderResourceBuilder.java  | 153 +++++++++++++++++++++
 .../juneau/http}/ResolvingReaderResource.java      |  86 ++----------
 .../http/ResolvingResourceReaderBuilder.java       |  98 +++++++++++++
 .../org/apache/juneau/http/StreamResource.java     | 136 +-----------------
 .../apache/juneau/http/StreamResourceBuilder.java  | 153 +++++++++++++++++++++
 .../main/ConfigurablePropertyCodeGenerator.java    |   6 +-
 .../apache/juneau/rest/client2/RestClientTest.java |  90 ++++++------
 .../org/apache/juneau/rest/client2/RestClient.java |  29 ++--
 .../apache/juneau/rest/client2/RestRequest.java    |  20 +--
 .../apache/juneau/rest/client2/RestResponse.java   |  34 +++++
 .../juneau/rest/client2/RestResponseBody.java      |  44 ++++++
 .../java/org/apache/juneau/rest/RestRequest.java   |   6 +-
 15 files changed, 587 insertions(+), 423 deletions(-)

diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BasicRuntimeException.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BasicRuntimeException.java
index a649fe5..ad71fe5 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BasicRuntimeException.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BasicRuntimeException.java
@@ -73,4 +73,8 @@ public class BasicRuntimeException extends RuntimeException {
        public <T extends Throwable> T getCause(Class<T> c) {
                return ThrowableUtils.getCause(c, this);
        }
+
+       // <FluentSetters>
+
+       // </FluentSetters>
 }
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAssertion.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAssertion.java
index c436681..c02ee54 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAssertion.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/assertions/FluentAssertion.java
@@ -59,7 +59,7 @@ public abstract class FluentAssertion<R> {
         */
        @FluentSetter
        public FluentAssertion<R> msg(String msg, Object...args) {
-               this.msg = msg;
+               this.msg = msg.replace("{msg}", "<<<MSG>>>");
                this.msgArgs = args;
                return this;
        }
@@ -95,16 +95,16 @@ public abstract class FluentAssertion<R> {
         */
        protected BasicAssertionError error(String msg, Object...args) {
                msg = format(msg, args);
-               if (this.msg != null) {
-                       if (this.msg.contains("{msg}"))
-                               msg = format(this.msg.replace("{msg}", msg), 
msgArgs);
-                       else
-                               msg = this.msg;
-               }
+               if (this.msg != null)
+                       msg = format(this.msg, 
this.msgArgs).replace("<<<MSG>>>", msg);
                if (stdout)
                        System.out.println(msg);
                if (stderr)
                        System.err.println(msg);
                return new BasicAssertionError(msg);
        }
+
+       // <FluentSetters>
+
+       // </FluentSetters>
 }
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 c885469..f2457b6 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
@@ -33,7 +33,7 @@ import org.apache.juneau.http.annotation.*;
  * <br>The contents of the request passed into the constructor are immediately 
converted to read-only strings.
  *
  * <p>
- * Instances of this class can be built using {@link Builder}.
+ * Instances of this class can be built using {@link ReaderResourceBuilder}.
  *
  * <ul class='seealso'>
  *     <li class='link'>{@doc juneau-rest-server.RestMethod.ReaderResource}
@@ -54,7 +54,7 @@ public class ReaderResource implements Writable {
         * @param b Builder containing values to initialize this object with.
         * @throws IOException Thrown by underlying stream.
         */
-       protected ReaderResource(Builder b) throws IOException {
+       protected ReaderResource(ReaderResourceBuilder b) throws IOException {
                this(b.mediaType, b.headers, b.cached, b.contents.toArray());
        }
 
@@ -89,137 +89,12 @@ public class ReaderResource implements Writable {
        
//-----------------------------------------------------------------------------------------------------------------
 
        /**
-        * Creates a new instance of a {@link Builder} for this class.
+        * Creates a new instance of a {@link ReaderResourceBuilder} for this 
class.
         *
-        * @return A new instance of a {@link Builder}.
+        * @return A new instance of a {@link ReaderResourceBuilder}.
         */
-       public static Builder create() {
-               return new Builder();
-       }
-
-       /**
-        * Builder class for constructing {@link ReaderResource} objects.
-        *
-        * <ul class='seealso'>
-        *      <li class='link'>{@doc 
juneau-rest-server.RestMethod.ReaderResource}
-        * </ul>
-        */
-       @SuppressWarnings("javadoc")
-       public static class Builder {
-
-               public ArrayList<Object> contents = new ArrayList<>();
-               public MediaType mediaType;
-               public Map<String,Object> headers = new LinkedHashMap<>();
-               public boolean cached;
-
-               /**
-                * Specifies the resource media type string.
-                *
-                * @param mediaType The resource media type string.
-                * @return This object (for method chaining).
-                */
-               public Builder mediaType(String mediaType) {
-                       this.mediaType = MediaType.forString(mediaType);
-                       return this;
-               }
-
-               /**
-                * Specifies the resource media type string.
-                *
-                * @param mediaType The resource media type string.
-                * @return This object (for method chaining).
-                */
-               public Builder mediaType(MediaType mediaType) {
-                       this.mediaType = mediaType;
-                       return this;
-               }
-
-               /**
-                * Specifies the contents for this resource.
-                *
-                * <p>
-                * This method can be called multiple times to add more content.
-                *
-                * @param contents
-                *      The resource contents.
-                *      <br>If multiple contents are specified, the results 
will be concatenated.
-                *      <br>Contents 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.
-                *      </ul>
-                * @return This object (for method chaining).
-                */
-               public Builder contents(Object...contents) {
-                       Collections.addAll(this.contents, contents);
-                       return this;
-               }
-
-               /**
-                * Specifies an HTTP response header value.
-                *
-                * @param name The HTTP header name.
-                * @param value
-                *      The HTTP header value.
-                *      <br>Will be converted to a <c>String</c> using {@link 
Object#toString()}.
-                * @return This object (for method chaining).
-                */
-               public Builder header(String name, Object value) {
-                       this.headers.put(name, value);
-                       return this;
-               }
-
-               /**
-                * Specifies HTTP response header values.
-                *
-                * @param headers
-                *      The HTTP headers.
-                *      <br>Values will be converted to <c>Strings</c> using 
{@link Object#toString()}.
-                * @return This object (for method chaining).
-                */
-               public Builder headers(Map<String,Object> headers) {
-                       this.headers.putAll(headers);
-                       return this;
-               }
-
-               /**
-                * Specifies HTTP response header values.
-                *
-                * @param headers
-                *      The HTTP headers.
-                *      <br>Values will be converted to <c>Strings</c> using 
{@link Object#toString()}.
-                * @return This object (for method chaining).
-                */
-               public Builder headers(org.apache.http.Header...headers) {
-                       for (org.apache.http.Header h : headers)
-                               this.headers.put(h.getName(), h.getValue());
-                       return this;
-               }
-
-               /**
-                * Specifies that this resource is intended to be cached.
-                *
-                * <p>
-                * This will trigger the contents to be loaded into a String 
for fast serializing.
-                *
-                * @return This object (for method chaining).
-                */
-               public Builder cached() {
-                       this.cached = true;
-                       return this;
-               }
-
-               /**
-                * Create a new {@link ReaderResource} using values in this 
builder.
-                *
-                * @return A new immutable {@link ReaderResource} object.
-                * @throws IOException Thrown by underlying stream.
-                */
-               public ReaderResource build() throws IOException {
-                       return new ReaderResource(this);
-               }
+       public static ReaderResourceBuilder create() {
+               return new ReaderResourceBuilder();
        }
 
        
//-----------------------------------------------------------------------------------------------------------------
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
new file mode 100644
index 0000000..02f2e48
--- /dev/null
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
@@ -0,0 +1,153 @@
+// 
***************************************************************************************************************************
+// * 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.io.*;
+import java.util.*;
+
+import org.apache.juneau.internal.*;
+
+/**
+ * Builder class for constructing {@link ReaderResource} objects.
+ *
+ * <ul class='seealso'>
+ *     <li class='link'>{@doc juneau-rest-server.RestMethod.ReaderResource}
+ * </ul>
+ */
+public class ReaderResourceBuilder {
+
+       ArrayList<Object> contents = new ArrayList<>();
+       MediaType mediaType;
+       Map<String,Object> headers = new LinkedHashMap<>();
+       boolean cached;
+
+       /**
+        * Specifies the resource media type string.
+        *
+        * @param mediaType The resource media type string.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public ReaderResourceBuilder mediaType(String mediaType) {
+               this.mediaType = MediaType.forString(mediaType);
+               return this;
+       }
+
+       /**
+        * Specifies the resource media type string.
+        *
+        * @param mediaType The resource media type string.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public ReaderResourceBuilder mediaType(MediaType mediaType) {
+               this.mediaType = mediaType;
+               return this;
+       }
+
+       /**
+        * Specifies the contents for this resource.
+        *
+        * <p>
+        * This method can be called multiple times to add more content.
+        *
+        * @param contents
+        *      The resource contents.
+        *      <br>If multiple contents are specified, the results will be 
concatenated.
+        *      <br>Contents 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.
+        *      </ul>
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public ReaderResourceBuilder contents(Object...contents) {
+               Collections.addAll(this.contents, contents);
+               return this;
+       }
+
+       /**
+        * Specifies an HTTP response header value.
+        *
+        * @param name The HTTP header name.
+        * @param value
+        *      The HTTP header value.
+        *      <br>Will be converted to a <c>String</c> using {@link 
Object#toString()}.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public ReaderResourceBuilder header(String name, Object value) {
+               this.headers.put(name, value);
+               return this;
+       }
+
+       /**
+        * Specifies HTTP response header values.
+        *
+        * @param headers
+        *      The HTTP headers.
+        *      <br>Values will be converted to <c>Strings</c> using {@link 
Object#toString()}.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public ReaderResourceBuilder headers(Map<String,Object> headers) {
+               this.headers.putAll(headers);
+               return this;
+       }
+
+       /**
+        * Specifies HTTP response header values.
+        *
+        * @param headers
+        *      The HTTP headers.
+        *      <br>Values will be converted to <c>Strings</c> using {@link 
Object#toString()}.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public ReaderResourceBuilder headers(org.apache.http.Header...headers) {
+               for (org.apache.http.Header h : headers)
+                       this.headers.put(h.getName(), h.getValue());
+               return this;
+       }
+
+       /**
+        * Specifies that this resource is intended to be cached.
+        *
+        * <p>
+        * This will trigger the contents to be loaded into a String for fast 
serializing.
+        *
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public ReaderResourceBuilder cached() {
+               this.cached = true;
+               return this;
+       }
+
+       /**
+        * Create a new {@link ReaderResource} using values in this builder.
+        *
+        * @return A new immutable {@link ReaderResource} object.
+        * @throws IOException Thrown by underlying stream.
+        */
+       public ReaderResource build() throws IOException {
+               return new ReaderResource(this);
+       }
+
+       // <FluentSetters>
+
+       // </FluentSetters>
+}
\ No newline at end of file
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/helper/ResolvingReaderResource.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
similarity index 64%
rename from 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/helper/ResolvingReaderResource.java
rename to 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
index fd5077c..14b7526 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/helper/ResolvingReaderResource.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
@@ -10,15 +10,13 @@
 // * "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.helper;
+package org.apache.juneau.http;
 
 import static org.apache.juneau.internal.IOUtils.*;
 
-import org.apache.juneau.http.ReaderResource;
 import java.io.*;
 import java.util.*;
 
-import org.apache.juneau.http.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.svl.*;
 
@@ -35,8 +33,9 @@ public class ResolvingReaderResource extends ReaderResource {
         * @param b Builder containing values to initialize this object with.
         * @throws IOException Thrown by underlying stream.
         */
-       protected ResolvingReaderResource(Builder b) throws IOException {
-               this(b.mediaType, b.headers, b.cached, b.varResolver, 
b.contents.toArray());
+       protected ResolvingReaderResource(ResolvingResourceReaderBuilder b) 
throws IOException {
+               super(b);
+               this.varSession = b.varResolver;
        }
 
        /**
@@ -70,81 +69,12 @@ public class ResolvingReaderResource extends ReaderResource 
{
        
//-----------------------------------------------------------------------------------------------------------------
 
        /**
-        * Creates a new instance of a {@link Builder} for this class.
+        * Creates a new instance of a {@link ResolvingResourceReaderBuilder} 
for this class.
         *
-        * @return A new instance of a {@link Builder}.
+        * @return A new instance of a {@link ResolvingResourceReaderBuilder}.
         */
-       public static Builder create() {
-               return new Builder();
-       }
-
-       /**
-        * Builder class for constructing {@link ResolvingReaderResource} 
objects.
-        *
-        * <ul class='seealso'>
-        *      <li class='link'>{@doc 
juneau-rest-server.RestMethod.ReaderResource}
-        * </ul>
-        */
-       public static class Builder extends ReaderResource.Builder {
-               VarResolverSession varResolver;
-
-               /**
-                * Specifies the variable resolver to use for this resource.
-                *
-                * @param varResolver The variable resolver.
-                * @return This object (for method chaining).
-                */
-               public Builder varResolver(VarResolverSession varResolver) {
-                       this.varResolver = varResolver;
-                       return this;
-               }
-
-               @Override
-               public Builder mediaType(String mediaType) {
-                       super.mediaType(mediaType);
-                       return this;
-               }
-
-               @Override
-               public Builder mediaType(MediaType mediaType) {
-                       super.mediaType(mediaType);
-                       return this;
-               }
-
-               @Override
-               public Builder contents(Object...contents) {
-                       super.contents(contents);
-                       return this;
-               }
-
-               @Override
-               public Builder header(String name, Object value) {
-                       super.header(name, value);
-                       return this;
-               }
-
-               @Override
-               public Builder headers(Map<String,Object> headers) {
-                       super.headers(headers);
-                       return this;
-               }
-
-               @Override
-               public Builder cached() {
-                       super.cached();
-                       return this;
-               }
-
-               /**
-                * Create a new {@link ResolvingReaderResource} using values in 
this builder.
-                *
-                * @return A new immutable {@link ResolvingReaderResource} 
object.
-                * @throws IOException Thrown by underlying stream.
-                */
-               @Override
-               public ResolvingReaderResource build() throws IOException {
-                       return new ResolvingReaderResource(this);
-               }
+       public static ResolvingResourceReaderBuilder create() {
+               return new ResolvingResourceReaderBuilder();
        }
 
        @ResponseBody
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
new file mode 100644
index 0000000..3808442
--- /dev/null
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
@@ -0,0 +1,98 @@
+// 
***************************************************************************************************************************
+// * 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.io.*;
+import java.util.*;
+
+import org.apache.http.*;
+import org.apache.juneau.svl.*;
+
+/**
+ * Builder class for constructing {@link ResolvingReaderResource} objects.
+ *
+ * <ul class='seealso'>
+ *     <li class='link'>{@doc juneau-rest-server.RestMethod.ReaderResource}
+ * </ul>
+ */
+public class ResolvingResourceReaderBuilder extends ReaderResourceBuilder {
+       VarResolverSession varResolver;
+
+       /**
+        * Specifies the variable resolver to use for this resource.
+        *
+        * @param varResolver The variable resolver.
+        * @return This object (for method chaining).
+        */
+       public ResolvingResourceReaderBuilder varResolver(VarResolverSession 
varResolver) {
+               this.varResolver = varResolver;
+               return this;
+       }
+
+       /**
+        * Create a new {@link ResolvingReaderResource} using values in this 
builder.
+        *
+        * @return A new immutable {@link ResolvingReaderResource} object.
+        * @throws IOException Thrown by underlying stream.
+        */
+       @Override
+       public ResolvingReaderResource build() throws IOException {
+               return new ResolvingReaderResource(this);
+       }
+
+       // <FluentSetters>
+
+       @Override /* GENERATED - ReaderResourceBuilder */
+       public ResolvingResourceReaderBuilder cached() {
+               super.cached();
+               return this;
+       }
+
+       @Override /* GENERATED - ReaderResourceBuilder */
+       public ResolvingResourceReaderBuilder contents(Object...contents) {
+               super.contents(contents);
+               return this;
+       }
+
+       @Override /* GENERATED - ReaderResourceBuilder */
+       public ResolvingResourceReaderBuilder header(String name, Object value) 
{
+               super.header(name, value);
+               return this;
+       }
+
+       @Override /* GENERATED - ReaderResourceBuilder */
+       public ResolvingResourceReaderBuilder headers(Header...headers) {
+               super.headers(headers);
+               return this;
+       }
+
+       @Override /* GENERATED - ReaderResourceBuilder */
+       public ResolvingResourceReaderBuilder headers(Map<String,Object> 
headers) {
+               super.headers(headers);
+               return this;
+       }
+
+       @Override /* GENERATED - ReaderResourceBuilder */
+       public ResolvingResourceReaderBuilder mediaType(String mediaType) {
+               super.mediaType(mediaType);
+               return this;
+       }
+
+       @Override /* GENERATED - ReaderResourceBuilder */
+       public ResolvingResourceReaderBuilder mediaType(MediaType mediaType) {
+               super.mediaType(mediaType);
+               return this;
+       }
+
+       // </FluentSetters>
+}
\ 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 151bec6..2f61327 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
@@ -33,7 +33,7 @@ import org.apache.juneau.http.annotation.*;
  * <br>The contents of the request passed into the constructor are immediately 
converted to read-only byte arrays.
  *
  * <p>
- * Instances of this class can be built using {@link Builder}.
+ * Instances of this class can be built using {@link StreamResourceBuilder}.
  *
  * <ul class='seealso'>
  *     <li class='link'>{@doc juneau-rest-server.RestMethod.StreamResource}
@@ -46,7 +46,7 @@ public class StreamResource implements Streamable {
        private final Object[] contents;
        private final Map<String,Object> headers;
 
-       StreamResource(Builder b) throws IOException {
+       StreamResource(StreamResourceBuilder b) throws IOException {
                this(b.mediaType, b.headers, b.cached, b.contents.toArray());
        }
 
@@ -82,136 +82,12 @@ public class StreamResource implements Streamable {
        
//-----------------------------------------------------------------------------------------------------------------
 
        /**
-        * Creates a new instance of a {@link Builder} for this class.
+        * Creates a new instance of a {@link StreamResourceBuilder} for this 
class.
         *
-        * @return A new instance of a {@link Builder}.
+        * @return A new instance of a {@link StreamResourceBuilder}.
         */
-       public static Builder create() {
-               return new Builder();
-       }
-
-       /**
-        * Builder class for constructing {@link StreamResource} objects.
-        *
-        * <ul class='seealso'>
-        *      <li class='link'>{@doc 
juneau-rest-server.RestMethod.StreamResource}
-        * </ul>
-        */
-       public static class Builder {
-               ArrayList<Object> contents = new ArrayList<>();
-               MediaType mediaType;
-               Map<String,Object> headers = new LinkedHashMap<>();
-               boolean cached;
-
-               /**
-                * Specifies the resource media type string.
-                *
-                * @param mediaType The resource media type string.
-                * @return This object (for method chaining).
-                */
-               public Builder mediaType(String mediaType) {
-                       this.mediaType = MediaType.forString(mediaType);
-                       return this;
-               }
-
-               /**
-                * Specifies the resource media type string.
-                *
-                * @param mediaType The resource media type string.
-                * @return This object (for method chaining).
-                */
-               public Builder mediaType(MediaType mediaType) {
-                       this.mediaType = mediaType;
-                       return this;
-               }
-
-               /**
-                * Specifies the contents for this resource.
-                *
-                * <p>
-                * This method can be called multiple times to add more content.
-                *
-                * @param contents
-                *      The resource contents.
-                *      <br>If multiple contents are specified, the results 
will be concatenated.
-                *      <br>Contents can be any of the following:
-                *      <ul>
-                *              <li><code><jk>byte</jk>[]</code>
-                *              <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.
-                *      </ul>
-                * @return This object (for method chaining).
-                */
-               public Builder contents(Object...contents) {
-                       Collections.addAll(this.contents, contents);
-                       return this;
-               }
-
-               /**
-                * Specifies an HTTP response header value.
-                *
-                * @param name The HTTP header name.
-                * @param value
-                *      The HTTP header value.
-                *      <br>Will be converted to a <c>String</c> using {@link 
Object#toString()}.
-                * @return This object (for method chaining).
-                */
-               public Builder header(String name, Object value) {
-                       this.headers.put(name, value);
-                       return this;
-               }
-
-               /**
-                * Specifies HTTP response header values.
-                *
-                * @param headers
-                *      The HTTP headers.
-                *      <br>Values will be converted to <c>Strings</c> using 
{@link Object#toString()}.
-                * @return This object (for method chaining).
-                */
-               public Builder headers(Map<String,Object> headers) {
-                       this.headers.putAll(headers);
-                       return this;
-               }
-
-               /**
-                * Specifies HTTP response header values.
-                *
-                * @param headers
-                *      The HTTP headers.
-                *      <br>Values will be converted to <c>Strings</c> using 
{@link Object#toString()}.
-                * @return This object (for method chaining).
-                */
-               public Builder headers(org.apache.http.Header...headers) {
-                       for (org.apache.http.Header h : headers)
-                               this.headers.put(h.getName(), h.getValue());
-                       return this;
-               }
-
-               /**
-                * Specifies that this resource is intended to be cached.
-                *
-                * <p>
-                * This will trigger the contents to be loaded into a byte 
array for fast serializing.
-                *
-                * @return This object (for method chaining).
-                */
-               public Builder cached() {
-                       this.cached = true;
-                       return this;
-               }
-
-               /**
-                * Create a new {@link StreamResource} using values in this 
builder.
-                *
-                * @return A new immutable {@link StreamResource} object.
-                * @throws IOException Thrown by underlying stream.
-                */
-               public StreamResource build() throws IOException {
-                       return new StreamResource(this);
-               }
+       public static StreamResourceBuilder create() {
+               return new StreamResourceBuilder();
        }
 
        /**
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
new file mode 100644
index 0000000..30934d6
--- /dev/null
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
@@ -0,0 +1,153 @@
+// 
***************************************************************************************************************************
+// * 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.io.*;
+import java.util.*;
+
+import org.apache.juneau.internal.*;
+
+/**
+ * Builder class for constructing {@link StreamResource} objects.
+ *
+ * <ul class='seealso'>
+ *     <li class='link'>{@doc juneau-rest-server.RestMethod.StreamResource}
+ * </ul>
+ */
+public class StreamResourceBuilder {
+       ArrayList<Object> contents = new ArrayList<>();
+       MediaType mediaType;
+       Map<String,Object> headers = new LinkedHashMap<>();
+       boolean cached;
+
+       /**
+        * Specifies the resource media type string.
+        *
+        * @param mediaType The resource media type string.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public StreamResourceBuilder mediaType(String mediaType) {
+               this.mediaType = MediaType.forString(mediaType);
+               return this;
+       }
+
+       /**
+        * Specifies the resource media type string.
+        *
+        * @param mediaType The resource media type string.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public StreamResourceBuilder mediaType(MediaType mediaType) {
+               this.mediaType = mediaType;
+               return this;
+       }
+
+       /**
+        * Specifies the contents for this resource.
+        *
+        * <p>
+        * This method can be called multiple times to add more content.
+        *
+        * @param contents
+        *      The resource contents.
+        *      <br>If multiple contents are specified, the results will be 
concatenated.
+        *      <br>Contents can be any of the following:
+        *      <ul>
+        *              <li><code><jk>byte</jk>[]</code>
+        *              <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.
+        *      </ul>
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public StreamResourceBuilder contents(Object...contents) {
+               Collections.addAll(this.contents, contents);
+               return this;
+       }
+
+       /**
+        * Specifies an HTTP response header value.
+        *
+        * @param name The HTTP header name.
+        * @param value
+        *      The HTTP header value.
+        *      <br>Will be converted to a <c>String</c> using {@link 
Object#toString()}.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public StreamResourceBuilder header(String name, Object value) {
+               this.headers.put(name, value);
+               return this;
+       }
+
+       /**
+        * Specifies HTTP response header values.
+        *
+        * @param headers
+        *      The HTTP headers.
+        *      <br>Values will be converted to <c>Strings</c> using {@link 
Object#toString()}.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public StreamResourceBuilder headers(Map<String,Object> headers) {
+               this.headers.putAll(headers);
+               return this;
+       }
+
+       /**
+        * Specifies HTTP response header values.
+        *
+        * @param headers
+        *      The HTTP headers.
+        *      <br>Values will be converted to <c>Strings</c> using {@link 
Object#toString()}.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public StreamResourceBuilder headers(org.apache.http.Header...headers) {
+               for (org.apache.http.Header h : headers)
+                       this.headers.put(h.getName(), h.getValue());
+               return this;
+       }
+
+       /**
+        * Specifies that this resource is intended to be cached.
+        *
+        * <p>
+        * This will trigger the contents to be loaded into a byte array for 
fast serializing.
+        *
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public StreamResourceBuilder cached() {
+               this.cached = true;
+               return this;
+       }
+
+       /**
+        * Create a new {@link StreamResource} using values in this builder.
+        *
+        * @return A new immutable {@link StreamResource} object.
+        * @throws IOException Thrown by underlying stream.
+        */
+       public StreamResource build() throws IOException {
+               return new StreamResource(this);
+       }
+
+       // <FluentSetters>
+
+       // </FluentSetters>
+}
\ No newline at end of file
diff --git 
a/juneau-releng/juneau-all/src/java/main/ConfigurablePropertyCodeGenerator.java 
b/juneau-releng/juneau-all/src/java/main/ConfigurablePropertyCodeGenerator.java
index 8824960..9781e10 100644
--- 
a/juneau-releng/juneau-all/src/java/main/ConfigurablePropertyCodeGenerator.java
+++ 
b/juneau-releng/juneau-all/src/java/main/ConfigurablePropertyCodeGenerator.java
@@ -23,6 +23,7 @@ import org.apache.juneau.config.*;
 import org.apache.juneau.config.store.*;
 import org.apache.juneau.csv.*;
 import org.apache.juneau.html.*;
+import org.apache.juneau.http.*;
 import org.apache.juneau.http.exception.*;
 import org.apache.juneau.http.response.*;
 import org.apache.juneau.internal.*;
@@ -165,6 +166,9 @@ public class ConfigurablePropertyCodeGenerator {
                FluentIntegerAssertion.class,
                FluentLongAssertion.class,
                FluentStringAssertion.class,
+               ReaderResourceBuilder.class,
+               StreamResourceBuilder.class,
+               ResolvingResourceReaderBuilder.class
        };
 
        private static String[] SOURCE_PATHS = {
@@ -237,7 +241,7 @@ public class ConfigurablePropertyCodeGenerator {
                                                        // Don't render ignored 
methods.
                                                        if 
(ignore.contains(m.getName()) || ignore.contains(mSig))
                                                                continue;
-                                                       
+
                                                        StringBuilder sigLine = 
new StringBuilder();
                                                        
sigLine.append("\n\tpublic ");
                                                        if 
(m.getTypeParameters().length > 0)
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java
index a9b4312..9b55f60 100644
--- 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClientTest.java
@@ -570,57 +570,45 @@ public class RestClientTest {
                }
        }
 
-//     @Test
-//     public void a23_basicCalls_formPost_exhaustiveBodyTypes() throws 
Exception {
-//
-//
-//             List<Object> bodies = AList.of(
-//                     bean,
-//                      NameValuePairs.of("f","1"),
-//                      new NameValuePair[]{BasicNameValuePair.of("f","1")},
-//                      new StringEntity("{f:1}", 
org.apache.http.entity.ContentType.APPLICATION_FORM_URLENCODED),
-//                      new StringEntity("{f:1}", 
(org.apache.http.entity.ContentType)null),
-//                      BasicNameValuePair.of("f","1")
-//             );
-//
-//             for (int i = 0; i < bodies.size(); i++) {
-//                     MockRestClient
-//                             .create(A.class)
-//                             .header("Check", "Content-Type")
-//                             .accept("application/json+simple")
-//                             .build()
-//                             .formPost("/checkHeader", bodies.get(i))
-//                             .run()
-//                             .assertBody()
-//                                     .msg("Body {0} failed", 
i).matchesSimple("['application/x-www-form-urlencoded*']");
-//
-//                     MockRestClient
-//                             .create(A.class)
-//                             .build()
-//                             .formPost("/bean", body)
-//                             .accept("application/json+simple")
-//                             .run()
-//                             .assertBody().is("{f:1}");
-//             }
-//
-//
-//             bodies = AList.of(
-//                     bean,
-//                      NameValuePairs.of("f","1"),
-//                      new NameValuePair[]{BasicNameValuePair.of("f","1")},
-//                      new StringEntity("{f:1}", 
org.apache.http.entity.ContentType.APPLICATION_JSON),
-//                      BasicNameValuePair.of("f","1")
-//             );
-//
-//             for (Object body : bodies) {
-//                     MockRestClient
-//                             .create(A.class)
-//                             .build()
-//                             .formPost("/echoBody", body)
-//                             .run()
-//                             .assertBody().is("{f:1}");
-//             }
-//     }
+       @Test
+       public void a23_basicCalls_formPost_exhaustiveBodyTypes() throws 
Exception {
+
+               List<Object> bodies = AList.of(
+                       /*[ 0]*/ bean,
+                       /*[ 1]*/ NameValuePairs.of("f","1"),
+                       /*[ 2]*/ new 
NameValuePair[]{BasicNameValuePair.of("f","1")},
+                       /*[ 3]*/ new StringEntity("f=1", 
org.apache.http.entity.ContentType.APPLICATION_FORM_URLENCODED),
+                       /*[ 4]*/ new StringEntity("f=1", 
(org.apache.http.entity.ContentType)null),
+                       /*[ 5]*/ BasicNameValuePair.of("f","1"),
+                       /*[ 6]*/ 
ReaderResource.create().contents("f=1").build(),
+                       /*[ 7]*/ ReaderResource.create().contents("f=1"),
+                       /*[ 8]*/ 
ReaderResource.create().contents("f=1").mediaType("application/x-www-form-urlencoded").build(),
+                       /*[ 9]*/ 
ReaderResource.create().contents("f=1").mediaType("application/x-www-form-urlencoded"),
+                       /*[10]*/ 
StreamResource.create().contents("f=1").build(),
+                       /*[11]*/ StreamResource.create().contents("f=1"),
+                       /*[12]*/ 
StreamResource.create().contents("f=1").mediaType("application/x-www-form-urlencoded").build(),
+                       /*[13]*/ 
StreamResource.create().contents("f=1").mediaType("application/x-www-form-urlencoded")
+               );
+
+               for (int i = 0; i < bodies.size(); i++) {
+                       MockRestClient
+                               .create(A.class)
+                               .header("Check", "Content-Type")
+                               .accept("application/json+simple")
+                               .build()
+                               .formPost("/checkHeader", bodies.get(i))
+                               .run()
+                               .assertBody().msg("Body {0} failed", 
i).matchesSimple("['application/x-www-form-urlencoded*']");
+
+                       MockRestClient
+                               .create(A.class)
+                               .build()
+                               .formPost("/bean", bodies.get(i))
+                               .accept("application/json+simple")
+                               .run()
+                               .assertBody().msg("Body {0} failed", 
"#"+i).is("{f:1}");
+               }
+       }
 
        @Test
        public void a24_basicCalls_formPostPairs() throws Exception {
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 fdda46f..7b31585 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
@@ -489,9 +489,9 @@ import org.apache.http.client.CookieStore;
  *             <li class='jc'>
  *                     {@link InputStream} - Raw contents of {@code 
InputStream} will be serialized to remote resource.
  *             <li class='jc'>
- *                     {@link ReaderResource} - Raw contents of {@code Reader} 
will be serialized to remote resource.  Additional headers and media type will 
be set on request.
+ *                     {@link ReaderResource}/{@link ReaderResourceBuilder} - 
Raw contents of {@code Reader} will be serialized to remote resource.  
Additional headers and media type will be set on request.
  *             <li class='jc'>
- *                     {@link StreamResource} - Raw contents of {@code 
InputStream} will be serialized to remote resource.  Additional headers and 
media type will be set on request.
+ *                     {@link StreamResource}/{@link StreamResourceBuilder} - 
Raw contents of {@code InputStream} will be serialized to remote resource.  
Additional headers and media type will be set on request.
  *             <li class='jc'>
  *                     {@link HttpEntity} - Bypass Juneau serialization and 
pass HttpEntity directly to HttpClient.
  *             <li class='jc'>
@@ -2152,9 +2152,9 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
         *              <li class='jc'>
         *                      {@link InputStream} - Raw contents of {@code 
InputStream} will be serialized to remote resource.
         *              <li class='jc'>
-        *                      {@link ReaderResource} - Raw contents of {@code 
Reader} will be serialized to remote resource.  Additional headers and media 
type will be set on request.
+        *                      {@link ReaderResource}/{@link 
ReaderResourceBuilder} - Raw contents of {@code Reader} will be serialized to 
remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
-        *                      {@link StreamResource} - Raw contents of {@code 
InputStream} will be serialized to remote resource.  Additional headers and 
media type will be set on request.
+        *                      {@link StreamResource}/{@link 
StreamResourceBuilder} - Raw contents of {@code InputStream} will be serialized 
to remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
         *                      {@link Object} - POJO to be converted to text 
using the {@link Serializer} registered with the
         *                      {@link RestClient}.
@@ -2249,9 +2249,9 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
         *              <li class='jc'>
         *                      {@link InputStream} - Raw contents of {@code 
InputStream} will be serialized to remote resource.
         *              <li class='jc'>
-        *                      {@link ReaderResource} - Raw contents of {@code 
Reader} will be serialized to remote resource.  Additional headers and media 
type will be set on request.
+        *                      {@link ReaderResource}/{@link 
ReaderResourceBuilder} - Raw contents of {@code Reader} will be serialized to 
remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
-        *                      {@link StreamResource} - Raw contents of {@code 
InputStream} will be serialized to remote resource.  Additional headers and 
media type will be set on request.
+        *                      {@link StreamResource}/{@link 
StreamResourceBuilder} - Raw contents of {@code InputStream} will be serialized 
to remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
         *                      {@link Object} - POJO to be converted to text 
using the {@link Serializer} registered with the
         *                      {@link RestClient}.
@@ -2412,7 +2412,7 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
         *              <li class='jc'>{@link NameValuePair} array - 
URL-encoded as name value pairs.
         *              <li class='jc'>{@link NameValuePairs} - URL-encoded as 
name value pairs.
         *              <li class='jc'>{@link Reader}/{@link InputStream}- 
Streamed directly and <l>Content-Type</l> set to 
<js>"application/x-www-form-urlencoded"</js>
-        *              <li class='jc'>{@link ReaderResource}/{@link 
StreamResource}/{@link HttpEntity}- Streamed directly and <l>Content-Type</l> 
set to <js>"application/x-www-form-urlencoded"</js> if not already specified on 
the entity.
+        *              <li class='jc'>{@link ReaderResource}/{@link 
ReaderResourceBuilder}/{@link StreamResource}/{@link 
StreamResourceBuilder}/{@link HttpEntity}- Streamed directly and 
<l>Content-Type</l> set to <js>"application/x-www-form-urlencoded"</js> if not 
already specified on the entity.
         *              <li class='jc'>{@link Object} - Converted to a {@link 
SerializedHttpEntity} using {@link UrlEncodingSerializer} to serialize.
         *      </ul>
         * @return
@@ -2437,12 +2437,16 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                        }
                        if (body instanceof Reader || body instanceof 
InputStream)
                                return 
req.contentType("application/x-www-form-urlencoded").body(body);
+                       if (body instanceof ReaderResourceBuilder)
+                               body = ((ReaderResourceBuilder)body).build();
                        if (body instanceof ReaderResource) {
                                ReaderResource r = (ReaderResource)body;
                                if (r.getContentType() == null)
                                        
req.contentType("application/x-www-form-urlencoded");
                                return req.body(r);
                        }
+                       if (body instanceof StreamResourceBuilder)
+                               body = ((StreamResourceBuilder)body).build();
                        if (body instanceof StreamResource) {
                                StreamResource r = (StreamResource)body;
                                if (r.getContentType() == null)
@@ -2450,8 +2454,7 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                                return req.body(r);
                        }
                        return req.body(new SerializedHttpEntity(body, 
urlEncodingSerializer, null, null));
-               } catch (UnsupportedEncodingException e) {
-                       // Should never happen.
+               } catch (IOException e) {
                        throw new RestCallException(e);
                }
        }
@@ -2552,9 +2555,9 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
         *              <li class='jc'>
         *                      {@link InputStream} - Raw contents of {@code 
InputStream} will be serialized to remote resource.
         *              <li class='jc'>
-        *                      {@link ReaderResource} - Raw contents of {@code 
Reader} will be serialized to remote resource.  Additional headers and media 
type will be set on request.
+        *                      {@link ReaderResource}/{@link 
ReaderResourceBuilder} - Raw contents of {@code Reader} will be serialized to 
remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
-        *                      {@link StreamResource} - Raw contents of {@code 
InputStream} will be serialized to remote resource.  Additional headers and 
media type will be set on request.
+        *                      {@link StreamResource}/{@link 
StreamResourceBuilder} - Raw contents of {@code InputStream} will be serialized 
to remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
         *                      {@link Object} - POJO to be converted to text 
using the {@link Serializer} registered with the
         *                      {@link RestClient}.
@@ -2736,9 +2739,9 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
         *              <li class='jc'>
         *                      {@link InputStream} - Raw contents of {@code 
InputStream} will be serialized to remote resource.
         *              <li class='jc'>
-        *                      {@link ReaderResource} - Raw contents of {@code 
Reader} will be serialized to remote resource.  Additional headers and media 
type will be set on request.
+        *                      {@link ReaderResource}/{@link 
ReaderResourceBuilder} - Raw contents of {@code Reader} will be serialized to 
remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
-        *                      {@link StreamResource} - Raw contents of {@code 
InputStream} will be serialized to remote resource.  Additional headers and 
media type will be set on request.
+        *                      {@link StreamResource}/{@link 
StreamResourceBuilder} - Raw contents of {@code InputStream} will be serialized 
to remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
         *                      {@link Object} - POJO to be converted to text 
using the {@link Serializer} registered with the
         *                      {@link RestClient}.
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java
index fc8f0f7..8a5a13c 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestRequest.java
@@ -2467,9 +2467,9 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
         *              <li class='jc'>
         *                      {@link InputStream} - Raw contents of {@code 
InputStream} will be serialized to remote resource.
         *              <li class='jc'>
-        *                      {@link ReaderResource} - Raw contents of {@code 
Reader} will be serialized to remote resource.  Additional headers and media 
type will be set on request.
+        *                      {@link ReaderResource}/{@link 
ReaderResourceBuilder} - Raw contents of {@code Reader} will be serialized to 
remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
-        *                      {@link StreamResource} - Raw contents of {@code 
InputStream} will be serialized to remote resource.  Additional headers and 
media type will be set on request.
+        *                      {@link StreamResource}/{@link 
StreamResourceBuilder} - Raw contents of {@code InputStream} will be serialized 
to remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
         *                      {@link Object} - POJO to be converted to text 
using the {@link Serializer} registered with the
         *                      {@link RestClient}.
@@ -2554,9 +2554,9 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
         *              <li class='jc'>
         *                      {@link InputStream} - Raw contents of {@code 
InputStream} will be serialized to remote resource.
         *              <li class='jc'>
-        *                      {@link ReaderResource} - Raw contents of {@code 
Reader} will be serialized to remote resource.  Additional headers and media 
type will be set on request.
+        *                      {@link ReaderResource}/{@link 
ReaderResourceBuilder} - Raw contents of {@code Reader} will be serialized to 
remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
-        *                      {@link StreamResource} - Raw contents of {@code 
InputStream} will be serialized to remote resource.  Additional headers and 
media type will be set on request.
+        *                      {@link StreamResource}/{@link 
StreamResourceBuilder} - Raw contents of {@code InputStream} will be serialized 
to remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
         *                      {@link Object} - POJO to be converted to text 
using the {@link Serializer} registered with the
         *                      {@link RestClient}.
@@ -2619,9 +2619,9 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
         *              <li class='jc'>
         *                      {@link InputStream} - Raw contents of {@code 
InputStream} will be serialized to remote resource.
         *              <li class='jc'>
-        *                      {@link ReaderResource} - Raw contents of {@code 
Reader} will be serialized to remote resource.  Additional headers and media 
type will be set on request.
+        *                      {@link ReaderResource}/{@link 
ReaderResourceBuilder} - Raw contents of {@code Reader} will be serialized to 
remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
-        *                      {@link StreamResource} - Raw contents of {@code 
InputStream} will be serialized to remote resource.  Additional headers and 
media type will be set on request.
+        *                      {@link StreamResource}/{@link 
StreamResourceBuilder} - Raw contents of {@code InputStream} will be serialized 
to remote resource.  Additional headers and media type will be set on request.
         *              <li class='jc'>
         *                      {@link Object} - POJO to be converted to text 
using the {@link Serializer} registered with the
         *                      {@link RestClient}.
@@ -3818,13 +3818,17 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                                        entity = new 
StringEntity(IOUtils.read((Reader)input), getRequestContentType(TEXT_PLAIN));
                                else if (input instanceof InputStream)
                                        entity = new 
InputStreamEntity((InputStream)input, 
getRequestContentType(ContentType.APPLICATION_OCTET_STREAM));
-                               else if (input instanceof ReaderResource) {
+                               else if (input instanceof ReaderResource || 
input instanceof ReaderResourceBuilder) {
+                                       if (input instanceof 
ReaderResourceBuilder)
+                                               input = 
((ReaderResourceBuilder)input).build();
                                        ReaderResource r = 
(ReaderResource)input;
                                        contentType(r.getContentType());
                                        headers(r.getHeaders());
                                        entity = new 
StringEntity(IOUtils.read(r.getContents()), getRequestContentType(TEXT_PLAIN));
                                }
-                               else if (input instanceof StreamResource) {
+                               else if (input instanceof StreamResource || 
input instanceof StreamResourceBuilder) {
+                                       if (input instanceof 
StreamResourceBuilder)
+                                               input = 
((StreamResourceBuilder)input).build();
                                        StreamResource r = 
(StreamResource)input;
                                        contentType(r.getContentType());
                                        headers(r.getHeaders());
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponse.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponse.java
index 48e0363..16c9f86 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponse.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponse.java
@@ -490,6 +490,40 @@ public class RestResponse implements HttpResponse {
        }
 
        /**
+        * Provides the ability to perform fluent-style assertions on this 
response body.
+        *
+        * <p>
+        * <p>
+        * Combines the functionality of {@link RestResponseBody#as(Class)} 
with {@link #assertBody()} by converting the body to the specified
+        * bean and then serializing it to simplified JSON for easy string 
comparison.
+        *
+        * <h5 class='section'>Examples:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Validates the response body bean is the expected 
value.</jc>
+        *      client
+        *              .get(<js>"/myBean"</js>)
+        *              .run()
+        *              
.assertBody(MyBean.<js>class</js>).equals(<js>"{foo:'bar'}"</js>);
+        * </p>
+        *
+        * <ul class='notes'>
+        *      <li>
+        *              If no charset was found on the 
<code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
+        *  <li>
+        *              When using this method, the body is automatically 
cached by calling the {@link RestResponseBody#cache()}.
+        *      <li>
+        *              The input stream is automatically closed after this 
call.
+        * </ul>
+        *
+        * @param type The object type to create.
+        * @return A new fluent assertion object.
+        * @throws RestCallException If REST call failed.
+        */
+       public FluentStringAssertion<RestResponse> assertBody(Class<?> type) 
throws RestCallException {
+               return responseBody.cache().assertThat(type);
+       }
+
+       /**
         * Caches the response body so that it can be read as a stream multiple 
times.
         *
         * This is equivalent to calling the following:
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseBody.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseBody.java
index e0a8c0f..31256b9 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseBody.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestResponseBody.java
@@ -28,10 +28,12 @@ import org.apache.juneau.collections.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
+import org.apache.juneau.marshall.*;
 import org.apache.juneau.oapi.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.parser.ParseException;
 import org.apache.juneau.reflect.*;
+import org.apache.juneau.serializer.*;
 import org.apache.juneau.utils.*;
 
 /**
@@ -1612,6 +1614,48 @@ public class RestResponseBody implements HttpEntity {
                return new FluentStringAssertion<>(asString(), response);
        }
 
+       /**
+        * Provides the ability to perform fluent-style assertions on this 
response body.
+        *
+        * <p>
+        * This method is called directly from the {@link 
RestResponse#assertBody(Class)} method to instantiate a fluent assertions 
object.
+        *
+        * <p>
+        * Combines the functionality of {@link #as(Class)} with {@link 
#assertThat()} by converting the body to the specified
+        * bean and then serializing it to simplified JSON for easy string 
comparison.
+        *
+        * <h5 class='section'>Examples:</h5>
+        * <p class='bcode w800'>
+        *      <jc>// Validates the response body bean is the expected 
value.</jc>
+        *      client
+        *              .get(<js>"/myBean"</js>)
+        *              .run()
+        *              
.assertBody(MyBean.<js>class</js>).equals(<js>"{foo:'bar'}"</js>);
+        * </p>
+        *
+        * <ul class='notes'>
+        *      <li>
+        *              If no charset was found on the 
<code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed.
+        *  <li>
+        *              If {@link #cache()} or {@link RestResponse#cacheBody()} 
has been called, this method can be can be called multiple times and/or 
combined with
+        *              other methods that retrieve the content of the 
response.  Otherwise a {@link RestCallException}
+        *              with an inner {@link IllegalStateException} will be 
thrown.
+        *      <li>
+        *              The input stream is automatically closed after this 
call.
+        * </ul>
+        *
+        * @param type The object type to create.
+        * @return A new fluent assertion object.
+        * @throws RestCallException If REST call failed.
+        */
+       public FluentStringAssertion<RestResponse> assertThat(Class<?> type) 
throws RestCallException {
+               try {
+                       return new 
FluentStringAssertion<>(SimpleJson.DEFAULT.write(as(type)), response);
+               } catch (SerializeException e) {
+                       throw new RestCallException(e);
+               }
+       }
+
        
//------------------------------------------------------------------------------------------------------------------
        // HttpEntity passthrough methods.
        
//------------------------------------------------------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
index aa62d64..6d71272 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -38,8 +38,6 @@ import org.apache.juneau.*;
 import org.apache.juneau.config.*;
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.http.*;
-import org.apache.juneau.http.ReaderResource;
-import org.apache.juneau.http.StreamResource;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.http.annotation.Body;
 import org.apache.juneau.http.annotation.FormData;
@@ -1461,7 +1459,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                String s = context.getClasspathResourceAsString(name, 
getLocale());
                if (s == null)
                        return null;
-               ResolvingReaderResource.Builder b = 
ResolvingReaderResource.create().mediaType(mediaType).contents(s);
+               ResolvingResourceReaderBuilder b = 
ResolvingReaderResource.create().mediaType(mediaType).contents(s);
                if (resolveVars)
                        b.varResolver(getVarResolverSession());
                if (cached)
@@ -1516,7 +1514,7 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                InputStream is = context.getClasspathResource(name, 
getLocale());
                if (is == null)
                        return null;
-               StreamResource.Builder b = 
StreamResource.create().mediaType(mediaType).contents(is);
+               StreamResourceBuilder b = 
StreamResource.create().mediaType(mediaType).contents(is);
                if (cached)
                        b.cached();
                return b.build();

Reply via email to