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 ce45e0c  org.apache.juneau.http improvements.
ce45e0c is described below

commit ce45e0cf564d3637627778416f26422ecf1faed9
Author: JamesBognar <[email protected]>
AuthorDate: Wed Jul 8 16:52:40 2020 -0400

    org.apache.juneau.http improvements.
---
 .../org/apache/juneau/http/BasicHttpResource.java  | 292 +++++++++++++++++++++
 .../http/{Resource.java => HttpResource.java}      |  67 ++++-
 .../org/apache/juneau/http/ReaderResource.java     | 202 +++++++-------
 .../apache/juneau/http/ReaderResourceBuilder.java  | 153 -----------
 .../juneau/http/ResolvingReaderResource.java       | 177 ++++++++++---
 .../http/ResolvingResourceReaderBuilder.java       |  98 -------
 .../org/apache/juneau/http/StreamResource.java     | 196 ++++++++------
 .../apache/juneau/http/StreamResourceBuilder.java  | 153 -----------
 .../main/ConfigurablePropertyCodeGenerator.java    |   7 +-
 .../rest/client2/Remote_CommonInterfaces_Test.java |  20 +-
 .../rest/client2/RestClient_BasicCalls_Test.java   |  43 ++-
 .../org/apache/juneau/rest/client/RestCall.java    |  26 +-
 .../org/apache/juneau/rest/client2/RestClient.java |  32 +--
 .../apache/juneau/rest/client2/RestRequest.java    |  21 +-
 .../juneau/rest/client2/RestResponseBody.java      |  18 +-
 .../juneau/rest/helper/ReaderResourceTest.java     |  15 +-
 .../juneau/rest/helper/StreamResourceTest.java     |  15 +-
 .../java/org/apache/juneau/rest/RestRequest.java   |  19 +-
 18 files changed, 802 insertions(+), 752 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
new file mode 100644
index 0000000..c9b4ce4
--- /dev/null
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/BasicHttpResource.java
@@ -0,0 +1,292 @@
+// 
***************************************************************************************************************************
+// * 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.http.entity.*;
+import org.apache.juneau.collections.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.http.header.*;
+import org.apache.juneau.http.header.ContentType;
+
+/**
+ * An abstract subclass of all {@link HttpResource} objects.
+ */
+public class BasicHttpResource extends AbstractHttpEntity implements 
HttpResource  {
+
+       private final List<Header> headers = AList.of();
+       private Object content;
+       private boolean cache;
+
+       /**
+        * Creator.
+        *
+        * @return A new empty {@link BasicHttpResource} object.
+        */
+       public static BasicHttpResource create() {
+               return new BasicHttpResource();
+       }
+
+       /**
+        * Constructor.
+        */
+       public BasicHttpResource() {
+               super();
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param contentType
+        *      The content type of the contents.
+        *      <br>Can be <jk>null</jk>.
+        * @param contentEncoding
+        *      The content encoding of the contents.
+        *      <br>Can be <jk>null</jk>.
+        * @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>
+        */
+       public BasicHttpResource(ContentType contentType, ContentEncoding 
contentEncoding, Object content) {
+               setContentType(contentType);
+               setContentEncoding(contentEncoding);
+               this.content = content;
+       }
+
+       /**
+        * Returns the raw content of this resource.
+        *
+        * @return The raw content of this resource.
+        */
+       protected Object getRawContent() {
+               return content;
+       }
+
+       @Override
+       @FluentSetter
+       public BasicHttpResource chunked() {
+               super.setChunked(true);
+               return this;
+       }
+
+       @Override
+       @FluentSetter
+       public BasicHttpResource contentType(Header value) {
+               super.setContentType(value);
+               return this;
+       }
+
+       /**
+        * Shortcut for calling {@link #contentType(String)}.
+        *
+        * @param value The new <c>Content-Type</ header, or <jk>null</jk> to 
unset.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public BasicHttpResource contentType(String value) {
+               super.setContentType(value);
+               return this;
+       }
+
+       @Override
+       @FluentSetter
+       public BasicHttpResource contentEncoding(Header value) {
+               super.setContentEncoding(value);
+               return this;
+       }
+
+       /**
+        * Shortcut for calling {@link #setContentEncoding(String)}.
+        *
+        * @param value The new <c>Content-Encoding</ header, or <jk>null</jk> 
to unset.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public BasicHttpResource contentEncoding(String value) {
+               super.setContentEncoding(value);
+               return this;
+       }
+
+       /**
+        * Adds an arbitrary header to this resource.
+        *
+        * @param name The header name.
+        * @param val The header value.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public BasicHttpResource header(String name, Object val) {
+               if (name != null && val != null)
+                       headers.add(BasicHeader.of(name, val));
+               return this;
+       }
+
+       @Override
+       @FluentSetter
+       public BasicHttpResource header(Header value) {
+               if (value != null)
+                       headers.add(value);
+               return this;
+       }
+
+       /**
+        * Adds an arbitrary collection of headers to this resource.
+        *
+        * @param headers The headers to add to this resource.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public BasicHttpResource headers(List<Header> headers) {
+               this.headers.addAll(headers);
+               return this;
+       }
+
+       /**
+        * Adds an arbitrary collection of headers to this resource.
+        *
+        * @param headers The headers to add to this resource.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public BasicHttpResource headers(Header...headers) {
+               this.headers.addAll(Arrays.asList(headers));
+               return this;
+       }
+
+       /**
+        * Returns the first header with the specified name as a string.
+        *
+        * @param name The header name.
+        * @return The header value or <jk>null</jk> if header was not found.
+        */
+       public String getStringHeader(String name) {
+               Header h = getFirstHeader(name);
+               return h == null ? null : h.getValue();
+       }
+
+       /**
+        * Returns the first header with the specified name as a string.
+        *
+        * @param name The header name.
+        * @return The header or <jk>null</jk> if header was not found.
+        */
+       public Header getFirstHeader(String name) {
+               for (Header h : headers)
+                       if (h.getName().equals(name))
+                               return h;
+               return null;
+       }
+
+       /**
+        * Returns the last header with the specified name as a string.
+        *
+        * @param name The header name.
+        * @return The header or <jk>null</jk> if header was not found.
+        */
+       public Header getLastHeader(String name) {
+               for (ListIterator<Header> li = 
headers.listIterator(headers.size()); li.hasPrevious();) {
+                       Header h = li.previous();
+                       if (h.getName().equals(name))
+                               return h;
+               }
+               return null;
+       }
+
+       @Override
+       @FluentSetter
+       public BasicHttpResource content(Object value) {
+               this.content = value;
+               return this;
+       }
+
+       @Override
+       @FluentSetter
+       public BasicHttpResource cache() {
+               this.cache = true;
+               return this;
+       }
+
+       @Override /* Resource */
+       public List<Header> getHeaders() {
+               return Collections.unmodifiableList(headers);
+       }
+
+       @Override
+       public boolean isRepeatable() {
+               return cache || content instanceof File || content instanceof 
CharSequence || content instanceof byte[];
+       }
+
+       @Override
+       public long getContentLength() {
+               try {
+                       doCache();
+               } catch (IOException e) {
+                       throw new RuntimeException(e);
+               }
+               if (content instanceof byte[])
+                       return ((byte[])content).length;
+               if (content instanceof File)
+                       return ((File)content).length();
+               if (content instanceof CharSequence)
+                       return ((CharSequence)content).length();
+               return -1;
+       }
+
+       @Override
+       public InputStream getContent() throws IOException, 
UnsupportedOperationException {
+               if (content == null)
+                       return null;
+               if (content instanceof File)
+                       return new FileInputStream((File)content);
+               if (content instanceof byte[])
+                       return new ByteArrayInputStream((byte[])content);
+               if (content instanceof Reader)
+                       return new ReaderInputStream((Reader)content, 
IOUtils.UTF8);
+               if (content instanceof InputStream)
+                       return (InputStream)content;
+               return new ReaderInputStream(new 
StringReader(content.toString()),IOUtils.UTF8);
+       }
+
+       @Override
+       public void writeTo(OutputStream os) throws IOException {
+               if (content != null)
+                       IOUtils.pipe(content, os);
+               os.flush();
+       }
+
+       @Override
+       public boolean isStreaming() {
+               return (content instanceof InputStream || content instanceof 
Reader);
+       }
+
+       private void doCache() throws IOException {
+               if (cache)
+                       if (content instanceof File || content instanceof 
InputStream || content instanceof Reader)
+                               content = IOUtils.readBytes(content);
+       }
+
+       // <FluentSetters>
+
+       // </FluentSetters>
+}
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Resource.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HttpResource.java
similarity index 53%
rename from 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Resource.java
rename to 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HttpResource.java
index d2cbfe9..a117fdc 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/Resource.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HttpResource.java
@@ -17,12 +17,13 @@ import java.util.*;
 import org.apache.http.*;
 import org.apache.http.Header;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.internal.*;
 
 /**
  * An extension of an {@link HttpEntity} that also includes arbitrary headers.
  */
 @Response
-public interface Resource extends HttpEntity {
+public interface HttpResource extends HttpEntity {
 
        /**
         * Returns the list of headers associated with this resource.
@@ -31,4 +32,68 @@ public interface Resource extends HttpEntity {
         */
        @ResponseHeader("*")
        List<Header> getHeaders();
+
+       /**
+        * Shortcut for calling {@link #chunked()} with <jk>true</jk>.
+        *
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public HttpResource chunked();
+
+       /**
+        * Shortcut for calling {@link #contentType(Header)}.
+        *
+        * @param value The new <c>Content-Type</ header, or <jk>null</jk> to 
unset.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public HttpResource contentType(Header value);
+
+       /**
+        * Shortcut for calling {@link #contentEncoding(Header)}.
+        *
+        * @param value The new <c>Content-Encoding</ header, or <jk>null</jk> 
to unset.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public HttpResource contentEncoding(Header value);
+
+       /**
+        * Adds an arbitrary header to this resource.
+        *
+        * @param value The header.  Ignored if <jk>null</jk>.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public HttpResource header(Header value);
+
+       /**
+        * Sets the content of this resource.
+        *
+        * <p>
+        * 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>
+        *
+        * @param value The new contents of this resource.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public HttpResource content(Object value);
+
+       /**
+        * Specifies that the contents of this resource should be cached into 
an internal byte array so that it can
+        * be read multiple times.
+        *
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public HttpResource cache();
 }
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 f0e6ccd..c1d1595 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
@@ -12,13 +12,14 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.http;
 
-import static org.apache.juneau.internal.IOUtils.*;
-
 import java.io.*;
 import java.util.*;
 
-import org.apache.juneau.collections.*;
+import org.apache.http.Header;
+import org.apache.juneau.assertions.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.http.header.*;
+import org.apache.juneau.internal.*;
 
 /**
  * Represents the contents of a text file with convenience methods for 
resolving SVL variables and adding
@@ -31,130 +32,141 @@ import org.apache.juneau.http.annotation.*;
  * <l>ReaderResources</l> are meant to be thread-safe and reusable objects.
  * <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 ReaderResourceBuilder}.
- *
  * <ul class='seealso'>
  *     <li class='link'>{@doc juneau-rest-server.RestMethod.ReaderResource}
  * </ul>
  */
 @Response
-public class ReaderResource {
-
-       private final MediaType mediaType;
-       private final Map<String,Object> headers;
+public class ReaderResource extends BasicHttpResource {
 
-       @SuppressWarnings("javadoc")
-       protected final Object contents;
+       /**
+        * Creator.
+        *
+        * @return A new empty {@link ReaderResource} object.
+        */
+       public static ReaderResource create() {
+               return new ReaderResource();
+       }
 
        /**
         * Constructor.
-        *
-        * @param b Builder containing values to initialize this object with.
-        * @throws IOException Thrown by underlying stream.
         */
-       protected ReaderResource(ReaderResourceBuilder b) throws IOException {
-               this(b.mediaType, b.headers, b.cached, b.contents);
+       public ReaderResource() {
+               super();
        }
 
        /**
         * Constructor.
         *
-        * @param mediaType The resource media type.
-        * @param headers The HTTP response headers for this streamed resource.
-        * @param cached
-        *      Identifies if this resource is cached in memory.
-        *      <br>If <jk>true</jk>, the contents will be loaded into a String 
for fast retrieval.
-        * @param contents
-        *      The resource contents.
-        *      <br>If multiple contents are specified, the results will be 
concatenated.
-        *      <br>Contents can be any of the following:
+        * @param contentType
+        *      The content type of the contents.
+        *      <br>Can be <jk>null</jk>.
+        * @param contentEncoding
+        *      The content encoding of the contents.
+        *      <br>Can be <jk>null</jk>.
+        * @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>
-        * @throws IOException Thrown by underlying stream.
+        * </ul>
         */
-       public ReaderResource(MediaType mediaType, Map<String,Object> headers, 
boolean cached, Object contents) throws IOException {
-               this.mediaType = mediaType;
-               this.headers = AMap.unmodifiable(headers);
-               this.contents = cached ? read(contents) : contents;
+       public ReaderResource(ContentType contentType, ContentEncoding 
contentEncoding, Object content) {
+               super(contentType, contentEncoding, content);
        }
 
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Builder
-       
//-----------------------------------------------------------------------------------------------------------------
-
        /**
-        * Creates a new instance of a {@link ReaderResourceBuilder} for this 
class.
+        * Converts the contents of this entity as a byte array.
         *
-        * @return A new instance of a {@link ReaderResourceBuilder}.
+        * @return The contents of this entity as a byte array.
+        * @throws IOException If a problem occurred while trying to read the 
byte array.
         */
-       public static ReaderResourceBuilder create() {
-               return new ReaderResourceBuilder();
+       public String asString() throws IOException {
+               return IOUtils.read(getRawContent());
        }
 
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Properties
-       
//-----------------------------------------------------------------------------------------------------------------
-
        /**
-        * Get the HTTP response headers.
+        * Returns an assertion on the contents of this resource.
         *
-        * @return
-        *      The HTTP response headers.
-        *      <br>An unmodifiable map.
-        *      <br>Never <jk>null</jk>.
+        * @return A new fluent assertion.
+        * @throws IOException If a problem occurred while trying to read the 
byte array.
         */
-       @ResponseHeader("*")
-       public Map<String,Object> getHeaders() {
-               return headers;
+       public FluentStringAssertion<ReaderResource> assertString() throws 
IOException {
+               return new FluentStringAssertion<>(asString(), this);
        }
 
-       /**
-        * TODO
-        *
-        * @param w - TODO
-        * @return TODO
-        * @throws IOException TODO
-        */
-       @ResponseBody
-       public Writer writeTo(Writer w) throws IOException {
-               if (contents != null)
-                       pipe(contents, w);
-               return w;
-       }
-
-       /**
-        * TODO
-        *
-        * @return TODO
-        */
-       @ResponseHeader("Content-Type")
-       public String getMediaType() {
-               return mediaType == null ? null : mediaType.toString();
-       }
-
-       @Override /* Object */
-       public String toString() {
-               try {
-                       return writeTo(new StringWriter()).toString();
-               } catch (IOException e) {
-                       throw new RuntimeException(e);
-               }
-       }
-
-       /**
-        * Returns the contents of this resource.
-        *
-        * @return The contents of this resource.
-        */
-       public Reader getContents() {
-               if (contents instanceof Reader) {
-                       return (Reader)contents;
-               }
-               return new StringReader(toString());
-       }
+       // <FluentSetters>
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ReaderResource cache() {
+               super.cache();
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ReaderResource chunked() {
+               super.chunked();
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ReaderResource content(Object value) {
+               super.content(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ReaderResource contentEncoding(String value) {
+               super.contentEncoding(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ReaderResource contentEncoding(Header value) {
+               super.contentEncoding(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ReaderResource contentType(String value) {
+               super.contentType(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ReaderResource contentType(Header value) {
+               super.contentType(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ReaderResource header(Header value) {
+               super.header(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ReaderResource header(String name, Object val) {
+               super.header(name, val);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ReaderResource headers(Header...headers) {
+               super.headers(headers);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ReaderResource headers(List<Header> headers) {
+               super.headers(headers);
+               return this;
+       }
+
+       // </FluentSetters>
 }
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
deleted file mode 100644
index 8991aa4..0000000
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ReaderResourceBuilder.java
+++ /dev/null
@@ -1,153 +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.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 {
-
-       Object contents;
-       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) {
-               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-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
index 917da4b..e4c9673 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingReaderResource.java
@@ -12,12 +12,12 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.http;
 
-import static org.apache.juneau.internal.IOUtils.*;
-
 import java.io.*;
 import java.util.*;
 
-import org.apache.juneau.http.annotation.*;
+import org.apache.http.*;
+import org.apache.juneau.http.header.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.svl.*;
 
 /**
@@ -25,67 +25,160 @@ import org.apache.juneau.svl.*;
  */
 public class ResolvingReaderResource extends ReaderResource {
 
-       private final VarResolverSession varSession;
+       private VarResolverSession varSession;
 
        /**
-        * Constructor.
+        * Creator.
         *
-        * @param b Builder containing values to initialize this object with.
-        * @throws IOException Thrown by underlying stream.
+        * @return A new empty {@link ReaderResource} object.
+        */
+       public static ResolvingReaderResource create() {
+               return new ResolvingReaderResource();
+       }
+
+       /**
+        * Constructor.
         */
-       protected ResolvingReaderResource(ResolvingResourceReaderBuilder b) 
throws IOException {
-               super(b);
-               this.varSession = b.varResolver;
+       public ResolvingReaderResource() {
+               super();
        }
 
        /**
         * Constructor.
         *
-        * @param mediaType The resource media type.
-        * @param headers The HTTP response headers for this streamed resource.
-        * @param varSession Optional variable resolver for resolving variables 
in the string.
-        * @param cached
-        *      Identifies if this resource is cached in memory.
-        *      <br>If <jk>true</jk>, the contents will be loaded into a String 
for fast retrieval.
-        * @param contents
-        *      The resource contents.
-        *      <br>If multiple contents are specified, the results will be 
concatenated.
-        *      <br>Contents can be any of the following:
+        * @param contentType
+        *      The content type of the contents.
+        *      <br>Can be <jk>null</jk>.
+        * @param contentEncoding
+        *      The content encoding of the contents.
+        *      <br>Can be <jk>null</jk>.
+        * @param varSession Var resolver session for resolving SVL variables.
+        * @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>
-        * @throws IOException Thrown by underlying stream.
+        * </ul>
         */
-       public ResolvingReaderResource(MediaType mediaType, Map<String,Object> 
headers, boolean cached, VarResolverSession varSession, Object...contents) 
throws IOException {
-               super(mediaType, headers, cached, contents);
+       public ResolvingReaderResource(ContentType contentType, ContentEncoding 
contentEncoding, VarResolverSession varSession, Object content) {
+               super(contentType, contentEncoding, content);
                this.varSession = varSession;
        }
 
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Builder
-       
//-----------------------------------------------------------------------------------------------------------------
-
        /**
-        * Creates a new instance of a {@link ResolvingResourceReaderBuilder} 
for this class.
+        * Converts the contents of this entity as a byte array.
         *
-        * @return A new instance of a {@link ResolvingResourceReaderBuilder}.
+        * @return The contents of this entity as a byte array.
+        * @throws IOException If a problem occurred while trying to read the 
byte array.
         */
-       public static ResolvingResourceReaderBuilder create() {
-               return new ResolvingResourceReaderBuilder();
-       }
-
-       @ResponseBody
-       @Override /* Writeable */
-       public Writer writeTo(Writer w) throws IOException {
-               if (contents != null) {
-                       if (varSession == null)
-                               pipe(contents, w);
-                       else
-                               varSession.resolveTo(read(contents), w);
+       @Override
+       public String asString() throws IOException {
+               if (varSession == null)
+                       return super.asString();
+               StringWriter sw = new StringWriter();
+               String s = IOUtils.read(getRawContent());
+               varSession.resolveTo(s, sw);
+               return sw.toString();
+       }
+
+       @Override
+       public void writeTo(OutputStream os) throws IOException {
+               if (varSession == null)
+                       super.writeTo(os);
+               else {
+                       try (OutputStreamWriter osw = new 
OutputStreamWriter(os, IOUtils.UTF8)) {
+                               String s = IOUtils.read(getRawContent());
+                               varSession.resolveTo(s, osw);
+                               osw.flush();
+                       }
                }
-               return w;
+               os.flush();
+       }
+
+       /**
+        * Sets the var resolver for resolving SVL variables.
+        *
+        * @param varSession - The var resolver session.
+        * @return This object (for method chaining).
+        */
+       @FluentSetter
+       public ResolvingReaderResource varResolver(VarResolverSession 
varSession) {
+               this.varSession = varSession;
+               return this;
+       }
+
+       // <FluentSetters>
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ResolvingReaderResource cache() {
+               super.cache();
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ResolvingReaderResource chunked() {
+               super.chunked();
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ResolvingReaderResource content(Object value) {
+               super.content(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ResolvingReaderResource contentEncoding(String value) {
+               super.contentEncoding(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ResolvingReaderResource contentEncoding(Header value) {
+               super.contentEncoding(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ResolvingReaderResource contentType(String value) {
+               super.contentType(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ResolvingReaderResource contentType(Header value) {
+               super.contentType(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ResolvingReaderResource header(Header value) {
+               super.header(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ResolvingReaderResource header(String name, Object val) {
+               super.header(name, val);
+               return this;
        }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ResolvingReaderResource headers(Header...headers) {
+               super.headers(headers);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public ResolvingReaderResource headers(List<Header> headers) {
+               super.headers(headers);
+               return this;
+       }
+
+       // </FluentSetters>
 }
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
deleted file mode 100644
index 838c0f5..0000000
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/ResolvingResourceReaderBuilder.java
+++ /dev/null
@@ -1,98 +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.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 3505a38..2115ec1 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
@@ -12,13 +12,14 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.http;
 
-import static org.apache.juneau.internal.IOUtils.*;
-
 import java.io.*;
 import java.util.*;
 
-import org.apache.juneau.collections.*;
+import org.apache.http.Header;
+import org.apache.juneau.assertions.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.http.header.*;
+import org.apache.juneau.internal.*;
 
 /**
  * Represents the contents of a byte stream file with convenience methods for 
adding HTTP response headers.
@@ -30,118 +31,141 @@ import org.apache.juneau.http.annotation.*;
  * <l>StreamResources</l> are meant to be thread-safe and reusable objects.
  * <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 StreamResourceBuilder}.
- *
  * <ul class='seealso'>
  *     <li class='link'>{@doc juneau-rest-server.RestMethod.StreamResource}
  * </ul>
  */
 @Response
-public class StreamResource {
+public class StreamResource extends BasicHttpResource {
 
-       private final MediaType mediaType;
-       private final Object contents;
-       private final Map<String,Object> headers;
+       /**
+        * Creator.
+        *
+        * @return A new empty {@link ReaderResource} object.
+        */
+       public static StreamResource create() {
+               return new StreamResource();
+       }
 
-       StreamResource(StreamResourceBuilder b) throws IOException {
-               this(b.mediaType, b.headers, b.cached, b.contents);
+       /**
+        * Constructor.
+        */
+       public StreamResource() {
+               super();
        }
 
        /**
         * Constructor.
         *
-        * @param mediaType The resource media type.
-        * @param headers The HTTP response headers for this streamed resource.
-        * @param cached
-        *      Identifies if this stream resource is cached in memory.
-        *      <br>If <jk>true</jk>, the contents will be loaded into a byte 
array for fast retrieval.
-        * @param contents
-        *      The resource contents.
-        *      <br>If multiple contents are specified, the results will be 
concatenated.
-        *      <br>Contents can be any of the following:
+        * @param contentType
+        *      The content type of the contents.
+        *      <br>Can be <jk>null</jk>.
+        * @param contentEncoding
+        *      The content encoding of the contents.
+        *      <br>Can be <jk>null</jk>.
+        * @param content
+        *      The content.
+        *      <br>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.
+        *              <li><c><jk>byte</jk>[]</c>.
         *      </ul>
-        * @throws IOException Thrown by underlying stream.
+        * </ul>
         */
-       public StreamResource(MediaType mediaType, Map<String,Object> headers, 
boolean cached, Object contents) throws IOException {
-               this.mediaType = mediaType;
-               this.headers = AMap.unmodifiable(headers);
-               this.contents = cached ? readBytes(contents) : contents;
+       public StreamResource(ContentType contentType, ContentEncoding 
contentEncoding, Object content) {
+               super(contentType, contentEncoding, content);
        }
 
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Builder
-       
//-----------------------------------------------------------------------------------------------------------------
-
        /**
-        * Creates a new instance of a {@link StreamResourceBuilder} for this 
class.
+        * Converts the contents of this entity as a byte array.
         *
-        * @return A new instance of a {@link StreamResourceBuilder}.
+        * @return The contents of this entity as a byte array.
+        * @throws IOException If a problem occurred while trying to read the 
byte array.
         */
-       public static StreamResourceBuilder create() {
-               return new StreamResourceBuilder();
+       public byte[] asBytes() throws IOException {
+               return IOUtils.readBytes(getRawContent());
        }
 
        /**
-        * Get the HTTP response headers.
+        * Returns an assertion on the contents of this resource.
         *
-        * @return
-        *      The HTTP response headers.
-        *      <br>An unmodifiable map.
-        *      <br>Never <jk>null</jk>.
+        * @return A new fluent assertion.
+        * @throws IOException If a problem occurred while trying to read the 
byte array.
         */
-       @ResponseHeader("*")
-       public Map<String,Object> getHeaders() {
-               return headers;
+       public FluentByteArrayAssertion<StreamResource> assertBytes() throws 
IOException {
+               return new FluentByteArrayAssertion<>(asBytes(), this);
        }
 
-       /**
-        * TODO
-        *
-        * @param os TODO
-        * @throws IOException TODO
-        */
-       @ResponseBody
-       public void streamTo(OutputStream os) throws IOException {
-               if (contents != null)
-                       pipe(contents, os);
-               os.flush();
-       }
-
-       /**
-        * TODO
-        *
-        * @return TODO
-        */
-       @ResponseHeader("Content-Type")
-       public String getMediaType() {
-               return mediaType == null ? null : mediaType.toString();
-       }
-
-       /**
-        * Returns the contents of this stream resource.
-        *
-        * @return The contents of this stream resource.
-        * @throws IOException Thrown by underlying stream.
-        */
-       public InputStream getContents() throws IOException {
-               Object c = contents;
-               if (c != null) {
-                       if (c instanceof byte[])
-                               return new ByteArrayInputStream((byte[])c);
-                       else if (c instanceof InputStream)
-                               return (InputStream)c;
-                       else if (c instanceof File)
-                               return new FileInputStream((File)c);
-                       else if (c instanceof CharSequence)
-                               return new 
ByteArrayInputStream((((CharSequence)c).toString().getBytes(UTF8)));
-               }
-               return null;
-       }
+       // <FluentSetters>
+
+       @Override /* GENERATED - BasicHttpResource */
+       public StreamResource cache() {
+               super.cache();
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public StreamResource chunked() {
+               super.chunked();
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public StreamResource content(Object value) {
+               super.content(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public StreamResource contentEncoding(String value) {
+               super.contentEncoding(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public StreamResource contentEncoding(Header value) {
+               super.contentEncoding(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public StreamResource contentType(String value) {
+               super.contentType(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public StreamResource contentType(Header value) {
+               super.contentType(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public StreamResource header(Header value) {
+               super.header(value);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public StreamResource header(String name, Object val) {
+               super.header(name, val);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public StreamResource headers(Header...headers) {
+               super.headers(headers);
+               return this;
+       }
+
+       @Override /* GENERATED - BasicHttpResource */
+       public StreamResource headers(List<Header> headers) {
+               super.headers(headers);
+               return this;
+       }
+
+       // </FluentSetters>
 }
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
deleted file mode 100644
index e9770ec..0000000
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/StreamResourceBuilder.java
+++ /dev/null
@@ -1,153 +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.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 {
-       Object contents = null;
-       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) {
-               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 6add84f..2bf2796 100644
--- 
a/juneau-releng/juneau-all/src/java/main/ConfigurablePropertyCodeGenerator.java
+++ 
b/juneau-releng/juneau-all/src/java/main/ConfigurablePropertyCodeGenerator.java
@@ -178,9 +178,10 @@ public class ConfigurablePropertyCodeGenerator {
                ThrowableAssertion.class,
                ObjectAssertion.class,
 
-               ReaderResourceBuilder.class,
-               StreamResourceBuilder.class,
-               ResolvingResourceReaderBuilder.class,
+               BasicHttpResource.class,
+               StreamResource.class,
+               ReaderResource.class,
+               ResolvingReaderResource.class,
                ExecutableInfo.class,
                ConstructorInfo.class,
                MethodInfo.class
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_CommonInterfaces_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_CommonInterfaces_Test.java
index ef6fa97..bff9079 100644
--- 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_CommonInterfaces_Test.java
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_CommonInterfaces_Test.java
@@ -211,11 +211,11 @@ public class Remote_CommonInterfaces_Test {
        public static class D1 implements D {
                @Override
                public StreamResource streamResource() throws IOException {
-                       return 
StreamResource.create().mediaType("text/foo").contents("foo".getBytes()).header("Foo","foo").headers(ETag.of("bar")).build();
+                       return 
StreamResource.create().contentType("text/foo").content("foo".getBytes()).header("Foo","foo").headers(ETag.of("bar"));
                }
                @Override
                public ReaderResource readerResource() throws IOException {
-                       return 
ReaderResource.create().mediaType("text/foo").contents("foo").header("Foo","foo").headers(ETag.of("bar")).build();
+                       return 
ReaderResource.create().contentType("text/foo").content("foo".getBytes()).header("Foo","foo").headers(ETag.of("bar"));
                }
        }
 
@@ -223,15 +223,15 @@ public class Remote_CommonInterfaces_Test {
        public void d01_streamResource_readerResource() throws Exception {
                D x = MockRestClient.build(D1.class).getRemote(D.class);
                StreamResource sr = x.streamResource();
-               assertEquals("foo",IOUtils.read(sr.getContents()));
-               assertEquals("foo",sr.getHeaders().get("Foo"));
-               assertEquals("bar",sr.getHeaders().get("ETag"));
-               assertEquals("text/foo",sr.getMediaType().toString());
+               assertEquals("foo",IOUtils.read(sr.getContent()));
+               assertEquals("foo",sr.getStringHeader("Foo"));
+               assertEquals("bar",sr.getStringHeader("ETag"));
+               
assertEquals("text/foo",sr.getContentType().getValue().toString());
                ReaderResource rr = x.readerResource();
-               assertEquals("foo",IOUtils.read(rr.getContents()));
-               assertEquals("foo",rr.getHeaders().get("Foo"));
-               assertEquals("bar",rr.getHeaders().get("ETag"));
-               assertEquals("text/foo",rr.getMediaType().toString());
+               assertEquals("foo",IOUtils.read(rr.getContent()));
+               assertEquals("foo",rr.getStringHeader("Foo"));
+               assertEquals("bar",rr.getStringHeader("ETag"));
+               
assertEquals("text/foo",rr.getContentType().getValue().toString());
        }
 
        
//-----------------------------------------------------------------------------------------------------------------
diff --git 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_BasicCalls_Test.java
 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_BasicCalls_Test.java
index bd6d582..ed336f5 100644
--- 
a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_BasicCalls_Test.java
+++ 
b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RestClient_BasicCalls_Test.java
@@ -163,10 +163,8 @@ public class RestClient_BasicCalls_Test {
                List<Object> bodies = AList.<Object>of(
                        new StringReader("{f:1}"),
                        new ByteArrayInputStream("{f:1}".getBytes()),
-                       ReaderResource.create().contents("{f:1}").build(),
-                       ReaderResource.create().contents("{f:1}"),
-                       StreamResource.create().contents("{f:1}").build(),
-                       StreamResource.create().contents("{f:1}"),
+                       ReaderResource.create().content("{f:1}"),
+                       StreamResource.create().content("{f:1}"),
                        bean,
                        new StringEntity("{f:1}"),
                        pairs("f",1)
@@ -209,8 +207,8 @@ public class RestClient_BasicCalls_Test {
                List<Object> bodies = AList.<Object>of(
                        new StringReader("{f:1}"),
                        new ByteArrayInputStream("{f:1}".getBytes()),
-                       ReaderResource.create().contents("{f:1}").build(),
-                       StreamResource.create().contents("{f:1}").build(),
+                       ReaderResource.create().content("{f:1}"),
+                       StreamResource.create().content("{f:1}"),
                        bean,
                        new StringEntity("{f:1}"),
                        pairs("f",1)
@@ -316,14 +314,14 @@ public class RestClient_BasicCalls_Test {
                        /*[ 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]*/ pair("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"),
+                       /*[ 6]*/ ReaderResource.create().content("f=1"),
+                       /*[ 7]*/ ReaderResource.create().content("f=1"),
+                       /*[ 8]*/ 
ReaderResource.create().content("f=1").contentType("application/x-www-form-urlencoded"),
+                       /*[ 9]*/ 
ReaderResource.create().content("f=1").contentType("application/x-www-form-urlencoded"),
+                       /*[10]*/ StreamResource.create().content("f=1"),
+                       /*[11]*/ StreamResource.create().content("f=1"),
+                       /*[12]*/ 
StreamResource.create().content("f=1").contentType("application/x-www-form-urlencoded"),
+                       /*[13]*/ 
StreamResource.create().content("f=1").contentType("application/x-www-form-urlencoded"),
                        /*[14]*/ s1,
                        /*[15]*/ s2
                );
@@ -331,15 +329,6 @@ public class RestClient_BasicCalls_Test {
                        
client().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*']");
                        
client().build().formPost("/bean",bodies.get(i)).accept("application/json+simple").run().assertBody().msg("Body
 {0} failed","#"+i).is("{f:1}");
                }
-
-               StreamResourceBuilder sr = new StreamResourceBuilder() {
-                       @Override
-                       public StreamResource build() throws IOException {
-                               throw new IOException("Foo");
-                       }
-               };
-
-               
assertThrown(()->client().build().formPost("/bean",sr)).contains("Foo");
        }
 
        @Test
@@ -363,8 +352,8 @@ public class RestClient_BasicCalls_Test {
                List<Object> bodies = AList.<Object>of(
                        new StringReader("{f:1}"),
                        new ByteArrayInputStream("{f:1}".getBytes()),
-                       ReaderResource.create().contents("{f:1}").build(),
-                       StreamResource.create().contents("{f:1}").build(),
+                       ReaderResource.create().content("{f:1}"),
+                       StreamResource.create().content("{f:1}"),
                        bean,
                        new StringEntity("{f:1}"),
                        pairs("f",1)
@@ -401,8 +390,8 @@ public class RestClient_BasicCalls_Test {
                List<Object> bodies = AList.<Object>of(
                        new StringReader("{f:1}"),
                        new ByteArrayInputStream("{f:1}".getBytes()),
-                       ReaderResource.create().contents("{f:1}").build(),
-                       StreamResource.create().contents("{f:1}").build(),
+                       ReaderResource.create().content("{f:1}"),
+                       StreamResource.create().content("{f:1}"),
                        bean,
                        new StringEntity("{f:1}"),
                        pairs("f",1)
diff --git 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
index 7a541ff..23f770e 100644
--- 
a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
+++ 
b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
@@ -2258,18 +2258,22 @@ public final class RestCall extends BeanSession 
implements Closeable {
                                return (T)getReader();
                        if (ic.equals(InputStream.class))
                                return (T)getInputStream();
-                       if (type.isType(ReaderResource.class) || 
type.isType(StreamResource.class)) {
-                               String mediaType = null;
-                               OMap headers = new OMap();
-                               for (Header h : response.getAllHeaders()) {
-                                       if 
(h.getName().equalsIgnoreCase("Content-Type"))
-                                               mediaType = h.getValue();
-                                       else
-                                               headers.put(h.getName(), 
h.getValue());
+                       if (type.isType(HttpResource.class)) {
+                               HttpResource r;
+                               try {
+                                       r = (HttpResource)type.newInstance();
+                                       for (Header h : 
response.getAllHeaders()) {
+                                               if 
(h.getName().equalsIgnoreCase("Content-Type"))
+                                                       r.contentType(h);
+                                               else if 
(h.getName().equalsIgnoreCase("Content-Encoding"))
+                                                       r.contentEncoding(h);
+                                               else
+                                                       r.header(h);
+                                       }
+                                       return (T)r;
+                               } catch (ExecutableException e) {
+                                       throw new IOException(e);
                                }
-                               if (type.isType(ReaderResource.class))
-                                       return 
(T)ReaderResource.create().headers(headers).mediaType(mediaType).contents(getReader()).build();
-                               return 
(T)StreamResource.create().headers(headers).mediaType(mediaType).contents(getInputStream()).build();
                        }
 
                        connect(type);
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 a97f0eb..8325854 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
@@ -2240,14 +2240,10 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
         *              <li>
         *                      {@link InputStream} - Raw contents of {@code 
InputStream} will be serialized to remote resource.
         *              <li>
-        *                      {@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>
-        *                      {@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>
         *                      {@link Object} - POJO to be converted to text 
using the {@link Serializer} registered with the
         *                      {@link RestClient}.
         *              <li>
-        *                      {@link HttpEntity} - Bypass Juneau 
serialization and pass HttpEntity directly to HttpClient.
+        *                      {@link HttpEntity} / {@link HttpResource} - 
Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
         *              <li>
         *                      {@link NameValuePairSupplier} - Converted to a 
URL-encoded FORM post.
         *              <li>
@@ -2339,14 +2335,10 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
         *              <li>
         *                      {@link InputStream} - Raw contents of {@code 
InputStream} will be serialized to remote resource.
         *              <li>
-        *                      {@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>
-        *                      {@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>
         *                      {@link Object} - POJO to be converted to text 
using the {@link Serializer} registered with the
         *                      {@link RestClient}.
         *              <li>
-        *                      {@link HttpEntity} - Bypass Juneau 
serialization and pass HttpEntity directly to HttpClient.
+        *                      {@link HttpEntity} / {@link HttpResource} - 
Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
         *              <li>
         *                      {@link NameValuePairSupplier} - Converted to a 
URL-encoded FORM post.
         *              <li>
@@ -2525,6 +2517,10 @@ public class RestClient extends BeanContext implements 
HttpClient, Closeable, Re
                                return req.body(new 
UrlEncodedFormEntity(Arrays.asList((NameValuePair[])body)));
                        if (body instanceof NameValuePairSupplier)
                                return req.body(new 
UrlEncodedFormEntity((NameValuePairSupplier)body));
+                       if (body instanceof HttpResource) {
+                               for (Header h : 
((HttpResource)body).getHeaders())
+                                       req.header(h);
+                       }
                        if (body instanceof HttpEntity) {
                                HttpEntity e = (HttpEntity)body;
                                if (e.getContentType() == null)
@@ -2533,22 +2529,6 @@ 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.getMediaType() == 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.getMediaType() == null)
-                                       
req.contentType("application/x-www-form-urlencoded");
-                               return req.body(r);
-                       }
                        return req.body(new SerializedHttpEntity(body, 
urlEncodingSerializer, null, null));
                } catch (IOException e) {
                        throw new RestCallException(null, e, "Could not read 
form post body.");
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 58a5ab6..43f5e51 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
@@ -2851,28 +2851,17 @@ public class RestRequest extends BeanSession implements 
HttpUriRequest, Configur
                                        entity = new 
UrlEncodedFormEntity(formData);
                                else if (input2 instanceof 
NameValuePairSupplier)
                                        entity = new 
UrlEncodedFormEntity((NameValuePairSupplier)input2);
+                               else if (input2 instanceof HttpResource) {
+                                       HttpResource r = (HttpResource)input2;
+                                       headers(r.getHeaders());
+                                       entity = (HttpEntity)input2;
+                               }
                                else if (input2 instanceof HttpEntity)
                                        entity = (HttpEntity)input2;
                                else if (input2 instanceof Reader)
                                        entity = new 
StringEntity(IOUtils.read((Reader)input2), getRequestContentType(TEXT_PLAIN));
                                else if (input2 instanceof InputStream)
                                        entity = new 
InputStreamEntity((InputStream)input2, 
getRequestContentType(ContentType.APPLICATION_OCTET_STREAM));
-                               else if (input2 instanceof ReaderResource || 
input2 instanceof ReaderResourceBuilder) {
-                                       if (input2 instanceof 
ReaderResourceBuilder)
-                                               input2 = 
((ReaderResourceBuilder)input2).build();
-                                       ReaderResource r = 
(ReaderResource)input2;
-                                       contentType(r.getMediaType());
-                                       headers(r.getHeaders());
-                                       entity = new 
StringEntity(IOUtils.read(r.getContents()), getRequestContentType(TEXT_PLAIN));
-                               }
-                               else if (input2 instanceof StreamResource || 
input2 instanceof StreamResourceBuilder) {
-                                       if (input2 instanceof 
StreamResourceBuilder)
-                                               input2 = 
((StreamResourceBuilder)input2).build();
-                                       StreamResource r = 
(StreamResource)input2;
-                                       contentType(r.getMediaType());
-                                       headers(r.getHeaders());
-                                       entity = new 
InputStreamEntity(r.getContents(), 
getRequestContentType(ContentType.APPLICATION_OCTET_STREAM));
-                               }
                                else if (serializer != null)
                                        entity = new 
SerializedHttpEntity(input2, serializer, requestBodySchema, contentType);
                                else {
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 b13946c..94df46d 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
@@ -758,18 +758,18 @@ public class RestResponseBody implements HttpEntity {
                        if (type.isType(HttpResponse.class))
                                return (T)response;
 
-                       if (type.isType(ReaderResource.class) || 
type.isType(StreamResource.class)) {
-                               String mediaType = null;
-                               OMap headers = new OMap();
+                       if (type.isType(HttpResource.class)) {
+                               HttpResource r = 
(HttpResource)type.newInstance();
                                for (Header h : response.getAllHeaders()) {
                                        if 
(h.getName().equalsIgnoreCase("Content-Type"))
-                                               mediaType = h.getValue();
+                                               r.contentType(h);
+                                       else if 
(h.getName().equalsIgnoreCase("Content-Encoding"))
+                                               r.contentEncoding(h);
                                        else
-                                               headers.put(h.getName(), 
h.getValue());
+                                               r.header(h);
                                }
-                               if (type.isType(ReaderResource.class))
-                                       return 
(T)ReaderResource.create().headers(headers).mediaType(mediaType).contents(asReader()).build();
-                               return 
(T)StreamResource.create().headers(headers).mediaType(mediaType).contents(asInputStream()).build();
+                               r.content(asInputStream());
+                               return (T)r;
                        }
 
                        String ct = 
firstNonEmpty(response.getHeader("Content-Type").asStringOrElse("text/plain"));
@@ -824,7 +824,7 @@ public class RestResponseBody implements HttpEntity {
                                response.getStringHeader("Content-Type")
                        );
 
-               } catch (ParseException | IOException e) {
+               } catch (ParseException | IOException | ExecutableException e) {
                        response.close();
                        throw new RestCallException(response, e, "Could not 
parse response body.");
                }
diff --git 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/helper/ReaderResourceTest.java
 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/helper/ReaderResourceTest.java
index ec8f619..9397ed9 100644
--- 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/helper/ReaderResourceTest.java
+++ 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/helper/ReaderResourceTest.java
@@ -17,7 +17,6 @@ import static org.junit.runners.MethodSorters.*;
 import java.io.*;
 
 import org.apache.juneau.http.*;
-import org.apache.juneau.http.ReaderResource;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.mock2.*;
@@ -31,37 +30,37 @@ public class ReaderResourceTest {
 
                @RestMethod
                public ReaderResource a01() throws Exception {
-                       return ReaderResource.create().contents("foo").build();
+                       return ReaderResource.create().content("foo");
                }
 
                @RestMethod
                public ReaderResource a02() throws Exception {
-                       return ReaderResource.create().header("Foo", 
"Bar").build();
+                       return ReaderResource.create().header("Foo", "Bar");
                }
 
                @RestMethod
                public ReaderResource a03() throws Exception {
-                       return 
ReaderResource.create().mediaType(MediaType.JSON).build();
+                       return 
ReaderResource.create().contentType("application/json");
                }
 
                @RestMethod
                public ReaderResource a04(RestRequest req) throws Exception {
-                       return 
ResolvingReaderResource.create().varResolver(req.getVarResolverSession()).contents("$RQ{foo}").build();
+                       return 
ResolvingReaderResource.create().varResolver(req.getVarResolverSession()).content("$RQ{foo}");
                }
 
                @RestMethod
                public ReaderResource a05() throws Exception {
-                       return ReaderResource.create().contents(new 
ByteArrayInputStream("foo".getBytes())).build();
+                       return ReaderResource.create().content(new 
ByteArrayInputStream("foo".getBytes()));
                }
 
                @RestMethod
                public ReaderResource a06() throws Exception {
-                       return ReaderResource.create().contents(new 
StringReader("foo")).build();
+                       return ReaderResource.create().content(new 
StringReader("foo"));
                }
 
                @RestMethod
                public ReaderResource a07() throws Exception {
-                       return ReaderResource.create().contents(new 
StringBuilder("foo")).build();
+                       return ReaderResource.create().content(new 
StringBuilder("foo"));
                }
        }
 
diff --git 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/helper/StreamResourceTest.java
 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/helper/StreamResourceTest.java
index c323d19..8e74e97 100644
--- 
a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/helper/StreamResourceTest.java
+++ 
b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/helper/StreamResourceTest.java
@@ -16,7 +16,6 @@ import static org.junit.runners.MethodSorters.*;
 
 import java.io.*;
 
-import org.apache.juneau.http.*;
 import org.apache.juneau.http.StreamResource;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.mock2.*;
@@ -30,37 +29,37 @@ public class StreamResourceTest {
 
                @RestMethod
                public StreamResource a01() throws Exception {
-                       return StreamResource.create().contents("foo").build();
+                       return StreamResource.create().content("foo");
                }
 
                @RestMethod
                public StreamResource a02() throws Exception {
-                       return StreamResource.create().header("Foo", 
"Bar").build();
+                       return StreamResource.create().header("Foo", "Bar");
                }
 
                @RestMethod
                public StreamResource a03() throws Exception {
-                       return 
StreamResource.create().mediaType(MediaType.JSON).build();
+                       return 
StreamResource.create().contentType("application/json");
                }
 
                @RestMethod
                public StreamResource a04() throws Exception {
-                       return 
StreamResource.create().contents("foo".getBytes()).build();
+                       return 
StreamResource.create().content("foo".getBytes());
                }
 
                @RestMethod
                public StreamResource a05() throws Exception {
-                       return StreamResource.create().contents(new 
ByteArrayInputStream("foo".getBytes())).build();
+                       return StreamResource.create().content(new 
ByteArrayInputStream("foo".getBytes()));
                }
 
                @RestMethod
                public StreamResource a06() throws Exception {
-                       return StreamResource.create().contents(new 
StringReader("foo")).build();
+                       return StreamResource.create().content(new 
StringReader("foo"));
                }
 
                @RestMethod
                public StreamResource a07() throws Exception {
-                       return StreamResource.create().contents(new 
StringBuilder("foo")).build();
+                       return StreamResource.create().content(new 
StringBuilder("foo"));
                }
        }
 
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 1f09414..db76172 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
@@ -56,6 +56,7 @@ import org.apache.juneau.reflect.*;
 import org.apache.juneau.remote.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.http.exception.*;
+import org.apache.juneau.http.header.*;
 import org.apache.juneau.rest.helper.*;
 import org.apache.juneau.rest.util.*;
 import org.apache.juneau.rest.widget.*;
@@ -1461,12 +1462,15 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                String s = context.getClasspathResourceAsString(name, 
getLocale());
                if (s == null)
                        return null;
-               ResolvingResourceReaderBuilder b = 
ResolvingReaderResource.create().mediaType(mediaType).contents(s);
+               ResolvingReaderResource b = ResolvingReaderResource
+                       .create()
+                       .content(s)
+                       .contentType(mediaType == null ? null : 
ContentType.of(mediaType.toString()));
                if (resolveVars)
                        b.varResolver(getVarResolverSession());
                if (cached)
-                       b.cached();
-               return b.build();
+                       b.cache();
+               return b;
        }
 
        /**
@@ -1542,10 +1546,13 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
                InputStream is = context.getClasspathResource(name, 
getLocale());
                if (is == null)
                        return null;
-               StreamResourceBuilder b = 
StreamResource.create().mediaType(mediaType).contents(is);
+               StreamResource b = StreamResource
+                       .create()
+                       .content(is)
+                       .contentType(mediaType == null ? null : 
ContentType.of(mediaType.toString()));
                if (cached)
-                       b.cached();
-               return b.build();
+                       b.cache();
+               return b;
        }
 
        /**

Reply via email to