You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2022/09/10 16:18:03 UTC

[juneau] branch master updated: Simplified HttpEntity/HttpResource classes.

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 55a7da9ae Simplified HttpEntity/HttpResource classes.
55a7da9ae is described below

commit 55a7da9ae0188da83c35e2a2145b51f4aeb9cdc0
Author: JamesBognar <ja...@salesforce.com>
AuthorDate: Sat Sep 10 12:17:10 2022 -0400

    Simplified HttpEntity/HttpResource classes.
---
 .../org/apache/juneau/rest/client/RestClient.java  |   2 +-
 .../org/apache/juneau/rest/client/RestRequest.java |   8 +-
 .../java/org/apache/juneau/http/HttpEntities.java  |  72 ++--
 .../java/org/apache/juneau/http/HttpResources.java |  56 ++--
 .../apache/juneau/http/entity/BasicHttpEntity.java | 333 +++++++++++++++++--
 .../apache/juneau/http/entity/ByteArrayEntity.java |  62 ++--
 .../org/apache/juneau/http/entity/FileEntity.java  |  85 +++--
 .../juneau/http/entity/HttpEntityBuilder.java      | 226 -------------
 .../apache/juneau/http/entity/ReaderEntity.java    |  95 ++++--
 .../juneau/http/entity/SerializedEntity.java       |  98 ++++--
 .../http/entity/SerializedEntityBuilder.java       | 172 ----------
 .../apache/juneau/http/entity/StreamEntity.java    |  91 ++++--
 .../apache/juneau/http/entity/StringEntity.java    |  94 ++++--
 .../apache/juneau/http/resource/BasicResource.java | 339 ++++++++++++++++++-
 .../juneau/http/resource/ByteArrayResource.java    |  34 +-
 .../apache/juneau/http/resource/FileResource.java  |  34 +-
 .../juneau/http/resource/HttpResourceBuilder.java  | 363 ---------------------
 .../juneau/http/resource/ReaderResource.java       |  34 +-
 .../juneau/http/resource/StreamResource.java       |  34 +-
 .../juneau/http/resource/StringResource.java       |  34 +-
 .../juneau/http/response/BasicHttpException.java   |   4 +-
 .../juneau/http/response/BasicHttpResponse.java    |   4 +-
 .../juneau/rest/staticfile/BasicStaticFiles.java   |   5 +-
 .../apache/juneau/http/BasicHttpResource_Test.java |  68 ++--
 .../juneau/http/SerializedHttpEntity_Test.java     |  28 +-
 .../http/remote/Remote_CommonInterfaces_Test.java  |   2 +-
 .../apache/juneau/rest/RestOp_Returns_Test.java    |  13 +-
 .../rest/client/RestClient_BasicCalls_Test.java    |  28 +-
 .../juneau/rest/client/RestClient_Body_Test.java   |  43 +--
 29 files changed, 1247 insertions(+), 1214 deletions(-)

diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index 37fbd1ffe..c8cb4f650 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -6828,7 +6828,7 @@ public class RestClient extends BeanContextable implements HttpClient, Closeable
 			}
 			if (body instanceof Reader || body instanceof InputStream)
 				return req.header(ContentType.APPLICATION_FORM_URLENCODED).content(body);
-			return req.content(serializedEntity(body, urlEncodingSerializer, null).build());
+			return req.content(serializedEntity(body, urlEncodingSerializer, 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/client/RestRequest.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java
index 8e3caae7f..960ca29dc 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequest.java
@@ -1925,18 +1925,18 @@ public class RestRequest extends BeanSession implements HttpUriRequest, Configur
 					}
 				}
 				else if (input2 instanceof Reader)
-					entity = readerEntity((Reader)input2, getRequestContentType(TEXT_PLAIN)).build();
+					entity = readerEntity((Reader)input2, getRequestContentType(TEXT_PLAIN));
 				else if (input2 instanceof InputStream)
-					entity = streamEntity((InputStream)input2, -1, getRequestContentType(ContentType.APPLICATION_OCTET_STREAM)).build();
+					entity = streamEntity((InputStream)input2, -1, getRequestContentType(ContentType.APPLICATION_OCTET_STREAM));
 				else if (serializer != null)
-					entity = serializedEntity(input2, serializer, contentSchema).contentType(contentType).build();
+					entity = serializedEntity(input2, serializer, contentSchema).setContentType(contentType);
 				else {
 					if (client.hasSerializers()) {
 						if (contentType == null)
 							throw new RestCallException(null, null, "Content-Type not specified on request.  Cannot match correct serializer.  Use contentType(String) or mediaType(String) to specify transport language.");
 						throw new RestCallException(null, null, "No matching serializer for media type ''{0}''", contentType);
 					}
-					entity = stringEntity(input2 == null ? "" : BeanContext.DEFAULT.getClassMetaForObject(input2).toString(input2), getRequestContentType(TEXT_PLAIN)).build();
+					entity = stringEntity(input2 == null ? "" : BeanContext.DEFAULT.getClassMetaForObject(input2).toString(input2), getRequestContentType(TEXT_PLAIN));
 				}
 
 				request2.setEntity(entity);
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/HttpEntities.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/HttpEntities.java
index c52895b5b..db5950e2d 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/HttpEntities.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/HttpEntities.java
@@ -39,8 +39,8 @@ public class HttpEntities {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link ByteArrayEntity} builder.
 	 */
-	public static final HttpEntityBuilder<ByteArrayEntity> byteArrayEntity(byte[] content) {
-		return ByteArrayEntity.create().content(content);
+	public static final ByteArrayEntity byteArrayEntity(byte[] content) {
+		return (ByteArrayEntity) new ByteArrayEntity().setContent(content);
 	}
 
 	/**
@@ -50,8 +50,8 @@ public class HttpEntities {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link ByteArrayEntity} builder.
 	 */
-	public static final HttpEntityBuilder<ByteArrayEntity> byteArrayEntity(byte[] content, ContentType contentType) {
-		return ByteArrayEntity.create().content(content).contentType(contentType);
+	public static final ByteArrayEntity byteArrayEntity(byte[] content, ContentType contentType) {
+		return (ByteArrayEntity) new ByteArrayEntity().setContent(content).setContentType(contentType);
 	}
 
 	/**
@@ -63,8 +63,8 @@ public class HttpEntities {
 	 * @param content The entity content supplier.  Can be <jk>null</jk>.
 	 * @return A new {@link ByteArrayEntity} builder.
 	 */
-	public static final HttpEntityBuilder<ByteArrayEntity> byteArrayEntity(Supplier<byte[]> content) {
-		return ByteArrayEntity.create().content(content);
+	public static final ByteArrayEntity byteArrayEntity(Supplier<byte[]> content) {
+		return (ByteArrayEntity) new ByteArrayEntity().setContent(content);
 	}
 
 	/**
@@ -74,8 +74,8 @@ public class HttpEntities {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link ByteArrayEntity} builder.
 	 */
-	public static final HttpEntityBuilder<ByteArrayEntity> byteArrayEntity(Supplier<byte[]> content, ContentType contentType) {
-		return ByteArrayEntity.create().content(content).contentType(contentType);
+	public static final ByteArrayEntity byteArrayEntity(Supplier<byte[]> content, ContentType contentType) {
+		return (ByteArrayEntity) new ByteArrayEntity().setContent(content).setContentType(contentType);
 	}
 
 	/**
@@ -87,8 +87,8 @@ public class HttpEntities {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link FileEntity} builder.
 	 */
-	public static final HttpEntityBuilder<FileEntity> fileEntity(File content) {
-		return FileEntity.create().content(content);
+	public static final FileEntity fileEntity(File content) {
+		return (FileEntity) new FileEntity().setContent(content);
 	}
 
 	/**
@@ -98,8 +98,8 @@ public class HttpEntities {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link FileEntity} builder.
 	 */
-	public static final HttpEntityBuilder<FileEntity> fileEntity(File content, ContentType contentType) {
-		return FileEntity.create().content(content).contentType(contentType);
+	public static final FileEntity fileEntity(File content, ContentType contentType) {
+		return (FileEntity) new FileEntity().setContent(content).setContentType(contentType);
 	}
 
 	/**
@@ -108,8 +108,8 @@ public class HttpEntities {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link ReaderEntity} builder.
 	 */
-	public static final HttpEntityBuilder<ReaderEntity> readerEntity(Reader content) {
-		return ReaderEntity.create().content(content);
+	public static final ReaderEntity readerEntity(Reader content) {
+		return (ReaderEntity) new ReaderEntity().setContent(content);
 	}
 
 	/**
@@ -119,8 +119,8 @@ public class HttpEntities {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link ReaderEntity} builder.
 	 */
-	public static final HttpEntityBuilder<ReaderEntity> readerEntity(Reader content, ContentType contentType) {
-		return ReaderEntity.create().content(content).contentType(contentType);
+	public static final ReaderEntity readerEntity(Reader content, ContentType contentType) {
+		return (ReaderEntity) new ReaderEntity().setContent(content).setContentType(contentType);
 	}
 
 	/**
@@ -134,8 +134,8 @@ public class HttpEntities {
 	 * 	<br>If <jk>null</jk>, POJO will be converted to a string using {@link Object#toString()}.
 	 * @return A new {@link SerializedEntity} object.
 	 */
-	public static final SerializedEntityBuilder<SerializedEntity> serializedEntity(Object content, Serializer serializer) {
-		return SerializedEntity.create().content(content).serializer(serializer);
+	public static final SerializedEntity serializedEntity(Object content, Serializer serializer) {
+		return ((SerializedEntity) new SerializedEntity().setContent(content)).setSerializer(serializer);
 	}
 
 	/**
@@ -149,8 +149,8 @@ public class HttpEntities {
 	 * 	<br>If <jk>null</jk>, POJO will be converted to a string using {@link Object#toString()}.
 	 * @return A new {@link SerializedEntity} object.
 	 */
-	public static final SerializedEntityBuilder<SerializedEntity> serializedEntity(Supplier<?> content, Serializer serializer) {
-		return SerializedEntity.create().content(content).serializer(serializer);
+	public static final SerializedEntity serializedEntity(Supplier<?> content, Serializer serializer) {
+		return ((SerializedEntity) new SerializedEntity().setContent(content)).setSerializer(serializer);
 	}
 
 	/**
@@ -166,8 +166,8 @@ public class HttpEntities {
 	 * 	Optional HTTP-part schema for providing instructionst to the serializer on the format of the entity.
 	 * @return A new {@link SerializedEntity} object.
 	 */
-	public static final SerializedEntityBuilder<SerializedEntity> serializedEntity(Object content, Serializer serializer, HttpPartSchema 	schema) {
-		return SerializedEntity.create().content(content).serializer(serializer).schema(schema);
+	public static final SerializedEntity serializedEntity(Object content, Serializer serializer, HttpPartSchema schema) {
+		return ((SerializedEntity) new SerializedEntity().setContent(content)).setSerializer(serializer).setSchema(schema);
 	}
 
 	/**
@@ -183,8 +183,8 @@ public class HttpEntities {
 	 * 	Optional HTTP-part schema for providing instructionst to the serializer on the format of the entity.
 	 * @return A new {@link SerializedEntity} object.
 	 */
-	public static final SerializedEntityBuilder<SerializedEntity> serializedEntity(Supplier<?> content, Serializer serializer, HttpPartSchema schema) {
-		return SerializedEntity.create().content(content).serializer(serializer).schema(schema);
+	public static final SerializedEntity serializedEntity(Supplier<?> content, Serializer serializer, HttpPartSchema schema) {
+		return ((SerializedEntity) new SerializedEntity().setContent(content)).setSerializer(serializer).setSchema(schema);
 	}
 
 	/**
@@ -196,8 +196,8 @@ public class HttpEntities {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link StreamEntity} builder.
 	 */
-	public static final HttpEntityBuilder<StreamEntity> streamEntity(InputStream content) {
-		return StreamEntity.create().content(content);
+	public static final StreamEntity streamEntity(InputStream content) {
+		return (StreamEntity) new StreamEntity().setContent(content);
 	}
 
 	/**
@@ -208,8 +208,8 @@ public class HttpEntities {
 	 * @param length The content length, or <c>-1</c> if not known.
 	 * @return A new {@link StreamEntity} builder.
 	 */
-	public static final HttpEntityBuilder<StreamEntity> streamEntity(InputStream content, long length, ContentType contentType) {
-		return StreamEntity.create().content(content).contentLength(length).contentType(contentType);
+	public static final StreamEntity streamEntity(InputStream content, long length, ContentType contentType) {
+		return (StreamEntity) new StreamEntity().setContent(content).setContentLength(length).setContentType(contentType);
 	}
 
 	/**
@@ -218,8 +218,8 @@ public class HttpEntities {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link StringEntity} builder.
 	 */
-	public static final HttpEntityBuilder<StringEntity> stringEntity(String content) {
-		return StringEntity.create().content(content);
+	public static final StringEntity stringEntity(String content) {
+		return (StringEntity) new StringEntity().setContent(content);
 	}
 
 	/**
@@ -229,8 +229,8 @@ public class HttpEntities {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link StringEntity} builder.
 	 */
-	public static final HttpEntityBuilder<StringEntity> stringEntity(String content, ContentType contentType) {
-		return StringEntity.create().content(content).contentType(contentType);
+	public static final StringEntity stringEntity(String content, ContentType contentType) {
+		return (StringEntity) new StringEntity().setContent(content).setContentType(contentType);
 	}
 
 	/**
@@ -239,8 +239,8 @@ public class HttpEntities {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link StringEntity} builder.
 	 */
-	public static final HttpEntityBuilder<StringEntity> stringEntity(Supplier<String> content) {
-		return StringEntity.create().content(content);
+	public static final StringEntity stringEntity(Supplier<String> content) {
+		return (StringEntity) new StringEntity().setContent(content);
 	}
 
 	/**
@@ -250,7 +250,7 @@ public class HttpEntities {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link StringEntity} builder.
 	 */
-	public static final HttpEntityBuilder<StringEntity> stringEntity(Supplier<String> content, ContentType contentType) {
-		return StringEntity.create().content(content).contentType(contentType);
+	public static final StringEntity stringEntity(Supplier<String> content, ContentType contentType) {
+		return (StringEntity) new StringEntity().setContent(content).setContentType(contentType);
 	}
 }
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/HttpResources.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/HttpResources.java
index 59789d335..7a406f53d 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/HttpResources.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/HttpResources.java
@@ -41,8 +41,8 @@ public class HttpResources {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link ByteArrayResource} builder.
 	 */
-	public static final HttpResourceBuilder<ByteArrayResource> byteArrayResource(byte[] content) {
-		return ByteArrayResource.create().content(content);
+	public static final ByteArrayResource byteArrayResource(byte[] content) {
+		return (ByteArrayResource) new ByteArrayResource().setContent(content);
 	}
 
 	/**
@@ -52,8 +52,8 @@ public class HttpResources {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link ByteArrayResource} builder.
 	 */
-	public static final HttpResourceBuilder<ByteArrayResource> byteArrayResource(byte[] content, ContentType contentType) {
-		return ByteArrayResource.create().content(content).contentType(contentType);
+	public static final ByteArrayResource byteArrayResource(byte[] content, ContentType contentType) {
+		return (ByteArrayResource) new ByteArrayResource().setContent(content).setContentType(contentType);
 	}
 
 	/**
@@ -65,8 +65,8 @@ public class HttpResources {
 	 * @param content The entity content supplier.  Can be <jk>null</jk>.
 	 * @return A new {@link ByteArrayResource} builder.
 	 */
-	public static final HttpResourceBuilder<ByteArrayResource> byteArrayResource(Supplier<byte[]> content) {
-		return ByteArrayResource.create().content(content);
+	public static final ByteArrayResource byteArrayResource(Supplier<byte[]> content) {
+		return (ByteArrayResource) new ByteArrayResource().setContent(content);
 	}
 
 	/**
@@ -76,8 +76,8 @@ public class HttpResources {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link ByteArrayResource} builder.
 	 */
-	public static final HttpResourceBuilder<ByteArrayResource> byteArrayResource(Supplier<byte[]> content, ContentType contentType) {
-		return ByteArrayResource.create().content(content).contentType(contentType);
+	public static final ByteArrayResource byteArrayResource(Supplier<byte[]> content, ContentType contentType) {
+		return (ByteArrayResource) new ByteArrayResource().setContent(content).setContentType(contentType);
 	}
 
 	/**
@@ -89,8 +89,8 @@ public class HttpResources {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link FileResource} builder.
 	 */
-	public static final HttpResourceBuilder<FileResource> fileResource(File content) {
-		return FileResource.create().content(content);
+	public static final FileResource fileResource(File content) {
+		return (FileResource) new FileResource().setContent(content);
 	}
 
 	/**
@@ -100,8 +100,8 @@ public class HttpResources {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link FileResource} builder.
 	 */
-	public static final HttpResourceBuilder<FileResource> fileResource(File content, ContentType contentType) {
-		return FileResource.create().content(content).contentType(contentType);
+	public static final FileResource fileResource(File content, ContentType contentType) {
+		return (FileResource) new FileResource().setContent(content).setContentType(contentType);
 	}
 
 	/**
@@ -110,8 +110,8 @@ public class HttpResources {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link ReaderResource} builder.
 	 */
-	public static final HttpResourceBuilder<ReaderResource> readerResource(Reader content) {
-		return ReaderResource.create().content(content);
+	public static final ReaderResource readerResource(Reader content) {
+		return (ReaderResource) new ReaderResource().setContent(content);
 	}
 
 	/**
@@ -121,8 +121,8 @@ public class HttpResources {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link ReaderResource} builder.
 	 */
-	public static final HttpResourceBuilder<ReaderResource> readerResource(Reader content, ContentType contentType) {
-		return ReaderResource.create().content(content).contentType(contentType);
+	public static final ReaderResource readerResource(Reader content, ContentType contentType) {
+		return (ReaderResource) new ReaderResource().setContent(content).setContentType(contentType);
 	}
 
 	/**
@@ -134,8 +134,8 @@ public class HttpResources {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link StreamResource} builder.
 	 */
-	public static final HttpResourceBuilder<StreamResource> streamResource(InputStream content) {
-		return StreamResource.create().content(content);
+	public static final StreamResource streamResource(InputStream content) {
+		return (StreamResource) new StreamResource().setContent(content);
 	}
 
 	/**
@@ -146,8 +146,8 @@ public class HttpResources {
 	 * @param length The content length, or <c>-1</c> if not known.
 	 * @return A new {@link StreamResource} builder.
 	 */
-	public static final HttpResourceBuilder<StreamResource> streamResource(InputStream content, long length, ContentType contentType) {
-		return StreamResource.create().content(content).contentLength(length).contentType(contentType);
+	public static final StreamResource streamResource(InputStream content, long length, ContentType contentType) {
+		return (StreamResource) new StreamResource().setContent(content).setContentLength(length).setContentType(contentType);
 	}
 
 	/**
@@ -156,8 +156,8 @@ public class HttpResources {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link StringResource} builder.
 	 */
-	public static final HttpResourceBuilder<StringResource> stringResource(String content) {
-		return StringResource.create().content(content);
+	public static final StringResource stringResource(String content) {
+		return (StringResource) new StringResource().setContent(content);
 	}
 
 	/**
@@ -167,8 +167,8 @@ public class HttpResources {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link StringResource} builder.
 	 */
-	public static final HttpResourceBuilder<StringResource> stringResource(String content, ContentType contentType) {
-		return StringResource.create().content(content).contentType(contentType);
+	public static final StringResource stringResource(String content, ContentType contentType) {
+		return (StringResource) new StringResource().setContent(content).setContentType(contentType);
 	}
 
 	/**
@@ -177,8 +177,8 @@ public class HttpResources {
 	 * @param content The entity content.  Can be <jk>null</jk>.
 	 * @return A new {@link StringResource} builder.
 	 */
-	public static final HttpResourceBuilder<StringResource> stringResource(Supplier<String> content) {
-		return StringResource.create().content(content);
+	public static final StringResource stringResource(Supplier<String> content) {
+		return (StringResource) new StringResource().setContent(content);
 	}
 
 	/**
@@ -188,7 +188,7 @@ public class HttpResources {
 	 * @param contentType The entity content type, or <jk>null</jk> if not specified.
 	 * @return A new {@link StringResource} builder.
 	 */
-	public static final HttpResourceBuilder<StringResource> stringResource(Supplier<String> content, ContentType contentType) {
-		return StringResource.create().content(content).contentType(contentType);
+	public static final StringResource stringResource(Supplier<String> content, ContentType contentType) {
+		return (StringResource) new StringResource().setContent(content).setContentType(contentType);
 	}
 }
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/BasicHttpEntity.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/BasicHttpEntity.java
index 7b03af750..952fc98fa 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/BasicHttpEntity.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/BasicHttpEntity.java
@@ -45,46 +45,64 @@ import org.apache.juneau.internal.*;
  * </ul>
  */
 @BeanIgnore
+@FluentSetters
 public class BasicHttpEntity implements HttpEntity {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * An empty HttpEntity.
 	 */
-	public static final BasicHttpEntity EMPTY = create(BasicHttpEntity.class).build();
+	public static final BasicHttpEntity EMPTY = new BasicHttpEntity().setUnmodifiable();
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
 
-	final boolean cached, chunked;
-	final Object content;
-	final Supplier<?> contentSupplier;
-	final ContentType contentType;
-	final ContentEncoding contentEncoding;
-	final Charset charset;
-	final long contentLength;
+	private boolean cached, chunked, unmodifiable;
+	private Object content;
+	private Supplier<?> contentSupplier;
+	private ContentType contentType;
+	private ContentEncoding contentEncoding;
+	private Charset charset;
+	private long contentLength = -1;
+	private int maxLength = -1;
 
 	/**
-	 * Creates a builder for this class.
-	 *
-	 * @param <T> The subclass that the builder is going to create.
-	 * @param implClass The subclass that the builder is going to create.
-	 * @return A new builder bean.
+	 * Constructor.
 	 */
-	public static <T extends BasicHttpEntity> HttpEntityBuilder<T> create(Class<T> implClass) {
-		return new HttpEntityBuilder<>(implClass);
+	public BasicHttpEntity() {
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The builder containing the arguments for this bean.
+	 * @param contentType The entity content type.
+	 * @param content The entity content.
+	 */
+	public BasicHttpEntity(ContentType contentType, Object content) {
+		this.contentType = contentType;
+		this.content = content;
+	}
+
+	/**
+	 * Copy constructor.
+	 *
+	 * @param copyFrom The bean being copied.
 	 */
-	public BasicHttpEntity(HttpEntityBuilder<?> builder) {
-		this.cached = builder.cached;
-		this.chunked = builder.chunked;
-		this.content = builder.content;
-		this.contentSupplier = builder.contentSupplier;
-		this.contentType = builder.contentType;
-		this.contentEncoding = builder.contentEncoding;
-		this.charset = builder.charset;
-		this.contentLength = builder.contentLength;
+	public BasicHttpEntity(BasicHttpEntity copyFrom) {
+		this.cached = copyFrom.cached;
+		this.chunked = copyFrom.chunked;
+		this.content = copyFrom.content;
+		this.contentSupplier = copyFrom.contentSupplier;
+		this.contentType = copyFrom.contentType;
+		this.contentEncoding = copyFrom.contentEncoding;
+		this.contentLength = copyFrom.contentLength;
+		this.charset = copyFrom.charset;
+		this.maxLength = copyFrom.maxLength;
+		this.unmodifiable = false;
 	}
 
 	/**
@@ -95,10 +113,242 @@ public class BasicHttpEntity implements HttpEntity {
 	 *
 	 * @return A new builder bean.
 	 */
-	public HttpEntityBuilder<? extends BasicHttpEntity> copy() {
-		return new HttpEntityBuilder<>(this);
+	public BasicHttpEntity copy() {
+		return new BasicHttpEntity(this);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Properties
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Specifies whether this bean should be unmodifiable.
+	 * <p>
+	 * When enabled, attempting to set any properties on this bean will cause an {@link UnsupportedOperationException}.
+	 *
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setUnmodifiable() {
+		unmodifiable = true;
+		return this;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this bean is unmodifiable.
+	 *
+	 * @return <jk>true</jk> if this bean is unmodifiable.
+	 */
+	public boolean isUnmodifiable() {
+		return unmodifiable;
+	}
+
+	/**
+	 * Throws an {@link UnsupportedOperationException} if the unmodifiable flag is set on this bean.
+	 */
+	protected final void assertModifiable() {
+		if (unmodifiable)
+			throw new UnsupportedOperationException("Bean is read-only");
+	}
+
+	/**
+	 * Sets the content on this entity bean.
+	 *
+	 * @param value The entity content, can be <jk>null</jk>.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setContent(Object value) {
+		assertModifiable();
+		this.content = value;
+		return this;
+	}
+
+	/**
+	 * Sets the content on this entity bean from a supplier.
+	 *
+	 * <p>
+	 * Repeatable entities such as {@link StringEntity} use this to allow the entity content to be resolved at
+	 * serialization time.
+	 *
+	 * @param value The entity content, can be <jk>null</jk>.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setContent(Supplier<?> value) {
+		assertModifiable();
+		this.contentSupplier = value == null ? ()->null : value;
+		return this;
+	}
+
+	/**
+	 * Sets the content type on this entity bean.
+	 *
+	 * @param value The new <c>Content-Type</c> header, or <jk>null</jk> to unset.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setContentType(String value) {
+		return setContentType(ContentType.of(value));
+	}
+
+	/**
+	 * Sets the content type on this entity bean.
+	 *
+	 * @param value The new <c>Content-Type</c> header, or <jk>null</jk> to unset.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setContentType(ContentType value) {
+		assertModifiable();
+		contentType = value;
+		return this;
+	}
+
+	/**
+	 * Sets the content length on this entity bean.
+	 *
+	 * @param value The new <c>Content-Length</c> header value, or <c>-1</c> to unset.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setContentLength(long value) {
+		assertModifiable();
+		contentLength = value;
+		return this;
+	}
+
+	/**
+	 * Sets the content encoding header on this entity bean.
+	 *
+	 * @param value The new <c>Content-Encoding</c> header, or <jk>null</jk> to unset.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setContentEncoding(String value) {
+		return setContentEncoding(ContentEncoding.of(value));
+	}
+
+	/**
+	 * Sets the content encoding header on this entity bean.
+	 *
+	 * @param value The new <c>Content-Encoding</c> header, or <jk>null</jk> to unset.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setContentEncoding(ContentEncoding value) {
+		assertModifiable();
+		contentEncoding = value;
+		return this;
+	}
+
+	/**
+	 * Sets the 'chunked' flag value to <jk>true</jk>.
+	 *
+	 * <ul class='notes'>
+	 * 	<li class='note'>If the {@link HttpEntity#getContentLength()} method returns a negative value, the HttpClient code will always
+	 * 		use chunked encoding.
+	 * </ul>
+	 *
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setChunked() {
+		return setChunked(true);
 	}
 
+	/**
+	 * Sets the 'chunked' flag value.
+	 *
+	 * <ul class='notes'>
+	 * 	<li class='note'>If the {@link HttpEntity#getContentLength()} method returns a negative value, the HttpClient code will always
+	 * 		use chunked encoding.
+	 * </ul>
+	 *
+	 * @param value The new value for this flag.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setChunked(boolean value) {
+		assertModifiable();
+		chunked = value;
+		return this;
+	}
+
+	/**
+	 * 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.
+	 * @throws IOException If entity could not be read into memory.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setCached() throws IOException {
+		assertModifiable();
+		cached = true;
+		return this;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this entity is cached in-memory.
+	 *
+	 * @return <jk>true</jk> if this entity is cached in-memory.
+	 */
+	public boolean isCached() {
+		return cached;
+	}
+
+	/**
+	 * Specifies the charset to use when converting to and from stream-based resources.
+	 *
+	 * @param value The new value.  If <jk>null</jk>, <c>UTF-8</c> is assumed.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setCharset(Charset value) {
+		assertModifiable();
+		this.charset = value;
+		return this;
+	}
+
+	/**
+	 * Returns the charset to use when converting to and from stream-based resources.
+	 *
+	 * @return The charset to use when converting to and from stream-based resources.
+	 */
+	public Charset getCharset() {
+		return charset == null ? UTF8 : charset;
+	}
+
+	/**
+	 * Specifies the maximum number of bytes to read or write to and from stream-based resources.
+	 *
+	 * <p>
+	 * Implementation is not universal.
+	 *
+	 * @param value The new value.  The default is <c>-1</c> which means read everything.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicHttpEntity setMaxLength(int value) {
+		assertModifiable();
+		this.maxLength = value;
+		return this;
+	}
+
+	/**
+	 * Returns the maximum number of bytes to read or write to and from stream-based resources.
+	 *
+	 * @return The maximum number of bytes to read or write to and from stream-based resources.
+	 */
+	public int getMaxLength() {
+		return maxLength;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other methods
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Converts the contents of this entity as a string.
 	 *
@@ -125,6 +375,19 @@ public class BasicHttpEntity implements HttpEntity {
 		return readBytes(getContent());
 	}
 
+	/**
+	 * Same as {@link #asBytes()} but wraps {@link IOException IOExceptions} inside a {@link RuntimeException}.
+	 *
+	 * @return The contents of this entity as a byte array.
+	 */
+	protected byte[] asSafeBytes() {
+		try {
+			return asBytes();
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
 	/**
 	 * Returns an assertion on the contents of this entity.
 	 *
@@ -184,40 +447,40 @@ public class BasicHttpEntity implements HttpEntity {
 		return contentLength;
 	}
 
-	@Override
+	@Override /* HttpEntity */
 	public boolean isRepeatable() {
 		return false;
 	}
 
-	@Override
+	@Override /* HttpEntity */
 	public boolean isChunked() {
 		return chunked;
 	}
 
-	@Override
+	@Override /* HttpEntity */
 	public Header getContentType() {
 		return contentType;
 	}
 
-	@Override
+	@Override /* HttpEntity */
 	public Header getContentEncoding() {
 		return contentEncoding;
 	}
 
-	@Override
+	@Override /* HttpEntity */
 	public boolean isStreaming() {
 		return false;
 	}
 
-	@Override
+	@Override /* HttpEntity */
 	public void consumeContent() throws IOException {}
 
-	@Override
+	@Override /* HttpEntity */
 	public InputStream getContent() throws IOException, UnsupportedOperationException {
 		return IOUtils.EMPTY_INPUT_STREAM;
 	}
 
-	@Override
+	@Override /* HttpEntity */
 	public void writeTo(OutputStream outStream) throws IOException {}
 
 	// <FluentSetters>
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/ByteArrayEntity.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/ByteArrayEntity.java
index bc5cf80bf..cee9c4598 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/ByteArrayEntity.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/ByteArrayEntity.java
@@ -13,10 +13,12 @@
 package org.apache.juneau.http.entity;
 
 import static org.apache.juneau.internal.ArgUtils.*;
-import static org.apache.juneau.internal.IOUtils.*;
 
 import java.io.*;
 
+import org.apache.juneau.http.header.*;
+import org.apache.juneau.internal.*;
+
 /**
  * A repeatable entity that obtains its content from a byte array.
  *
@@ -25,50 +27,66 @@ import java.io.*;
  * 	<li class='extlink'>{@source}
  * </ul>
  */
+@FluentSetters
 public class ByteArrayEntity extends BasicHttpEntity {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final byte[] EMPTY = new byte[0];
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
-	 * Creates a new {@link ByteArrayEntity} builder.
-	 *
-	 * @return A new {@link ByteArrayEntity} builder.
+	 * Constructor.
 	 */
-	public static HttpEntityBuilder<ByteArrayEntity> create() {
-		return new HttpEntityBuilder<>(ByteArrayEntity.class);
+	public ByteArrayEntity() {
+		super();
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The entity builder.
+	 * @param contentType The entity content type.
+	 * @param contents The entity contents.
 	 */
-	public ByteArrayEntity(HttpEntityBuilder<?> builder) {
-		super(builder);
+	public ByteArrayEntity(ContentType contentType, byte[] contents) {
+		super(contentType, contents);
 	}
 
 	/**
-	 * Creates a new {@link ByteArrayEntity} builder initialized with the contents of this entity.
+	 * Copy constructor.
 	 *
-	 * @return A new {@link ByteArrayEntity} builder initialized with the contents of this entity.
+	 * @param copyFrom The bean being copied.
 	 */
-	@Override /* BasicHttpEntity */
-	public HttpEntityBuilder<ByteArrayEntity> copy() {
-		return new HttpEntityBuilder<>(this);
+	protected ByteArrayEntity(ByteArrayEntity copyFrom) {
+		super(copyFrom);
 	}
 
-	private byte[] bytes() {
+	@Override
+	public ByteArrayEntity copy() {
+		return new ByteArrayEntity(this);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other methods
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private byte[] content() {
 		return contentOrElse(EMPTY);
 	}
 
 	@Override /* AbstractHttpEntity */
 	public String asString() throws IOException {
-		return new String(bytes(), UTF8);
+		return new String(content(), getCharset());
 	}
 
 	@Override /* AbstractHttpEntity */
 	public byte[] asBytes() throws IOException {
-		return bytes();
+		return content();
 	}
 
 	@Override /* HttpEntity */
@@ -78,17 +96,21 @@ public class ByteArrayEntity extends BasicHttpEntity {
 
 	@Override /* HttpEntity */
 	public long getContentLength() {
-		return isSupplied() ? super.getContentLength() : bytes().length;
+		return isSupplied() ? super.getContentLength() : content().length;
 	}
 
 	@Override /* HttpEntity */
 	public InputStream getContent() throws IOException {
-		return new ByteArrayInputStream(bytes());
+		return new ByteArrayInputStream(content());
 	}
 
 	@Override /* HttpEntity */
 	public void writeTo(OutputStream out) throws IOException {
 		assertArgNotNull("out", out);
-		out.write(bytes());
+		out.write(content());
 	}
+
+	// <FluentSetters>
+
+	// </FluentSetters>
 }
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/FileEntity.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/FileEntity.java
index f5bd80753..94545aaa7 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/FileEntity.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/FileEntity.java
@@ -17,6 +17,7 @@ import static org.apache.juneau.internal.IOUtils.*;
 
 import java.io.*;
 
+import org.apache.juneau.http.header.*;
 import org.apache.juneau.internal.*;
 
 /**
@@ -27,50 +28,78 @@ import org.apache.juneau.internal.*;
  * 	<li class='extlink'>{@source}
  * </ul>
  */
+@FluentSetters
 public class FileEntity extends BasicHttpEntity {
 
-	private final File content;
-	private final byte[] cache;
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private byte[] byteCache;
+	private String stringCache;
 
 	/**
-	 * Creates a new {@link FileEntity} builder.
-	 *
-	 * @return A new {@link FileEntity} builder.
+	 * Constructor.
 	 */
-	public static HttpEntityBuilder<FileEntity> create() {
-		return new HttpEntityBuilder<>(FileEntity.class);
+	public FileEntity() {
+		super();
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The entity builder.
-	 * @throws IOException If file could not be read.
+	 * @param contentType The entity content type.
+	 * @param content The entity contents.
 	 */
-	public FileEntity(HttpEntityBuilder<?> builder) throws IOException {
-		super(builder);
-		content = contentOrElse(null);
-		cache = builder.cached ? readBytes(content) : null;
+	public FileEntity(ContentType contentType, File content) {
+		super(contentType, content);
 	}
 
 	/**
-	 * Creates a new {@link FileEntity} builder initialized with the contents of this entity.
+	 * Copy constructor.
 	 *
-	 * @return A new {@link FileEntity} builder initialized with the contents of this entity.
+	 * @param copyFrom The bean being copied.
 	 */
-	@Override /* BasicHttpEntity */
-	public HttpEntityBuilder<FileEntity> copy() {
-		return new HttpEntityBuilder<>(this);
+	protected FileEntity(FileEntity copyFrom) {
+		super(copyFrom);
+	}
+
+	@Override
+	public FileEntity copy() {
+		return new FileEntity(this);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other methods
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private File content() {
+		File f = contentOrElse((File)null);
+		if (f == null)
+			throw new RuntimeException("File is null.");
+		if (! f.exists())
+			throw new RuntimeException("File "+f.getAbsolutePath()+" does not exist.");
+		if (! f.canRead())
+			throw new RuntimeException("File "+f.getAbsolutePath()+" is not readable.");
+		return f;
 	}
 
 	@Override /* AbstractHttpEntity */
 	public String asString() throws IOException {
-		return read(content);
+		if (isCached() && stringCache == null)
+			stringCache = read(new InputStreamReader(new FileInputStream(content()), getCharset()), getMaxLength());
+		if (stringCache != null)
+			return stringCache;
+		return read(new InputStreamReader(new FileInputStream(content()), getCharset()), getMaxLength());
 	}
 
 	@Override /* AbstractHttpEntity */
 	public byte[] asBytes() throws IOException {
-		return cache == null ? readBytes(this.content) : cache;
+		if (isCached() && byteCache == null)
+			byteCache = readBytes(content(), getMaxLength());
+		if (byteCache != null)
+			return byteCache;
+		return readBytes(content());
 	}
 
 	@Override /* HttpEntity */
@@ -80,24 +109,30 @@ public class FileEntity extends BasicHttpEntity {
 
 	@Override /* HttpEntity */
 	public long getContentLength() {
-		return content == null ? 0 : content.length();
+		return content().length();
 	}
 
 	@Override /* HttpEntity */
 	public InputStream getContent() throws IOException {
-		return cache == null ? new FileInputStream(content) : new ByteArrayInputStream(cache);
+		if (isCached())
+			return new ByteArrayInputStream(asBytes());
+		return new FileInputStream(content());
 	}
 
 	@Override /* HttpEntity */
 	public void writeTo(OutputStream out) throws IOException {
 		assertArgNotNull("out", out);
 
-		if (cache != null) {
-			out.write(cache);
+		if (isCached()) {
+			out.write(asBytes());
 		} else {
 			try (InputStream is = getContent()) {
-				IOUtils.pipe(is, out);
+				IOUtils.pipe(is, out, getMaxLength());
 			}
 		}
 	}
+
+	// <FluentSetters>
+
+	// </FluentSetters>
 }
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/HttpEntityBuilder.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/HttpEntityBuilder.java
deleted file mode 100644
index 04087dd56..000000000
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/HttpEntityBuilder.java
+++ /dev/null
@@ -1,226 +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.entity;
-
-import static org.apache.juneau.internal.ThrowableUtils.*;
-
-import java.io.*;
-import java.nio.charset.*;
-import java.util.function.*;
-
-import org.apache.http.*;
-import org.apache.juneau.http.header.*;
-import org.apache.juneau.internal.*;
-
-/**
- * Builder for {@link HttpEntity} beans.
- *
- * <ul class='seealso'>
- * 	<li class='link'>{@doc juneau-rest-common}
- * 	<li class='extlink'>{@source}
- * </ul>
- *
- * @param <T> The bean type to create for this builder.
- */
-@FluentSetters(returns="HttpEntityBuilder<T>")
-public class HttpEntityBuilder<T extends BasicHttpEntity> {
-
-	boolean cached, chunked;
-	Object content;
-	Supplier<?> contentSupplier;
-	ContentType contentType;
-	ContentEncoding contentEncoding;
-	Charset charset;
-	long contentLength = -1;
-
-	/** The HttpEntity implementation class. */
-	protected final Class<? extends BasicHttpEntity> implClass;
-
-	/**
-	 * Constructor.
-	 *
-	 * @param implClass
-	 * 	The subclass of {@link HttpResponse} to create.
-	 * 	<br>This must contain a public constructor that takes in an {@link HttpEntityBuilder} object.
-	 */
-	public HttpEntityBuilder(Class<T> implClass) {
-		this.implClass = implClass;
-	}
-
-	/**
-	 * Copy constructor.
-	 *
-	 * @param impl
-	 * 	The implementation object of {@link HttpEntity} to copy from.
-	 * 	<br>This must contain a public constructor that takes in an {@link HttpEntityBuilder} object.
-	 */
-	public HttpEntityBuilder(T impl) {
-		implClass = impl.getClass();
-		cached = impl.cached;
-		content = impl.content;
-		contentSupplier = impl.contentSupplier;
-		contentType = impl.contentType;
-		contentEncoding = impl.contentEncoding;
-		charset = impl.charset;
-		contentLength = impl.contentLength;
-	}
-
-	/**
-	 * Instantiates the entity bean from the settings in this builder.
-	 *
-	 * @return A new {@link HttpEntity} bean.
-	 */
-	@SuppressWarnings("unchecked")
-	public T build() {
-		try {
-			return (T) implClass.getConstructor(HttpEntityBuilder.class).newInstance(this);
-		} catch (Exception e) {
-			throw asRuntimeException(e);
-		}
-	}
-
-	/**
-	 * Sets the content on this entity bean.
-	 *
-	 * @param value The entity content, can be <jk>null</jk>.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpEntityBuilder<T> content(Object value) {
-		this.content = value;
-		return this;
-	}
-
-	/**
-	 * Sets the content on this entity bean from a supplier.
-	 *
-	 * <p>
-	 * Repeatable entities such as {@link StringEntity} use this to allow the entity content to be resolved at
-	 * serialization time.
-	 *
-	 * @param value The entity content, can be <jk>null</jk>.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpEntityBuilder<T> content(Supplier<?> value) {
-		this.contentSupplier = value == null ? ()->null : value;
-		return this;
-	}
-
-	/**
-	 * Sets the content type on this entity bean.
-	 *
-	 * @param value The new <c>Content-Type</c> header, or <jk>null</jk> to unset.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpEntityBuilder<T> contentType(String value) {
-		return contentType(ContentType.of(value));
-	}
-
-	/**
-	 * Sets the content type on this entity bean.
-	 *
-	 * @param value The new <c>Content-Type</c> header, or <jk>null</jk> to unset.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpEntityBuilder<T> contentType(ContentType value) {
-		contentType = value;
-		return this;
-	}
-
-	/**
-	 * Sets the content length on this entity bean.
-	 *
-	 * @param value The new <c>Content-Length</c> header value, or <c>-1</c> to unset.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpEntityBuilder<T> contentLength(long value) {
-		contentLength = value;
-		return this;
-	}
-
-	/**
-	 * Sets the content encoding header on this entity bean.
-	 *
-	 * @param value The new <c>Content-Encoding</c> header, or <jk>null</jk> to unset.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpEntityBuilder<T> contentEncoding(String value) {
-		return contentEncoding(ContentEncoding.of(value));
-	}
-
-	/**
-	 * Sets the content encoding header on this entity bean.
-	 *
-	 * @param value The new <c>Content-Encoding</c> header, or <jk>null</jk> to unset.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpEntityBuilder<T> contentEncoding(ContentEncoding value) {
-		contentEncoding = value;
-		return this;
-	}
-
-	/**
-	 * Sets the 'chunked' flag value to <jk>true</jk>.
-	 *
-	 * <ul class='notes'>
-	 * 	<li class='note'>If the {@link HttpEntity#getContentLength()} method returns a negative value, the HttpClient code will always
-	 * 		use chunked encoding.
-	 * </ul>
-	 *
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpEntityBuilder<T> chunked() {
-		return chunked(true);
-	}
-
-	/**
-	 * Sets the 'chunked' flag value.
-	 *
-	 * <ul class='notes'>
-	 * 	<li class='note'>If the {@link HttpEntity#getContentLength()} method returns a negative value, the HttpClient code will always
-	 * 		use chunked encoding.
-	 * </ul>
-	 *
-	 * @param value The new value for this flag.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpEntityBuilder<T> chunked(boolean value) {
-		chunked = value;
-		return this;
-	}
-
-	/**
-	 * 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.
-	 * @throws IOException If entity could not be read into memory.
-	 */
-	@FluentSetter
-	public HttpEntityBuilder<T> cached() throws IOException {
-		cached = true;
-		return this;
-	}
-
-	// <FluentSetters>
-
-	// </FluentSetters>
-}
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/ReaderEntity.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/ReaderEntity.java
index 35ec9d2aa..6935dac21 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/ReaderEntity.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/ReaderEntity.java
@@ -14,11 +14,10 @@ package org.apache.juneau.http.entity;
 
 import static org.apache.juneau.internal.ArgUtils.*;
 import static org.apache.juneau.internal.IOUtils.*;
-import static org.apache.juneau.internal.ObjectUtils.*;
 
 import java.io.*;
-import java.nio.charset.*;
 
+import org.apache.juneau.http.header.*;
 import org.apache.juneau.internal.*;
 
 /**
@@ -29,69 +28,93 @@ import org.apache.juneau.internal.*;
  * 	<li class='extlink'>{@source}
  * </ul>
  */
+@FluentSetters
 public class ReaderEntity extends BasicHttpEntity {
 
-	private final Reader content;
-	private final long contentLength;
-	private final Charset charset;
-	private final byte[] cache;
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private byte[] byteCache;
+	private String stringCache;
 
 	/**
-	 * Creates a new {@link ReaderEntity} builder.
-	 *
-	 * @return A new {@link ReaderEntity} builder.
+	 * Constructor.
 	 */
-	public static HttpEntityBuilder<ReaderEntity> create() {
-		return new HttpEntityBuilder<>(ReaderEntity.class);
+	public ReaderEntity() {
+		super();
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The entity builder.
-	 * @throws IOException If reader could not be read.
+	 * @param contentType The entity content type.
+	 * @param content The entity contents.
 	 */
-	public ReaderEntity(HttpEntityBuilder<?> builder) throws IOException {
-		super(builder);
-		content = contentOrElse(EMPTY_READER);
-		charset = firstNonNull(builder.charset, UTF8);
-		cache = builder.cached ? readBytes(this.content) : null;
-		contentLength = builder.contentLength == -1 && cache != null ? cache.length : builder.contentLength;
+	public ReaderEntity(ContentType contentType, Reader content) {
+		super(contentType, content);
 	}
 
 	/**
-	 * Creates a new {@link ReaderEntity} builder initialized with the contents of this entity.
+	 * Copy constructor.
 	 *
-	 * @return A new {@link ReaderEntity} builder initialized with the contents of this entity.
+	 * @param copyFrom The bean being copied.
 	 */
-	@Override /* BasicHttpEntity */
-	public HttpEntityBuilder<ReaderEntity> copy() {
-		return new HttpEntityBuilder<>(this);
+	protected ReaderEntity(ReaderEntity copyFrom) {
+		super(copyFrom);
+	}
+
+	@Override
+	public ReaderEntity copy() {
+		return new ReaderEntity(this);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other methods
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private Reader content() {
+		Reader r = contentOrElse((Reader)null);
+		if (r == null)
+			throw new RuntimeException("Reader is null.");
+		return r;
 	}
 
 	@Override /* AbstractHttpEntity */
 	public String asString() throws IOException {
-		return cache == null ? read(content) : new String(cache, UTF8);
+		if (isCached() && stringCache == null)
+			stringCache = read(content(), getMaxLength());
+		if (stringCache != null)
+			return stringCache;
+		return read(content());
 	}
 
 	@Override /* AbstractHttpEntity */
 	public byte[] asBytes() throws IOException {
-		return cache == null ? asString().getBytes(UTF8) : cache;
+		if (isCached() && byteCache == null)
+			byteCache = readBytes(content());
+		if (byteCache != null)
+			return byteCache;
+		return readBytes(content());
 	}
 
 	@Override /* HttpEntity */
 	public boolean isRepeatable() {
-		return cache != null;
+		return isCached();
 	}
 
 	@Override /* HttpEntity */
 	public long getContentLength() {
-		return contentLength;
+		if (isCached())
+			return asSafeBytes().length;
+		return super.getContentLength();
 	}
 
 	@Override /* HttpEntity */
 	public InputStream getContent() throws IOException {
-		return cache == null ? new ReaderInputStream(content, charset) : new ByteArrayInputStream(cache);
+		if (isCached())
+			return new ByteArrayInputStream(asBytes());
+		return new ReaderInputStream(content(), getCharset());
 	}
 
 	/**
@@ -104,11 +127,11 @@ public class ReaderEntity extends BasicHttpEntity {
 	public void writeTo(OutputStream out) throws IOException {
 		assertArgNotNull("out", out);
 
-		if (cache != null) {
-			out.write(cache);
+		if (isCached()) {
+			out.write(asBytes());
 		} else {
-			OutputStreamWriter osw = new OutputStreamWriter(out, charset);
-			pipe(content, osw);
+			OutputStreamWriter osw = new OutputStreamWriter(out, getCharset());
+			pipe(content(), osw);
 			osw.flush();
 		}
 		out.flush();
@@ -116,6 +139,10 @@ public class ReaderEntity extends BasicHttpEntity {
 
 	@Override /* HttpEntity */
 	public boolean isStreaming() {
-		return cache == null;
+		return ! isCached();
 	}
+
+	// <FluentSetters>
+
+	// </FluentSetters>
 }
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/SerializedEntity.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/SerializedEntity.java
index 5893a594e..5f3cea9c0 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/SerializedEntity.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/SerializedEntity.java
@@ -20,6 +20,7 @@ import java.io.*;
 
 import org.apache.http.*;
 import org.apache.juneau.*;
+import org.apache.juneau.http.header.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.serializer.*;
@@ -32,40 +33,62 @@ import org.apache.juneau.serializer.*;
  * 	<li class='extlink'>{@source}
  * </ul>
  */
+@FluentSetters
 public class SerializedEntity extends BasicHttpEntity {
-	final Serializer serializer;
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instances
+	//-----------------------------------------------------------------------------------------------------------------
+
+	Serializer serializer;
 	HttpPartSchema schema;
 
 	/**
-	 * Creates a new {@link SerializedEntity} builder.
-	 *
-	 * @return A new {@link SerializedEntity} builder.
+	 * Constructor.
 	 */
-	public static SerializedEntityBuilder<SerializedEntity> create() {
-		return new SerializedEntityBuilder<>(SerializedEntity.class);
+	public SerializedEntity() {
+		super();
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The builder for this bean.
+	 * @param contentType The entity content type.
+	 * @param content The entity content.
+	 * @param serializer The entity serializer.
+	 * @param schema The entity schema.  Can be <jk>null</jk>.
 	 */
-	public SerializedEntity(SerializedEntityBuilder<?> builder) {
-		super(builder);
-		serializer = builder.serializer;
-		schema = builder.schema;
+	public SerializedEntity(ContentType contentType, Object content, Serializer serializer, HttpPartSchema schema) {
+		super(contentType, content);
+		this.serializer = serializer;
+		this.schema = schema;
 	}
 
 	/**
-	 * Creates a copy of this object.
+	 * Copy constructor.
 	 *
-	 * @return A new copy of this object.
+	 * @param copyFrom The bean being copied.
+	 */
+	public SerializedEntity(SerializedEntity copyFrom) {
+		super(copyFrom);
+		this.serializer = copyFrom.serializer;
+		this.schema = copyFrom.schema;
+	}
+
+	/**
+	 * Creates a builder for this class initialized with the contents of this bean.
+	 *
+	 * <p>
+	 * Allows you to create a modifiable copy of this bean.
+	 *
+	 * @return A new builder bean.
 	 */
 	@Override
-	public SerializedEntityBuilder<SerializedEntity> copy() {
-		return new SerializedEntityBuilder<>(this);
+	public SerializedEntity copy() {
+		return new SerializedEntity(this);
 	}
 
+
 	/**
 	 * Copies this bean and sets the serializer and schema on it.
 	 *
@@ -76,16 +99,49 @@ public class SerializedEntity extends BasicHttpEntity {
 	 */
 	public SerializedEntity copyWith(Serializer serializer, HttpPartSchema schema) {
 		if ((this.serializer == null && serializer != null) || (this.schema == null && schema != null)) {
-			SerializedEntityBuilder<SerializedEntity> h = copy();
+			SerializedEntity h = copy();
 			if (serializer != null)
-				h.serializer(serializer);
+				h.setSerializer(serializer);
 			if (schema != null)
-				h.schema(schema);
-			return h.build();
+				h.setSchema(schema);
+			return h;
 		}
 		return this;
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Sets the serializer on this entity bean.
+	 *
+	 * @param value The entity serializer, can be <jk>null</jk>.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public SerializedEntity setSerializer(Serializer value) {
+		assertModifiable();
+		this.serializer = value;
+		return this;
+	}
+
+	/**
+	 * Sets the schema on this entity bean.
+	 *
+	 * <p>
+	 * Used to provide instructions to the serializer on how to serialize this object.
+	 *
+	 * @param value The entity schema, can be <jk>null</jk>.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public SerializedEntity setSchema(HttpPartSchema value) {
+		assertModifiable();
+		this.schema = value;
+		return this;
+	}
+
+
+
 	@Override
 	public Header getContentType() {
 		Header x = super.getContentType();
@@ -134,4 +190,8 @@ public class SerializedEntity extends BasicHttpEntity {
 			throw asRuntimeException(e);
 		}
 	}
+
+	// <FluentSetters>
+
+	// </FluentSetters>
 }
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/SerializedEntityBuilder.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/SerializedEntityBuilder.java
deleted file mode 100644
index f2e80155a..000000000
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/SerializedEntityBuilder.java
+++ /dev/null
@@ -1,172 +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.entity;
-
-import static org.apache.juneau.internal.ThrowableUtils.*;
-
-import java.io.*;
-import java.util.function.*;
-
-import org.apache.http.*;
-import org.apache.juneau.httppart.*;
-import org.apache.juneau.internal.*;
-import org.apache.juneau.serializer.*;
-import org.apache.juneau.http.header.*;
-
-
-/**
- * Builder for {@link SerializedEntity} beans.
- *
- * <ul class='seealso'>
- * 	<li class='link'>{@doc juneau-rest-common}
- * 	<li class='extlink'>{@source}
- * </ul>
- *
- * @param <T> The bean type to create for this builder.
- */
-@FluentSetters(returns="SerializedEntityBuilder<T>")
-public class SerializedEntityBuilder<T extends SerializedEntity> extends HttpEntityBuilder<T> {
-
-	Serializer serializer;
-	HttpPartSchema schema;
-
-	/**
-	 * Constructor.
-	 *
-	 * @param implClass
-	 * 	The subclass of {@link HttpResponse} to create.
-	 * 	<br>This must contain a public constructor that takes in an {@link HttpEntityBuilder} object.
-	 */
-	public SerializedEntityBuilder(Class<T> implClass) {
-		super(implClass);
-	}
-
-	/**
-	 * Copy constructor.
-	 *
-	 * @param impl
-	 * 	The implementation object of {@link HttpEntity} to copy from.
-	 * 	<br>This must contain a public constructor that takes in an {@link HttpEntityBuilder} object.
-	 */
-	public SerializedEntityBuilder(T impl) {
-		super(impl);
-		this.serializer = impl.serializer;
-		this.schema = impl.schema;
-	}
-
-	/**
-	 * Instantiates the entity bean from the settings in this builder.
-	 *
-	 * @return A new {@link SerializedEntity} bean.
-	 */
-	@Override
-	@SuppressWarnings("unchecked")
-	public T build() {
-		try {
-			return (T) implClass.getConstructor(SerializedEntityBuilder.class).newInstance(this);
-		} catch (Exception e) {
-			throw asRuntimeException(e);
-		}
-	}
-
-	/**
-	 * Sets the serializer on this entity bean.
-	 *
-	 * @param value The entity serializer, can be <jk>null</jk>.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public SerializedEntityBuilder<T> serializer(Serializer value) {
-		this.serializer = value;
-		return this;
-	}
-
-	/**
-	 * Sets the schema on this entity bean.
-	 *
-	 * <p>
-	 * Used to provide instructions to the serializer on how to serialize this object.
-	 *
-	 * @param value The entity schema, can be <jk>null</jk>.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public SerializedEntityBuilder<T> schema(HttpPartSchema value) {
-		this.schema = value;
-		return this;
-	}
-
-	// <FluentSetters>
-
-	@Override /* GENERATED - org.apache.juneau.http.entity.HttpEntityBuilder */
-	public SerializedEntityBuilder<T> cached() throws IOException{
-		super.cached();
-		return this;
-	}
-
-	@Override /* GENERATED - org.apache.juneau.http.entity.HttpEntityBuilder */
-	public SerializedEntityBuilder<T> chunked() {
-		super.chunked();
-		return this;
-	}
-
-	@Override /* GENERATED - org.apache.juneau.http.entity.HttpEntityBuilder */
-	public SerializedEntityBuilder<T> chunked(boolean value) {
-		super.chunked(value);
-		return this;
-	}
-
-	@Override /* GENERATED - org.apache.juneau.http.entity.HttpEntityBuilder */
-	public SerializedEntityBuilder<T> content(Object value) {
-		super.content(value);
-		return this;
-	}
-
-	@Override /* GENERATED - org.apache.juneau.http.entity.HttpEntityBuilder */
-	public SerializedEntityBuilder<T> content(Supplier<?> value) {
-		super.content(value);
-		return this;
-	}
-
-	@Override /* GENERATED - org.apache.juneau.http.entity.HttpEntityBuilder */
-	public SerializedEntityBuilder<T> contentEncoding(String value) {
-		super.contentEncoding(value);
-		return this;
-	}
-
-	@Override /* GENERATED - org.apache.juneau.http.entity.HttpEntityBuilder */
-	public SerializedEntityBuilder<T> contentEncoding(ContentEncoding value) {
-		super.contentEncoding(value);
-		return this;
-	}
-
-	@Override /* GENERATED - org.apache.juneau.http.entity.HttpEntityBuilder */
-	public SerializedEntityBuilder<T> contentLength(long value) {
-		super.contentLength(value);
-		return this;
-	}
-
-	@Override /* GENERATED - org.apache.juneau.http.entity.HttpEntityBuilder */
-	public SerializedEntityBuilder<T> contentType(String value) {
-		super.contentType(value);
-		return this;
-	}
-
-	@Override /* GENERATED - org.apache.juneau.http.entity.HttpEntityBuilder */
-	public SerializedEntityBuilder<T> contentType(ContentType value) {
-		super.contentType(value);
-		return this;
-	}
-
-	// </FluentSetters>
-}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/StreamEntity.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/StreamEntity.java
index b6828847a..82f61c6d7 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/StreamEntity.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/StreamEntity.java
@@ -17,6 +17,9 @@ import static org.apache.juneau.internal.IOUtils.*;
 
 import java.io.*;
 
+import org.apache.juneau.http.header.*;
+import org.apache.juneau.internal.*;
+
 /**
  * A streamed, non-repeatable entity that obtains its content from an {@link InputStream}.
  *
@@ -25,67 +28,93 @@ import java.io.*;
  * 	<li class='extlink'>{@source}
  * </ul>
  */
+@FluentSetters
 public class StreamEntity extends BasicHttpEntity {
 
-	private final InputStream content;
-	private final long maxLength;
-	private final byte[] cache;
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private byte[] byteCache;
+	private String stringCache;
 
 	/**
-	 * Creates a new {@link StreamEntity} builder.
-	 *
-	 * @return A new {@link StreamEntity} builder.
+	 * Constructor.
 	 */
-	public static HttpEntityBuilder<StreamEntity> create() {
-		return new HttpEntityBuilder<>(StreamEntity.class);
+	public StreamEntity() {
+		super();
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The entity builder.
-	 * @throws IOException If stream could not be read.
+	 * @param contentType The entity content type.
+	 * @param content The entity contents.
 	 */
-	public StreamEntity(HttpEntityBuilder<?> builder) throws IOException {
-		super(builder);
-		content = contentOrElse(EMPTY_INPUT_STREAM);
-		cache = builder.cached ? readBytes(content) : null;
-		maxLength = builder.contentLength == -1 && cache != null ? cache.length : builder.contentLength;
+	public StreamEntity(ContentType contentType, InputStream content) {
+		super(contentType, content);
 	}
 
 	/**
-	 * Creates a new {@link StreamEntity} builder initialized with the contents of this entity.
+	 * Copy constructor.
 	 *
-	 * @return A new {@link StreamEntity} builder initialized with the contents of this entity.
+	 * @param copyFrom The bean being copied.
 	 */
-	@Override /* BasicHttpEntity */
-	public HttpEntityBuilder<StreamEntity> copy() {
-		return new HttpEntityBuilder<>(this);
+	protected StreamEntity(StreamEntity copyFrom) {
+		super(copyFrom);
+	}
+
+	@Override
+	public StreamEntity copy() {
+		return new StreamEntity(this);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other methods
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private InputStream content() {
+		InputStream is = contentOrElse((InputStream)null);
+		if (is == null)
+			throw new RuntimeException("Input stream is null.");
+		return is;
 	}
 
 	@Override /* AbstractHttpEntity */
 	public String asString() throws IOException {
-		return new String(asBytes(), UTF8);
+		if (isCached() && stringCache == null)
+			stringCache = read(content(), getCharset());
+		if (stringCache != null)
+			return stringCache;
+		return read(content());
 	}
 
 	@Override /* AbstractHttpEntity */
 	public byte[] asBytes() throws IOException {
-		return cache == null ? readBytes(content) : cache;
+		if (isCached() && byteCache == null)
+			byteCache = readBytes(content(), getMaxLength());
+		if (byteCache != null)
+			return byteCache;
+		return readBytes(content(), getMaxLength());
 	}
 
 	@Override /* HttpEntity */
 	public boolean isRepeatable() {
-		return cache != null;
+		return isCached();
 	}
 
 	@Override /* HttpEntity */
 	public long getContentLength() {
-		return maxLength;
+		if (isCached())
+			return asSafeBytes().length;
+		return super.getContentLength();
 	}
 
 	@Override /* HttpEntity */
 	public InputStream getContent() throws IOException {
-		return cache == null ? content : new ByteArrayInputStream(cache);
+		if (isCached())
+			return new ByteArrayInputStream(asBytes());
+		return content();
 	}
 
 	/**
@@ -98,17 +127,21 @@ public class StreamEntity extends BasicHttpEntity {
 	public void writeTo(OutputStream out) throws IOException {
 		assertArgNotNull("out", out);
 
-		if (cache != null) {
-			pipe(cache, out, (int)maxLength);
+		if (isCached()) {
+			out.write(asBytes());
 		} else {
 			try (InputStream is = getContent()) {
-				pipe(is, out, maxLength);
+				pipe(is, out, getMaxLength());
 			}
 		}
 	}
 
 	@Override /* HttpEntity */
 	public boolean isStreaming() {
-		return cache == null;
+		return ! isCached();
 	}
+
+	// <FluentSetters>
+
+	// </FluentSetters>
 }
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/StringEntity.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/StringEntity.java
index d47b4bd4c..0b79a7f9b 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/StringEntity.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/entity/StringEntity.java
@@ -14,11 +14,10 @@ package org.apache.juneau.http.entity;
 
 import static org.apache.juneau.internal.ArgUtils.*;
 import static org.apache.juneau.internal.IOUtils.*;
-import static org.apache.juneau.internal.ObjectUtils.*;
 
 import java.io.*;
-import java.nio.charset.Charset;
 
+import org.apache.juneau.http.header.*;
 import org.apache.juneau.internal.*;
 
 /**
@@ -29,50 +28,72 @@ import org.apache.juneau.internal.*;
  * 	<li class='extlink'>{@source}
  * </ul>
  */
+@FluentSetters
 public class StringEntity extends BasicHttpEntity {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Static
+	//-----------------------------------------------------------------------------------------------------------------
+
 	private static final String EMPTY = "";
 
-	private final byte[] cache;
-	private final Charset charset;
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private byte[] byteCache;
 
 	/**
-	 * Creates a new {@link StringEntity} builder.
-	 *
-	 * @return A new {@link StringEntity} builder.
+	 * Constructor.
 	 */
-	public static HttpEntityBuilder<StringEntity> create() {
-		return new HttpEntityBuilder<>(StringEntity.class);
+	public StringEntity() {
+		super();
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The entity builder.
+	 * @param contentType The entity content type.
+	 * @param content The entity contents.
 	 */
-	public StringEntity(HttpEntityBuilder<?> builder) {
-		super(builder);
-		charset = firstNonNull(builder.charset, UTF8);
-		cache = builder.cached ? string().getBytes(charset) : null;
+	public StringEntity(ContentType contentType, String content) {
+		super(contentType, content);
 	}
 
 	/**
-	 * Creates a new {@link StringEntity} builder initialized with the contents of this entity.
+	 * Copy constructor.
 	 *
-	 * @return A new {@link StringEntity} builder initialized with the contents of this entity.
+	 * @param copyFrom The bean being copied.
 	 */
-	@Override /* BasicHttpEntity */
-	public HttpEntityBuilder<StringEntity> copy() {
-		return new HttpEntityBuilder<>(this);
+	protected StringEntity(StringEntity copyFrom) {
+		super(copyFrom);
+	}
+
+	@Override
+	public StringEntity copy() {
+		return new StringEntity(this);
 	}
 
-	private String string() {
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other methods
+	//-----------------------------------------------------------------------------------------------------------------
+
+	private String content() {
 		return contentOrElse(EMPTY);
 	}
 
-	@Override
+	@Override /* AbstractHttpEntity */
+	public String asString() throws IOException {
+		return content();
+	}
+
+	@Override /* AbstractHttpEntity */
 	public byte[] asBytes() throws IOException {
-		return cache == null ? string().getBytes() : cache;
+		if (isCached() && byteCache == null)
+			byteCache = content().getBytes(getCharset());
+		if (byteCache != null)
+			return byteCache;
+		return content().getBytes(getCharset());
 	}
 
 	@Override /* HttpEntity */
@@ -82,13 +103,13 @@ public class StringEntity extends BasicHttpEntity {
 
 	@Override /* HttpEntity */
 	public long getContentLength() {
-		if (cache != null)
-			return cache.length;
+		if (isCached())
+			return asSafeBytes().length;
 		long l = super.getContentLength();
 		if (l != -1 || isSupplied())
 			return l;
-		String s = string();
-		if (charset == UTF8)
+		String s = content();
+		if (getCharset() == UTF8)
 			for (int i = 0; i < s.length(); i++)
 				if (s.charAt(i) > 127)
 					return -1;
@@ -97,22 +118,19 @@ public class StringEntity extends BasicHttpEntity {
 
 	@Override /* HttpEntity */
 	public InputStream getContent() throws IOException {
-		if (cache != null)
-			return new ByteArrayInputStream(cache);
-		String s = string();
-		if (s == null)
-			return IOUtils.EMPTY_INPUT_STREAM;
-		return new ReaderInputStream(new StringReader(s), charset);
+		if (isCached())
+			return new ByteArrayInputStream(asBytes());
+		return new ReaderInputStream(new StringReader(content()), getCharset());
 	}
 
 	@Override /* HttpEntity */
 	public void writeTo(OutputStream out) throws IOException {
 		assertArgNotNull("out", out);
-		if (cache != null) {
-			out.write(cache);
+		if (isCached()) {
+			out.write(asBytes());
 		} else {
-			OutputStreamWriter osw = new OutputStreamWriter(out, charset);
-			osw.write(string());
+			OutputStreamWriter osw = new OutputStreamWriter(out, getCharset());
+			osw.write(content());
 			osw.flush();
 		}
 	}
@@ -121,5 +139,9 @@ public class StringEntity extends BasicHttpEntity {
 	public boolean isStreaming() {
 		return false;
 	}
+
+	// <FluentSetters>
+
+	// </FluentSetters>
 }
 
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/BasicResource.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/BasicResource.java
index f9f71cfa7..2e9e3ebee 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/BasicResource.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/BasicResource.java
@@ -12,13 +12,17 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.http.resource;
 
+import static org.apache.juneau.internal.StringUtils.*;
+
 import java.io.*;
+import java.util.function.*;
 
 import org.apache.http.*;
 import org.apache.juneau.annotation.*;
 import org.apache.juneau.assertions.*;
 import org.apache.juneau.http.entity.*;
 import org.apache.juneau.http.header.*;
+import org.apache.juneau.internal.*;
 
 /**
  * A basic {@link org.apache.juneau.http.resource.HttpResource} implementation with additional features.
@@ -43,31 +47,34 @@ import org.apache.juneau.http.header.*;
 @BeanIgnore  /* Use toString() to serialize */
 public class BasicResource implements HttpResource {
 
-	final BasicHttpEntity entity;
-	final HeaderList headers;
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
+	BasicHttpEntity entity;
+	HeaderList headers = HeaderList.create();
+	boolean unmodifiable;
 
 	/**
-	 * Creates a builder for this class.
+	 * Constructor.
 	 *
-	 * @param <T> The subclass that the builder is going to create.
-	 * @param implClass The subclass that the builder is going to create.
-	 * @param entityImplClass The entity subclass that the builder is going to create.
-	 * @return A new builder bean.
+	 * @param entity The entity that makes up this resource content.
 	 */
-	public static <T extends BasicResource> HttpResourceBuilder<T> create(Class<T> implClass, Class<? extends BasicHttpEntity> entityImplClass) {
-		return new HttpResourceBuilder<>(implClass, entityImplClass);
+	public BasicResource(BasicHttpEntity entity) {
+		this.entity = entity;
 	}
 
 	/**
-	 * Constructor.
+	 * Copy constructor.
 	 *
-	 * @param builder The builder containing the arguments for this bean.
+	 * @param copyFrom The bean bean copied.
 	 */
-	public BasicResource(HttpResourceBuilder<?> builder) {
-		this.entity = builder.entity();
-		this.headers = builder.headers.copy();
+	public BasicResource(BasicResource copyFrom) {
+		this.entity = copyFrom.entity.copy();
+		this.headers = copyFrom.headers.copy();
 	}
 
+
 	/**
 	 * Constructor.
 	 *
@@ -78,7 +85,8 @@ public class BasicResource implements HttpResource {
 	 * @throws IOException Rethrown from {@link HttpEntity#getContent()}.
 	 */
 	public BasicResource(HttpResponse response) throws IOException {
-		this(create(null, StreamEntity.class).copyFrom(response));
+		this(new StreamEntity());
+		copyFrom(response);
 	}
 
 	/**
@@ -89,10 +97,307 @@ public class BasicResource implements HttpResource {
 	 *
 	 * @return A new builder bean.
 	 */
-	public HttpResourceBuilder<? extends BasicResource> copy() {
-		return new HttpResourceBuilder<>(this);
+	public BasicResource copy() {
+		return new BasicResource(this);
+	}
+
+	/**
+	 * Copies the contents of the specified HTTP response to this builder.
+	 *
+	 * @param response The response to copy from.  Must not be null.
+	 * @return This object.
+	 * @throws IOException If content could not be retrieved.
+	 */
+	public BasicResource copyFrom(HttpResponse response) throws IOException {
+		addHeaders(response.getAllHeaders());
+		setContent(response.getEntity().getContent());
+		return this;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Properties
+	//-----------------------------------------------------------------------------------------------------------------
+
+
+	/**
+	 * Specifies whether this bean should be unmodifiable.
+	 * <p>
+	 * When enabled, attempting to set any properties on this bean will cause an {@link UnsupportedOperationException}.
+	 *
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicResource setUnmodifiable() {
+		unmodifiable = true;
+		entity.setUnmodifiable();
+		headers.setUnmodifiable();
+		return this;
+	}
+
+	/**
+	 * Returns <jk>true</jk> if this bean is unmodifiable.
+	 *
+	 * @return <jk>true</jk> if this bean is unmodifiable.
+	 */
+	public boolean isUnmodifiable() {
+		return unmodifiable;
+	}
+
+	/**
+	 * Throws an {@link UnsupportedOperationException} if the unmodifiable flag is set on this bean.
+	 */
+	protected final void assertModifiable() {
+		if (unmodifiable)
+			throw new UnsupportedOperationException("Bean is read-only");
+	}
+
+	/**
+	 * Returns access to the underlying builder for the HTTP entity.
+	 *
+	 * @return The underlying builder for the HTTP entity.
+	 */
+	public HttpEntity getEntity() {
+		return entity;
+	}
+
+	/**
+	 * Sets the content on this entity bean.
+	 *
+	 * @param value The entity content, can be <jk>null</jk>.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicResource setContent(Object value) {
+		entity.setContent(value);
+		return this;
+	}
+
+	/**
+	 * Sets the content on this entity bean from a supplier.
+	 *
+	 * <p>
+	 * Repeatable entities such as {@link StringEntity} use this to allow the entity content to be resolved at
+	 * serialization time.
+	 *
+	 * @param value The entity content, can be <jk>null</jk>.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicResource setContent(Supplier<?> value) {
+		entity.setContent(value);
+		return this;
+	}
+
+	/**
+	 * Sets the content type on this entity bean.
+	 *
+	 * @param value The new <c>Content-Type</c> header, or <jk>null</jk> to unset.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicResource setContentType(String value) {
+		entity.setContentType(value);
+		return this;
+	}
+
+	/**
+	 * Sets the content type on this entity bean.
+	 *
+	 * @param value The new <c>Content-Type</c> header, or <jk>null</jk> to unset.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicResource setContentType(ContentType value) {
+		entity.setContentType(value);
+		return this;
+	}
+
+	/**
+	 * Sets the content length on this entity bean.
+	 *
+	 * @param value The new <c>Content-Length</c> header value, or <c>-1</c> to unset.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicResource setContentLength(long value) {
+		entity.setContentLength(value);
+		return this;
+	}
+
+	/**
+	 * Sets the content encoding header on this entity bean.
+	 *
+	 * @param value The new <c>Content-Encoding</c> header, or <jk>null</jk> to unset.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicResource setContentEncoding(String value) {
+		entity.setContentEncoding(value);
+		return this;
+	}
+
+	/**
+	 * Sets the content encoding header on this entity bean.
+	 *
+	 * @param value The new <c>Content-Encoding</c> header, or <jk>null</jk> to unset.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicResource setContentEncoding(ContentEncoding value) {
+		entity.setContentEncoding(value);
+		return this;
+	}
+
+	/**
+	 * Sets the 'chunked' flag value to <jk>true</jk>.
+	 *
+	 * <ul class='notes'>
+	 * 	<li>If the {@link HttpEntity#getContentLength()} method returns a negative value, the HttpClient code will always
+	 * 		use chunked encoding.
+	 * </ul>
+	 *
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicResource setChunked() {
+		entity.setChunked();
+		return this;
+	}
+
+	/**
+	 * Sets the 'chunked' flag value.
+	 *
+	 * <ul class='notes'>
+	 * 	<li class='note'>If the {@link HttpEntity#getContentLength()} method returns a negative value, the HttpClient code will always
+	 * 		use chunked encoding.
+	 * </ul>
+	 *
+	 * @param value The new value for this flag.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicResource setChunked(boolean value) {
+		entity.setChunked(value);
+		return this;
+	}
+
+	/**
+	 * 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.
+	 * @throws IOException If entity could not be read into memory.
+	 */
+	@FluentSetter
+	public BasicResource setCached() throws IOException {
+		entity.setCached();
+		return this;
 	}
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// BasicHeaderGroup setters.
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Sets the specified header in this builder.
+	 *
+	 * <p>
+	 * This is a no-op if either the name or value is <jk>null</jk>.
+	 *
+	 * @param name The header name.
+	 * @param value The header value.
+	 * @return This object.
+	 */
+	public BasicResource setHeader(String name, String value) {
+		if (name != null && value != null)
+			headers.set(name, value);
+		return this;
+	}
+
+	/**
+	 * Appends the specified header to the end of the headers in this builder.
+	 *
+	 * <p>
+	 * This is a no-op if either the name or value is <jk>null</jk>.
+	 *
+	 * @param name The header name.
+	 * @param value The header value.
+	 * @return This object.
+	 */
+	public BasicResource addHeader(String name, String value) {
+		if (name != null && value != null)
+			headers.append(name, value);
+		return this;
+	}
+
+	/**
+	 * Sets the specified headers in this builder.
+	 *
+	 * @param value The new value.
+	 * @return This object.
+	 */
+	@FluentSetter
+	public BasicResource setHeaders(HeaderList value) {
+		headers = value.copy();
+		return this;
+	}
+
+	/**
+	 * Sets the specified headers in this builder.
+	 *
+	 * @param values The headers to add.  <jk>null</jk> values are ignored.
+	 * @return This object.
+	 */
+	public BasicResource setHeaders(Header...values) {
+		for (Header h : values) {
+			if (h != null) {
+				String n = h.getName();
+				String v = h.getValue();
+				if (isNotEmpty(n)) {
+					if (n.equalsIgnoreCase("content-type"))
+						setContentType(v);
+					else if (n.equalsIgnoreCase("content-encoding"))
+						setContentEncoding(v);
+					else if (n.equalsIgnoreCase("content-length"))
+						setContentLength(Long.parseLong(v));
+					else
+						headers.set(h);
+				}
+			}
+		}
+		return this;
+	}
+
+	/**
+	 * Appends the specified headers to the end of the headers in this builder.
+	 *
+	 * @param values The headers to set.  <jk>null</jk> headers and headers with <jk>null</jk> names or values are ignored.
+	 * @return This object.
+	 */
+	public BasicResource addHeaders(Header...values) {
+		for (Header h : values) {
+			if (h != null) {
+				String n = h.getName();
+				String v = h.getValue();
+				if (isNotEmpty(n)) {
+					if (n.equalsIgnoreCase("content-type"))
+						setContentType(v);
+					else if (n.equalsIgnoreCase("content-encoding"))
+						setContentEncoding(v);
+					else if (n.equalsIgnoreCase("content-length"))
+						setContentLength(Long.parseLong(v));
+					else
+						headers.append(h);
+				}
+			}
+		}
+		return this;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
+	// Other methods
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
 	 * Converts the contents of the entity of this resource as a string.
 	 *
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/ByteArrayResource.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/ByteArrayResource.java
index e99ca1718..0bcc13136 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/ByteArrayResource.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/ByteArrayResource.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.http.resource;
 
 import org.apache.juneau.http.entity.*;
+import org.apache.juneau.http.header.*;
 
 /**
  * A repeatable resource that obtains its content from a byte array.
@@ -24,31 +25,38 @@ import org.apache.juneau.http.entity.*;
  */
 public class ByteArrayResource extends BasicResource {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
-	 * Creates a new {@link ByteArrayResource} builder.
-	 *
-	 * @return A new {@link ByteArrayResource} builder.
+	 * Constructor.
 	 */
-	public static HttpResourceBuilder<ByteArrayResource> create() {
-		return new HttpResourceBuilder<>(ByteArrayResource.class, ByteArrayEntity.class);
+	public ByteArrayResource() {
+		super(new ByteArrayEntity());
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The resource builder.
+	 * @param contentType The entity content type.
+	 * @param contents The entity contents.
 	 */
-	public ByteArrayResource(HttpResourceBuilder<?> builder) {
-		super(builder);
+	public ByteArrayResource(ContentType contentType, byte[] contents) {
+		super(new ByteArrayEntity(contentType, contents));
 	}
 
 	/**
-	 * Creates a new {@link ByteArrayResource} builder initialized with the contents of this entity.
+	 * Copy constructor.
 	 *
-	 * @return A new {@link ByteArrayResource} builder initialized with the contents of this entity.
+	 * @param copyFrom The bean being copied.
 	 */
-	@Override /* BasicResource */
-	public HttpResourceBuilder<ByteArrayResource> copy() {
-		return new HttpResourceBuilder<>(this);
+	protected ByteArrayResource(ByteArrayResource copyFrom) {
+		super(copyFrom);
+	}
+
+	@Override
+	public ByteArrayResource copy() {
+		return new ByteArrayResource(this);
 	}
 }
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/FileResource.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/FileResource.java
index d40edcfe4..974c13210 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/FileResource.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/FileResource.java
@@ -14,6 +14,7 @@ package org.apache.juneau.http.resource;
 
 import java.io.*;
 import org.apache.juneau.http.entity.*;
+import org.apache.juneau.http.header.*;
 
 /**
  * A repeatable resource that obtains its content from a {@link File}.
@@ -25,31 +26,38 @@ import org.apache.juneau.http.entity.*;
  */
 public class FileResource extends BasicResource {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
-	 * Creates a new {@link FileResource} builder.
-	 *
-	 * @return A new {@link FileResource} builder.
+	 * Constructor.
 	 */
-	public static HttpResourceBuilder<FileResource> create() {
-		return new HttpResourceBuilder<>(FileResource.class, FileEntity.class);
+	public FileResource() {
+		super(new FileEntity());
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The resource builder.
+	 * @param contentType The entity content type.
+	 * @param contents The entity contents.
 	 */
-	public FileResource(HttpResourceBuilder<?> builder) {
-		super(builder);
+	public FileResource(ContentType contentType, File contents) {
+		super(new FileEntity(contentType, contents));
 	}
 
 	/**
-	 * Creates a new {@link FileResource} builder initialized with the contents of this entity.
+	 * Copy constructor.
 	 *
-	 * @return A new {@link FileResource} builder initialized with the contents of this entity.
+	 * @param copyFrom The bean being copied.
 	 */
-	@Override /* BasicResource */
-	public HttpResourceBuilder<FileResource> copy() {
-		return new HttpResourceBuilder<>(this);
+	protected FileResource(FileResource copyFrom) {
+		super(copyFrom);
+	}
+
+	@Override
+	public FileResource copy() {
+		return new FileResource(this);
 	}
 }
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/HttpResourceBuilder.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/HttpResourceBuilder.java
deleted file mode 100644
index 447d83da6..000000000
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/HttpResourceBuilder.java
+++ /dev/null
@@ -1,363 +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.resource;
-
-import static org.apache.juneau.internal.ThrowableUtils.*;
-import static org.apache.juneau.internal.StringUtils.*;
-
-import java.io.*;
-import java.util.*;
-import java.util.function.*;
-
-import org.apache.http.*;
-import org.apache.juneau.http.entity.*;
-import org.apache.juneau.http.header.*;
-import org.apache.juneau.internal.*;
-
-/**
- * Builder for {@link HttpEntity} beans.
- *
- * <ul class='seealso'>
- * 	<li class='link'>{@doc juneau-rest-common}
- * 	<li class='extlink'>{@source}
- * </ul>
- *
- * @param <T> The bean type to create for this builder.
- */
-@FluentSetters(returns="HttpResourceBuilder<T>")
-public class HttpResourceBuilder<T extends BasicResource> {
-
-	HeaderList headers = HeaderList.create();
-
-	BasicHttpEntity entity;
-	HttpEntityBuilder<?> entityBuilder;
-
-	/** The HttpEntity implementation class. */
-	protected final Class<? extends BasicResource> implClass;
-
-	/** The HttpEntity implementation class. */
-	protected final Class<? extends BasicHttpEntity> entityImplClass;
-
-	/**
-	 * Constructor.
-	 *
-	 * @param implClass
-	 * 	The subclass of {@link HttpResponse} to create.
-	 * 	<br>This must contain a public constructor that takes in an {@link HttpResourceBuilder} object.
-	 * @param entityImplClass
-	 * 	The subclass of {@link BasicHttpEntity} to create.
-	 * 	<br>This must contain a public constructor that takes in an {@link HttpEntityBuilder} object.
-	 */
-	public HttpResourceBuilder(Class<T> implClass, Class<? extends BasicHttpEntity> entityImplClass) {
-		this.implClass = implClass;
-		this.entityImplClass = entityImplClass;
-	}
-
-	/**
-	 * Copy constructor.
-	 *
-	 * @param impl
-	 * 	The implementation object of {@link HttpEntity} to copy from.
-	 * 	<br>This must contain a public constructor that takes in an {@link HttpResourceBuilder} object.
-	 */
-	public HttpResourceBuilder(T impl) {
-		implClass = impl.getClass();
-		headers = impl.headers;
-		entity = impl.entity;
-		this.entityImplClass = entity.getClass();
-	}
-
-	/**
-	 * Instantiates the entity bean from the settings in this builder.
-	 *
-	 * @return A new {@link HttpEntity} bean.
-	 */
-	@SuppressWarnings("unchecked")
-	public T build() {
-		try {
-			return (T) implClass.getConstructor(HttpResourceBuilder.class).newInstance(this);
-		} catch (Exception e) {
-			throw asRuntimeException(e);
-		}
-	}
-
-	BasicHttpEntity entity() {
-		if (entityBuilder != null)
-			return entityBuilder.build();
-		if (entity == null)
-			return BasicHttpEntity.EMPTY;
-		return entity;
-	}
-
-	/**
-	 * Copies the contents of the specified HTTP response to this builder.
-	 *
-	 * @param response The response to copy from.  Must not be null.
-	 * @return This object.
-	 * @throws IOException If content could not be retrieved.
-	 */
-	public HttpResourceBuilder<?> copyFrom(HttpResponse response) throws IOException {
-		headers(response.getAllHeaders());
-		content(response.getEntity().getContent());
-		return this;
-	}
-
-	//-----------------------------------------------------------------------------------------------------------------
-	// HttpEntityBuilder setters.
-	//-----------------------------------------------------------------------------------------------------------------
-
-	/**
-	 * Returns access to the underlying builder for the HTTP entity.
-	 *
-	 * @return The underlying builder for the HTTP entity.
-	 */
-	public HttpEntityBuilder<?> getEntity() {
-		if (entityBuilder == null) {
-			entityBuilder = entity == null ? BasicHttpEntity.create(entityImplClass) : entity.copy();
-			entity = null;
-		}
-		return entityBuilder;
-	}
-
-	/**
-	 * Sets the content on this entity bean.
-	 *
-	 * @param value The entity content, can be <jk>null</jk>.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpResourceBuilder<T> content(Object value) {
-		getEntity().content(value);
-		return this;
-	}
-
-	/**
-	 * Sets the content on this entity bean from a supplier.
-	 *
-	 * <p>
-	 * Repeatable entities such as {@link StringEntity} use this to allow the entity content to be resolved at
-	 * serialization time.
-	 *
-	 * @param value The entity content, can be <jk>null</jk>.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpResourceBuilder<T> content(Supplier<?> value) {
-		getEntity().content(value);
-		return this;
-	}
-
-	/**
-	 * Sets the content type on this entity bean.
-	 *
-	 * @param value The new <c>Content-Type</c> header, or <jk>null</jk> to unset.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpResourceBuilder<T> contentType(String value) {
-		getEntity().contentType(value);
-		return this;
-	}
-
-	/**
-	 * Sets the content type on this entity bean.
-	 *
-	 * @param value The new <c>Content-Type</c> header, or <jk>null</jk> to unset.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpResourceBuilder<T> contentType(ContentType value) {
-		getEntity().contentType(value);
-		return this;
-	}
-
-	/**
-	 * Sets the content length on this entity bean.
-	 *
-	 * @param value The new <c>Content-Length</c> header value, or <c>-1</c> to unset.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpResourceBuilder<T> contentLength(long value) {
-		getEntity().contentLength(value);
-		return this;
-	}
-
-	/**
-	 * Sets the content encoding header on this entity bean.
-	 *
-	 * @param value The new <c>Content-Encoding</c> header, or <jk>null</jk> to unset.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpResourceBuilder<T> contentEncoding(String value) {
-		getEntity().contentEncoding(value);
-		return this;
-	}
-
-	/**
-	 * Sets the content encoding header on this entity bean.
-	 *
-	 * @param value The new <c>Content-Encoding</c> header, or <jk>null</jk> to unset.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpResourceBuilder<T> contentEncoding(ContentEncoding value) {
-		getEntity().contentEncoding(value);
-		return this;
-	}
-
-	/**
-	 * Sets the 'chunked' flag value to <jk>true</jk>.
-	 *
-	 * <ul class='notes'>
-	 * 	<li>If the {@link HttpEntity#getContentLength()} method returns a negative value, the HttpClient code will always
-	 * 		use chunked encoding.
-	 * </ul>
-	 *
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpResourceBuilder<T> chunked() {
-		getEntity().chunked();
-		return this;
-	}
-
-	/**
-	 * Sets the 'chunked' flag value.
-	 *
-	 * <ul class='notes'>
-	 * 	<li class='note'>If the {@link HttpEntity#getContentLength()} method returns a negative value, the HttpClient code will always
-	 * 		use chunked encoding.
-	 * </ul>
-	 *
-	 * @param value The new value for this flag.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpResourceBuilder<T> chunked(boolean value) {
-		getEntity().chunked(value);
-		return this;
-	}
-
-	/**
-	 * 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.
-	 * @throws IOException If entity could not be read into memory.
-	 */
-	@FluentSetter
-	public HttpResourceBuilder<T> cached() throws IOException {
-		getEntity().cached();
-		return this;
-	}
-
-	//-----------------------------------------------------------------------------------------------------------------
-	// BasicHeaderGroup setters.
-	//-----------------------------------------------------------------------------------------------------------------
-
-	/**
-	 * Returns access to the underlying builder for the headers.
-	 *
-	 * @return The underlying builder for the headers.
-	 */
-	public HeaderList getHeaders() {
-		return headers;
-	}
-
-	/**
-	 * Sets the specified headers in this builder.
-	 *
-	 * @param value The new value.
-	 * @return This object.
-	 */
-	@FluentSetter
-	public HttpResourceBuilder<T> headers(HeaderList value) {
-		headers = value;
-		return this;
-	}
-
-	/**
-	 * Adds the specified header to the end of the headers in this builder.
-	 *
-	 * @param value The header to add.  <jk>null</jk> values are ignored.
-	 * @return This object.
-	 */
-	public HttpResourceBuilder<T> header(Header value) {
-		if (value != null)
-			headers.append(value);
-		return this;
-	}
-
-	/**
-	 * Adds the specified header to the end of the headers in this builder.
-	 *
-	 * <p>
-	 * This is a no-op if either the name or value is <jk>null</jk>.
-	 *
-	 * @param name The header name.
-	 * @param value The header value.
-	 * @return This object.
-	 */
-	public HttpResourceBuilder<T> header(String name, String value) {
-		if (name != null && value != null)
-			headers.append(name, value);
-		return this;
-	}
-
-	/**
-	 * Adds the specified headers to the end of the headers in this builder.
-	 *
-	 * @param values The headers to add.  <jk>null</jk> headers and headers with <jk>null</jk> names or values are ignored.
-	 * @return This object.
-	 */
-	public HttpResourceBuilder<T> headers(Header...values) {
-		for (Header h : values) {
-			if (h != null) {
-				String n = h.getName();
-				String v = h.getValue();
-				if (isNotEmpty(n)) {
-					if (n.equalsIgnoreCase("content-type"))
-						contentType(v);
-					else if (n.equalsIgnoreCase("content-encoding"))
-						contentEncoding(v);
-					else if (n.equalsIgnoreCase("content-length"))
-						contentLength(Long.parseLong(v));
-					else
-						headers.append(h);
-				}
-			}
-		}
-		return this;
-	}
-
-	/**
-	 * Adds the specified headers to the end of the headers in this builder.
-	 *
-	 * @param values The headers to add.  <jk>null</jk> values are ignored.
-	 * @return This object.
-	 */
-	public HttpResourceBuilder<T> headers(List<Header> values) {
-		headers.append(values);
-		return this;
-	}
-
-	//-----------------------------------------------------------------------------------------------------------------
-	// Other methods
-	//-----------------------------------------------------------------------------------------------------------------
-
-	// <FluentSetters>
-
-	// </FluentSetters>
-}
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/ReaderResource.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/ReaderResource.java
index 6499663f2..72856b134 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/ReaderResource.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/ReaderResource.java
@@ -14,6 +14,7 @@ package org.apache.juneau.http.resource;
 
 import java.io.*;
 import org.apache.juneau.http.entity.*;
+import org.apache.juneau.http.header.*;
 
 /**
  * A streamed, non-repeatable resource that obtains its content from an {@link Reader}.
@@ -25,31 +26,38 @@ import org.apache.juneau.http.entity.*;
  */
 public class ReaderResource extends BasicResource {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
-	 * Creates a new {@link ReaderResource} builder.
-	 *
-	 * @return A new {@link ReaderResource} builder.
+	 * Constructor.
 	 */
-	public static HttpResourceBuilder<ReaderResource> create() {
-		return new HttpResourceBuilder<>(ReaderResource.class, ReaderEntity.class);
+	public ReaderResource() {
+		super(new ReaderEntity());
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The resource builder.
+	 * @param contentType The entity content type.
+	 * @param contents The entity contents.
 	 */
-	public ReaderResource(HttpResourceBuilder<?> builder) {
-		super(builder);
+	public ReaderResource(ContentType contentType, Reader contents) {
+		super(new ReaderEntity(contentType, contents));
 	}
 
 	/**
-	 * Creates a new {@link ReaderResource} builder initialized with the contents of this entity.
+	 * Copy constructor.
 	 *
-	 * @return A new {@link ReaderResource} builder initialized with the contents of this entity.
+	 * @param copyFrom The bean being copied.
 	 */
-	@Override /* BasicResource */
-	public HttpResourceBuilder<ReaderResource> copy() {
-		return new HttpResourceBuilder<>(this);
+	protected ReaderResource(ReaderResource copyFrom) {
+		super(copyFrom);
+	}
+
+	@Override
+	public ReaderResource copy() {
+		return new ReaderResource(this);
 	}
 }
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/StreamResource.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/StreamResource.java
index 569894a89..56a2ef441 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/StreamResource.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/StreamResource.java
@@ -14,6 +14,7 @@ package org.apache.juneau.http.resource;
 
 import java.io.*;
 import org.apache.juneau.http.entity.*;
+import org.apache.juneau.http.header.*;
 
 /**
  * A streamed, non-repeatable resource that obtains its content from an {@link InputStream}.
@@ -25,31 +26,38 @@ import org.apache.juneau.http.entity.*;
  */
 public class StreamResource extends BasicResource {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
-	 * Creates a new {@link StreamResource} builder.
-	 *
-	 * @return A new {@link StreamResource} builder.
+	 * Constructor.
 	 */
-	public static HttpResourceBuilder<StreamResource> create() {
-		return new HttpResourceBuilder<>(StreamResource.class, StreamEntity.class);
+	public StreamResource() {
+		super(new StreamEntity());
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The resource builder.
+	 * @param contentType The entity content type.
+	 * @param contents The entity contents.
 	 */
-	public StreamResource(HttpResourceBuilder<?> builder) {
-		super(builder);
+	public StreamResource(ContentType contentType, InputStream contents) {
+		super(new StreamEntity(contentType, contents));
 	}
 
 	/**
-	 * Creates a new {@link StreamResource} builder initialized with the contents of this entity.
+	 * Copy constructor.
 	 *
-	 * @return A new {@link StreamResource} builder initialized with the contents of this entity.
+	 * @param copyFrom The bean being copied.
 	 */
-	@Override /* BasicResource */
-	public HttpResourceBuilder<StreamResource> copy() {
-		return new HttpResourceBuilder<>(this);
+	protected StreamResource(StreamResource copyFrom) {
+		super(copyFrom);
+	}
+
+	@Override
+	public StreamResource copy() {
+		return new StreamResource(this);
 	}
 }
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/StringResource.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/StringResource.java
index 582df4757..ab05e9a7e 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/StringResource.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/resource/StringResource.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.http.resource;
 
 import org.apache.juneau.http.entity.*;
+import org.apache.juneau.http.header.*;
 
 /**
  * A self contained, repeatable resource that obtains its content from a {@link String}.
@@ -24,32 +25,39 @@ import org.apache.juneau.http.entity.*;
  */
 public class StringResource extends BasicResource {
 
+	//-----------------------------------------------------------------------------------------------------------------
+	// Instance
+	//-----------------------------------------------------------------------------------------------------------------
+
 	/**
-	 * Creates a new {@link StringResource} builder.
-	 *
-	 * @return A new {@link StringResource} builder.
+	 * Constructor.
 	 */
-	public static HttpResourceBuilder<StringResource> create() {
-		return new HttpResourceBuilder<>(StringResource.class, StringEntity.class);
+	public StringResource() {
+		super(new StringEntity());
 	}
 
 	/**
 	 * Constructor.
 	 *
-	 * @param builder The resource builder.
+	 * @param contentType The entity content type.
+	 * @param contents The entity contents.
 	 */
-	public StringResource(HttpResourceBuilder<?> builder) {
-		super(builder);
+	public StringResource(ContentType contentType, String contents) {
+		super(new StringEntity(contentType, contents));
 	}
 
 	/**
-	 * Creates a new {@link StringResource} builder initialized with the contents of this entity.
+	 * Copy constructor.
 	 *
-	 * @return A new {@link StringResource} builder initialized with the contents of this entity.
+	 * @param copyFrom The bean being copied.
 	 */
-	@Override /* BasicResource */
-	public HttpResourceBuilder<StringResource> copy() {
-		return new HttpResourceBuilder<>(this);
+	protected StringResource(StringResource copyFrom) {
+		super(copyFrom);
+	}
+
+	@Override
+	public StringResource copy() {
+		return new StringResource(this);
 	}
 }
 
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/response/BasicHttpException.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/response/BasicHttpException.java
index 758b168a0..6b7413a49 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/response/BasicHttpException.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/response/BasicHttpException.java
@@ -331,7 +331,7 @@ public class BasicHttpException extends BasicRuntimeException implements HttpRes
 	 * @return This object.
 	 */
 	public BasicHttpException setContent(String value) {
-		setContent(stringEntity(value).build());
+		setContent(stringEntity(value));
 		return this;
 	}
 
@@ -563,7 +563,7 @@ public class BasicHttpException extends BasicRuntimeException implements HttpRes
 	public HttpEntity getEntity() {
 		// Constructing a StringEntity is somewhat expensive, so don't create it unless it's needed.
 		if (content == null)
-			content = stringEntity(getMessage()).build();
+			content = stringEntity(getMessage());
 		return content;
 	}
 
diff --git a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/response/BasicHttpResponse.java b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/response/BasicHttpResponse.java
index d729aa4ab..96d739099 100644
--- a/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/response/BasicHttpResponse.java
+++ b/juneau-rest/juneau-rest-common/src/main/java/org/apache/juneau/http/response/BasicHttpResponse.java
@@ -334,7 +334,7 @@ public class BasicHttpResponse implements HttpResponse {
 	 */
 	@FluentSetter
 	public BasicHttpResponse setContent(String value) {
-		return setContent(stringEntity(value).build());
+		return setContent(stringEntity(value));
 	}
 
 	/**
@@ -491,7 +491,7 @@ public class BasicHttpResponse implements HttpResponse {
 	public HttpEntity getEntity() {
 		// Constructing a StringEntity is somewhat expensive, so don't create it unless it's needed.
 		if (content == null)
-			content = stringEntity(getStatusLine().getReasonPhrase()).build();
+			content = stringEntity(getStatusLine().getReasonPhrase());
 		return content;
 	}
 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java
index fad514712..098c788df 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/staticfile/BasicStaticFiles.java
@@ -123,9 +123,8 @@ public class BasicStaticFiles implements StaticFiles {
 				return empty();
 			return optional(
 				streamResource(is.get())
-					.header(contentType(mimeTypes == null ? null : mimeTypes.getContentType(getFileName(path))))
-					.headers(headers)
-					.build()
+					.setHeaders(contentType(mimeTypes == null ? null : mimeTypes.getContentType(getFileName(path))))
+					.addHeaders(headers)
 			);
 		} catch (IOException e) {
 			throw new InternalServerError(e);
diff --git a/juneau-utest/src/test/java/org/apache/juneau/http/BasicHttpResource_Test.java b/juneau-utest/src/test/java/org/apache/juneau/http/BasicHttpResource_Test.java
index 8501333d0..c84e5e1ff 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/http/BasicHttpResource_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/http/BasicHttpResource_Test.java
@@ -15,7 +15,6 @@ package org.apache.juneau.http;
 import static org.apache.juneau.assertions.Assertions.*;
 import static org.apache.juneau.http.HttpHeaders.*;
 import static org.apache.juneau.http.HttpResources.*;
-import static org.apache.juneau.internal.CollectionUtils.*;
 import static org.junit.Assert.*;
 import static org.junit.runners.MethodSorters.*;
 import static org.apache.juneau.testutils.StreamUtils.*;
@@ -32,92 +31,87 @@ public class BasicHttpResource_Test {
 	public void a01_basic() throws Exception {
 		File f = File.createTempFile("test", "txt");
 
-		HttpResource x = stringResource((String)null).build();
+		HttpResource x = stringResource((String)null);
 
 		assertNull(x.getContentType());
 		assertBytes(x.getContent()).isNotNull().asString().isEmpty();
 		assertNull(x.getContentEncoding());
 		assertInteger(x.getHeaders().size()).is(0);
 
-		x = stringResource("foo").build();
+		x = stringResource("foo");
 		assertBytes(x.getContent()).asString().is("foo");
 		assertTrue(x.isRepeatable());
 		assertFalse(x.isStreaming());
 
-		x = readerResource(reader("foo")).build();
+		x = readerResource(reader("foo"));
 		assertBytes(x.getContent()).asString().is("foo");
 		assertFalse(x.isRepeatable());
 		assertTrue(x.isStreaming());
 
-		x = byteArrayResource("foo".getBytes()).build();
+		x = byteArrayResource("foo".getBytes());
 		assertBytes(x.getContent()).asString().is("foo");
 		assertTrue(x.isRepeatable());
 		assertFalse(x.isStreaming());
 
-		x = streamResource(inputStream("foo")).build();
+		x = streamResource(inputStream("foo"));
 		assertBytes(x.getContent()).asString().is("foo");
 		assertFalse(x.isRepeatable());
 		assertTrue(x.isStreaming());
 
-		x = streamResource(null).build();
-		assertBytes(x.getContent()).isNotNull().asString().isEmpty();
-		assertFalse(x.isRepeatable());
-		assertTrue(x.isStreaming());
-
-		x = fileResource(f).build();
+		x = fileResource(f);
 		assertBytes(x.getContent()).asString().isEmpty();
 		assertTrue(x.isRepeatable());
 		assertFalse(x.isStreaming());
 
-		x = stringResource("foo").cached().build();
+		x = stringResource("foo").setCached();
 		assertBytes(x.getContent()).asString().is("foo");
 		assertBytes(x.getContent()).asString().is("foo");
 		assertTrue(x.isRepeatable());
 
-		x = readerResource(reader("foo")).cached().build();
+		x = readerResource(reader("foo")).setCached();
 		assertBytes(x.getContent()).asString().is("foo");
 		assertBytes(x.getContent()).asString().is("foo");
 		assertTrue(x.isRepeatable());
 
-		x = byteArrayResource("foo".getBytes()).cached().build();
+		x = byteArrayResource("foo".getBytes()).setCached();
 		assertBytes(x.getContent()).asString().is("foo");
 		assertBytes(x.getContent()).asString().is("foo");
 		assertTrue(x.isRepeatable());
 
-		x = streamResource(inputStream("foo")).cached().build();
+		x = streamResource(inputStream("foo")).setCached();
 		assertBytes(x.getContent()).asString().is("foo");
 		assertBytes(x.getContent()).asString().is("foo");
 		assertTrue(x.isRepeatable());
 
-		x = stringResource((String)null).cached().build();
+		x = stringResource((String)null).setCached();
 		assertBytes(x.getContent()).isExists().asString().isEmpty();
 		assertTrue(x.isRepeatable());
 		x.writeTo(new ByteArrayOutputStream());
 
-		x = fileResource(f).cached().build();
+		x = fileResource(f).setCached();
 		assertBytes(x.getContent()).asString().isEmpty();
 		assertTrue(x.isRepeatable());
 		x.writeTo(new ByteArrayOutputStream());
 
-		assertLong(stringResource("foo").build().getContentLength()).is(3l);
-		assertLong(byteArrayResource("foo".getBytes()).build().getContentLength()).is(3l);
-		assertLong(fileResource(f).build().getContentLength()).is(0l);
+		assertLong(stringResource("foo").getContentLength()).is(3l);
+		assertLong(byteArrayResource("foo".getBytes()).getContentLength()).is(3l);
+		assertLong(fileResource(f).getContentLength()).is(0l);
 
-		assertLong(readerResource(reader("foo")).build().getContentLength()).is(-1l);
-		assertLong(readerResource(reader("foo")).contentLength(3).build().getContentLength()).is(3l);
+		assertLong(readerResource(reader("foo")).getContentLength()).is(-1l);
+		assertLong(readerResource(reader("foo")).setContentLength(3).getContentLength()).is(3l);
 
-		x = stringResource("foo", contentType("text/plain")).contentEncoding("identity").build();
+		x = stringResource("foo", contentType("text/plain")).setContentEncoding("identity");
 		assertString(x.getContentType().getValue()).is("text/plain");
 		assertString(x.getContentEncoding().getValue()).is("identity");
 
-		x = stringResource("foo", null).contentEncoding((String)null).build();
+		x = stringResource("foo", null).setContentEncoding((String)null);
 		assertObject(x.getContentType()).isNull();
 		assertObject(x.getContentEncoding()).isNull();
 	}
 
 	@Test
 	public void a02_header_String_Object() throws Exception {
-		HeaderList x = stringResource("foo").header("Foo","bar").header("Foo","baz").header(null,"bar").header("foo",null).build().getHeaders();
+		HeaderList x = stringResource("foo").addHeader("Foo","bar").addHeader("Foo","baz").addHeader(null,"bar").addHeader("foo",null).getHeaders();
 		assertString(x.getFirst("Foo").get().toString()).is("Foo: bar");
 		assertString(x.getLast("Foo").get().toString()).is("Foo: baz");
 		assertOptional(x.getFirst("Bar")).isNull();
@@ -127,7 +121,7 @@ public class BasicHttpResource_Test {
 
 	@Test
 	public void a03_header_Header() throws Exception {
-		HeaderList x = stringResource("foo").header(null).header(header("Foo","bar")).header(header("Foo","baz")).header(header("Bar",null)).header(null).build().getHeaders();
+		HeaderList x = stringResource("foo").addHeaders(header("Foo","bar")).addHeaders(header("Foo","baz")).addHeaders(header("Bar",null)).getHeaders();
 		assertString(x.getFirst("Foo").get().toString()).is("Foo: bar");
 		assertString(x.getLast("Foo").get().toString()).is("Foo: baz");
 		assertObject(x.getFirst("Bar").get().getValue()).isNull();
@@ -137,7 +131,7 @@ public class BasicHttpResource_Test {
 
 	@Test
 	public void a04_headers_List() throws Exception {
-		HeaderList x = stringResource("foo").headers(alist(header("Foo","bar"),header("Foo","baz"),header("Bar",null),null)).build().getHeaders();
+		HeaderList x = stringResource("foo").addHeaders(header("Foo","bar"),header("Foo","baz"),header("Bar",null),null).getHeaders();
 		assertString(x.getFirst("Foo").get().toString()).is("Foo: bar");
 		assertString(x.getLast("Foo").get().toString()).is("Foo: baz");
 		assertObject(x.getFirst("Bar").get().getValue()).isNull();
@@ -147,7 +141,7 @@ public class BasicHttpResource_Test {
 
 	@Test
 	public void a05_headers_array() throws Exception {
-		HeaderList x = stringResource("foo").headers(header("Foo","bar"),header("Foo","baz"),header("Bar",null),null).build().getHeaders();
+		HeaderList x = stringResource("foo").addHeaders(header("Foo","bar"),header("Foo","baz"),header("Bar",null),null).getHeaders();
 		assertString(x.getFirst("Foo").get().toString()).is("Foo: bar");
 		assertString(x.getLast("Foo").get().toString()).is("Foo: baz");
 		assertObject(x.getFirst("Bar").get().getValue()).isNull();
@@ -158,33 +152,33 @@ public class BasicHttpResource_Test {
 
 	@Test
 	public void a06_chunked() throws Exception {
-		StringResource x1 = stringResource("foo").chunked().build();
+		StringResource x1 = (StringResource) stringResource("foo").setChunked();
 		assertBoolean(x1.isChunked()).isTrue();
-		StringResource x2 = stringResource("foo").build();
+		StringResource x2 = stringResource("foo");
 		assertBoolean(x2.isChunked()).isFalse();
 	}
 
 	@Test
 	public void a07_chunked_boolean() throws Exception {
-		StringResource x1 = stringResource("foo").chunked(true).build();
+		StringResource x1 = (StringResource) stringResource("foo").setChunked(true);
 		assertBoolean(x1.isChunked()).isTrue();
-		StringResource x2 = stringResource("foo").chunked(false).build();
+		StringResource x2 = (StringResource) stringResource("foo").setChunked(false);
 		assertBoolean(x2.isChunked()).isFalse();
 	}
 
 	@Test
 	public void a08_contentType_String() throws Exception {
-		StringResource x1 = stringResource("foo").contentType("text/plain").build();
+		StringResource x1 = (StringResource) stringResource("foo").setContentType("text/plain");
 		assertString(x1.getContentType().getValue()).is("text/plain");
-		StringResource x2 = stringResource("foo").contentType((String)null).build();
+		StringResource x2 = (StringResource) stringResource("foo").setContentType((String)null);
 		assertObject(x2.getContentType()).isNull();
 	}
 
 	@Test
 	public void a09_contentEncoding_String() throws Exception {
-		StringResource x1 = stringResource("foo").contentEncoding("identity").build();
+		StringResource x1 = (StringResource) stringResource("foo").setContentEncoding("identity");
 		assertString(x1.getContentEncoding().getValue()).is("identity");
-		StringResource x2 = stringResource("foo").contentEncoding((String)null).build();
+		StringResource x2 = (StringResource) stringResource("foo").setContentEncoding((String)null);
 		assertObject(x2.getContentEncoding()).isNull();
 	}
 
diff --git a/juneau-utest/src/test/java/org/apache/juneau/http/SerializedHttpEntity_Test.java b/juneau-utest/src/test/java/org/apache/juneau/http/SerializedHttpEntity_Test.java
index 9f5f39588..c24b0576c 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/http/SerializedHttpEntity_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/http/SerializedHttpEntity_Test.java
@@ -51,62 +51,62 @@ public class SerializedHttpEntity_Test {
 
 	@Test
 	public void a01_basic() throws Exception {
-		serializedEntity(ABean.get(),JsonSerializer.DEFAULT).build().assertString().is("{\"a\":1,\"b\":\"foo\"}");
-		serializedEntity(()->ABean.get(),JsonSerializer.DEFAULT).build().assertString().is("{\"a\":1,\"b\":\"foo\"}");
-		serializedEntity(ABean.get(),null).build().assertString().is("{a:1,b:'foo'}");
-		serializedEntity(null,JsonSerializer.DEFAULT).build().assertString().is("null");
+		serializedEntity(ABean.get(),JsonSerializer.DEFAULT).assertString().is("{\"a\":1,\"b\":\"foo\"}");
+		serializedEntity(()->ABean.get(),JsonSerializer.DEFAULT).assertString().is("{\"a\":1,\"b\":\"foo\"}");
+		serializedEntity(ABean.get(),null).assertString().is("{a:1,b:'foo'}");
+		serializedEntity(null,JsonSerializer.DEFAULT).assertString().is("null");
 	}
 
 	@Test
 	public void a02_schema() throws Exception {
-		serializedEntity(alist("foo","bar"),OpenApiSerializer.DEFAULT).schema(T_ARRAY_PIPES).build().assertString().is("foo|bar");
+		serializedEntity(alist("foo","bar"),OpenApiSerializer.DEFAULT).setSchema(T_ARRAY_PIPES).assertString().is("foo|bar");
 	}
 
 	@Test
 	public void a03_serializer_streaming() throws Exception {
-		serializedEntity(ABean.get(),MsgPackSerializer.DEFAULT).build().assertBytes().asSpacedHex().is("82 A1 61 01 A1 62 A3 66 6F 6F");
+		serializedEntity(ABean.get(),MsgPackSerializer.DEFAULT).assertBytes().asSpacedHex().is("82 A1 61 01 A1 62 A3 66 6F 6F");
 	}
 
 	@Test
 	public void a04_serializer_bad() throws Exception {
-		assertThrown(()->serializedEntity(null,OpenApiSerializer.DEFAULT).schema(schema().required().build()).build().asString()).asMessages().isContains("Required value not provided.");
+		assertThrown(()->serializedEntity(null,OpenApiSerializer.DEFAULT).setSchema(schema().required().build()).asString()).asMessages().isContains("Required value not provided.");
 	}
 
 	@Test
 	public void a05_writeTo() throws Exception {
 		ByteArrayOutputStream baos = new ByteArrayOutputStream();
-		serializedEntity("foo", null).build().writeTo(baos);
+		serializedEntity("foo", null).writeTo(baos);
 		assertBytes(baos.toByteArray()).asString().is("foo");
 	}
 
 	@Test
 	public void a06_isRepeatable() throws Exception {
-		assertBoolean(serializedEntity(ABean.get(),null).build().isRepeatable()).isTrue();
+		assertBoolean(serializedEntity(ABean.get(),null).isRepeatable()).isTrue();
 	}
 
 	@Test
 	public void a07_getContentLength() throws Exception {
-		assertLong(serializedEntity(ABean.get(),null).build().getContentLength()).is(-1l);
+		assertLong(serializedEntity(ABean.get(),null).getContentLength()).is(-1l);
 	}
 
 	@Test
 	public void a08_getContent() throws Exception {
-		assertBytes(serializedEntity("foo",null).build().getContent()).asString().is("foo");
+		assertBytes(serializedEntity("foo",null).getContent()).asString().is("foo");
 	}
 
 	@Test
 	public void a09_chunked() throws Exception {
-		checkHeaderClient("Transfer-Encoding").post("/",serializedEntity(ABean.get(),null).chunked().build()).run().assertContent("['chunked']");
+		checkHeaderClient("Transfer-Encoding").post("/",serializedEntity(ABean.get(),null).setChunked()).run().assertContent("['chunked']");
 	}
 
 	@Test
 	public void a10_contentEncoding() throws Exception {
-		checkHeaderClient("Content-Encoding").post("/",serializedEntity(ABean.get(),null).contentEncoding("identity").build()).run().assertContent("['identity']");
+		checkHeaderClient("Content-Encoding").post("/",serializedEntity(ABean.get(),null).setContentEncoding("identity")).run().assertContent("['identity']");
 	}
 
 	@Test
 	public void a12_contentType() throws Exception {
-		checkHeaderClient("Content-Type").post("/",serializedEntity(reader("foo"),null).contentType("text/foo").build()).run().assertContent("['text/foo']");
+		checkHeaderClient("Content-Type").post("/",serializedEntity(reader("foo"),null).setContentType("text/foo")).run().assertContent("['text/foo']");
 	}
 
 	//------------------------------------------------------------------------------------------------------------------
diff --git a/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_CommonInterfaces_Test.java b/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_CommonInterfaces_Test.java
index 82b2c2c54..08644bef6 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_CommonInterfaces_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/http/remote/Remote_CommonInterfaces_Test.java
@@ -205,7 +205,7 @@ public class Remote_CommonInterfaces_Test {
 	public static class D1 implements D {
 		@Override
 		public BasicResource httpResource() throws IOException {
-			return byteArrayResource("foo".getBytes()).contentType("text/foo").header("Foo","foo").headers(eTag("\"bar\"")).build();
+			return byteArrayResource("foo".getBytes()).setContentType("text/foo").setHeader("Foo","foo").addHeaders(eTag("\"bar\""));
 		}
 	}
 
diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/RestOp_Returns_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/RestOp_Returns_Test.java
index 2b247e534..70d4df0c2 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/rest/RestOp_Returns_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/rest/RestOp_Returns_Test.java
@@ -19,6 +19,7 @@ import static org.junit.Assert.*;
 import static org.junit.runners.MethodSorters.*;
 import static org.apache.juneau.testutils.StreamUtils.*;
 
+import java.io.*;
 import java.util.*;
 
 import org.apache.juneau.dto.swagger.*;
@@ -124,27 +125,27 @@ public class RestOp_Returns_Test {
 	public static class B {
 		@RestGet
 		public HttpResource a() throws Exception {
-			return stringResource("foo").build();
+			return stringResource("foo");
 		}
 		@RestGet
 		public HttpResource b() throws Exception {
-			return readerResource(null).header("Foo", "Bar").build();
+			return readerResource(new StringReader("foo")).setHeader("Foo", "Bar");
 		}
 		@RestGet
 		public HttpResource c() throws Exception {
-			return readerResource(null).contentType("application/json").build();
+			return readerResource(new StringReader("foo")).setContentType("application/json");
 		}
 		@RestGet
 		public HttpResource d(RestRequest req) throws Exception {
-			return stringResource(()->req.getVarResolverSession().resolve("$RQ{foo}")).build();
+			return stringResource(()->req.getVarResolverSession().resolve("$RQ{foo}"));
 		}
 		@RestGet
 		public HttpResource e() throws Exception {
-			return streamResource(inputStream("foo")).build();
+			return streamResource(inputStream("foo"));
 		}
 		@RestGet
 		public HttpResource f() throws Exception {
-			return readerResource(reader("foo")).build();
+			return readerResource(reader("foo"));
 		}
 	}
 
diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_BasicCalls_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_BasicCalls_Test.java
index 03244e337..775bf8e6d 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_BasicCalls_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_BasicCalls_Test.java
@@ -169,9 +169,9 @@ public class RestClient_BasicCalls_Test {
 		List<Object> bodies = list(
 			reader("{f:1}"),
 			inputStream("{f:1}"),
-			stringResource("{f:1}").build(),
+			stringResource("{f:1}"),
 			bean,
-			stringEntity("{f:1}").build(),
+			stringEntity("{f:1}"),
 			parts("f","1")
 		);
 		for (Object body : bodies) {
@@ -212,9 +212,9 @@ public class RestClient_BasicCalls_Test {
 		List<Object> bodies = list(
 			reader("{f:1}"),
 			inputStream("{f:1}"),
-			stringResource("{f:1}").build(),
+			stringResource("{f:1}"),
 			bean,
-			stringEntity("{f:1}").build(),
+			stringEntity("{f:1}"),
 			parts("f","1")
 		);
 		for (Object body : bodies) {
@@ -315,13 +315,13 @@ public class RestClient_BasicCalls_Test {
 			/*[ 0]*/ bean,
 			/*[ 1]*/ parts("f","1"),
 			/*[ 2]*/ new NameValuePair[]{part("f","1")},
-			/*[ 3]*/ stringEntity("f=1", ContentType.APPLICATION_FORM_URLENCODED).build(),
-			/*[ 4]*/ stringEntity("f=1", null).build(),
+			/*[ 3]*/ stringEntity("f=1", ContentType.APPLICATION_FORM_URLENCODED),
+			/*[ 4]*/ stringEntity("f=1", null),
 			/*[ 5]*/ part("f","1"),
-			/*[ 6]*/ stringResource("f=1").build(),
-			/*[ 7]*/ stringResource("f=1").build(),
-			/*[ 8]*/ stringResource("f=1").contentType(APPLICATION_FORM_URLENCODED).build(),
-			/*[ 9]*/ stringResource("f=1").contentType(APPLICATION_FORM_URLENCODED).build(),
+			/*[ 6]*/ stringResource("f=1"),
+			/*[ 7]*/ stringResource("f=1"),
+			/*[ 8]*/ stringResource("f=1").setContentType(APPLICATION_FORM_URLENCODED),
+			/*[ 9]*/ stringResource("f=1").setContentType(APPLICATION_FORM_URLENCODED),
 			/*[14]*/ s1,
 			/*[15]*/ s2
 		);
@@ -352,9 +352,9 @@ public class RestClient_BasicCalls_Test {
 		List<Object> bodies = list(
 			reader("{f:1}"),
 			inputStream("{f:1}"),
-			stringResource("{f:1}").build(),
+			stringResource("{f:1}"),
 			bean,
-			stringEntity("{f:1}").build(),
+			stringEntity("{f:1}"),
 			parts("f","1")
 		);
 		RestClient x = client().build();
@@ -389,9 +389,9 @@ public class RestClient_BasicCalls_Test {
 		List<Object> bodies = list(
 			reader("{f:1}"),
 			inputStream("{f:1}"),
-			stringResource("{f:1}").build(),
+			stringResource("{f:1}"),
 			bean,
-			stringEntity("{f:1}").build(),
+			stringEntity("{f:1}"),
 			parts("f","1")
 		);
 		RestClient x = client().build();
diff --git a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Body_Test.java b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Body_Test.java
index aaa7427a5..dfc0e2854 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Body_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/rest/client/RestClient_Body_Test.java
@@ -19,7 +19,6 @@ import static org.junit.runners.MethodSorters.*;
 import static org.apache.juneau.testutils.StreamUtils.*;
 
 import java.io.*;
-import java.util.*;
 
 import org.apache.http.*;
 import org.apache.juneau.http.entity.*;
@@ -52,7 +51,7 @@ public class RestClient_Body_Test {
 
 	@Test
 	public void a01_BasicHttpResource() throws Exception {
-		HttpResource x1 = stringResource("foo").build();
+		HttpResource x1 = stringResource("foo");
 		client().build().post("/", x1).run()
 			.assertHeader("X-Content-Length").asInteger().is(3)
 			.assertHeader("X-Content-Encoding").isNull()
@@ -60,7 +59,7 @@ public class RestClient_Body_Test {
 			.assertHeader("X-Transfer-Encoding").isNull()
 		;
 
-		HttpResource x2 = stringResource("foo").contentType("text/plain").contentEncoding("identity").build();
+		HttpResource x2 = stringResource("foo").setContentType("text/plain").setContentEncoding("identity");
 		client().build().post("/",x2).run()
 			.assertHeader("X-Content-Length").asInteger().is(3)
 			.assertHeader("X-Content-Encoding").is("identity")
@@ -68,7 +67,7 @@ public class RestClient_Body_Test {
 			.assertHeader("X-Transfer-Encoding").isNull()
 		;
 
-		HttpResource x3 = stringResource("foo").contentType(contentType("text/plain")).contentEncoding(contentEncoding("identity")).chunked().build();
+		HttpResource x3 = stringResource("foo").setContentType(contentType("text/plain")).setContentEncoding(contentEncoding("identity")).setChunked();
 		client().build().post("/",x3).run()
 			.assertHeader("X-Content-Length").isNull()  // Missing when chunked.
 			.assertHeader("X-Content-Encoding").is("identity")
@@ -76,7 +75,7 @@ public class RestClient_Body_Test {
 			.assertHeader("X-Transfer-Encoding").is("chunked")
 		;
 
-		HttpResource x4 = stringResource("foo", contentType("text/plain")).contentEncoding("identity").build();
+		HttpResource x4 = stringResource("foo", contentType("text/plain")).setContentEncoding("identity");
 		client().build().post("/",x4).run()
 			.assertHeader("X-Content-Length").asInteger().is(3)
 			.assertHeader("X-Content-Encoding").is("identity")
@@ -84,32 +83,29 @@ public class RestClient_Body_Test {
 			.assertHeader("X-Transfer-Encoding").isNull()
 		;
 
-		HttpResource x5 = stringResource("foo").header("Foo","bar").header(header("Baz","qux")).build();
+		HttpResource x5 = stringResource("foo").setHeader("Foo","bar").setHeaders(header("Baz","qux"));
 		client().build().post("/",x5).run()
 			.assertHeader("X-Foo").is("bar")
 			.assertHeader("X-Baz").is("qux")
 		;
 
-		HttpResource x6 = stringResource("foo").headers(Arrays.asList(header("Foo","bar"),header("Baz","qux"))).build();
+		HttpResource x6 = stringResource("foo").addHeaders(header("Foo","bar"),header("Baz","qux"));
 		client().build().post("/",x6).run()
 			.assertHeader("X-Foo").is("bar")
 			.assertHeader("X-Baz").is("qux")
 		;
 
-		HttpResource x7 = readerResource(reader("foo")).build();
+		HttpResource x7 = readerResource(reader("foo"));
 		client().build().post("/",x7).run().assertContent("foo");
 
-		HttpResource x8 = readerResource(reader("foo")).cached().build();
+		HttpResource x8 = readerResource(reader("foo")).setCached();
 		client().build().post("/",x8).run().assertContent("foo");
 		client().build().post("/",x8).run().assertContent("foo");
-
-		HttpResource x9 = readerResource(null).build();
-		client().build().post("/",x9).run().assertContent().isEmpty();
 	}
 
 	@Test
 	public void a02_StringEntity() throws Exception {
-		HttpEntity x1 = stringEntity("foo").build();
+		HttpEntity x1 = stringEntity("foo");
 		client().build().post("/", x1).run()
 			.assertHeader("X-Content-Length").asInteger().is(3)
 			.assertHeader("X-Content-Encoding").isNull()
@@ -117,7 +113,7 @@ public class RestClient_Body_Test {
 			.assertHeader("X-Transfer-Encoding").isNull()
 		;
 
-		HttpEntity x2 = stringEntity("foo").contentType("text/plain").contentEncoding("identity").build();
+		HttpEntity x2 = stringEntity("foo").setContentType("text/plain").setContentEncoding("identity");
 		client().build().post("/",x2).run()
 			.assertHeader("X-Content-Length").asInteger().is(3)
 			.assertHeader("X-Content-Encoding").is("identity")
@@ -125,7 +121,7 @@ public class RestClient_Body_Test {
 			.assertHeader("X-Transfer-Encoding").isNull()
 		;
 
-		HttpEntity x3 = stringEntity("foo").contentType(contentType("text/plain")).contentEncoding(contentEncoding("identity")).chunked().build();
+		HttpEntity x3 = stringEntity("foo").setContentType(contentType("text/plain")).setContentEncoding(contentEncoding("identity")).setChunked();
 		client().build().post("/",x3).run()
 			.assertHeader("X-Content-Length").isNull()  // Missing when chunked.
 			.assertHeader("X-Content-Encoding").is("identity")
@@ -133,7 +129,7 @@ public class RestClient_Body_Test {
 			.assertHeader("X-Transfer-Encoding").is("chunked")
 		;
 
-		HttpEntity x4 = stringEntity("foo", contentType("text/plain")).contentEncoding("identity").build();
+		HttpEntity x4 = stringEntity("foo", contentType("text/plain")).setContentEncoding("identity");
 		client().build().post("/",x4).run()
 			.assertHeader("X-Content-Length").asInteger().is(3)
 			.assertHeader("X-Content-Encoding").is("identity")
@@ -141,17 +137,14 @@ public class RestClient_Body_Test {
 			.assertHeader("X-Transfer-Encoding").isNull()
 		;
 
-		HttpEntity x7 = readerEntity(reader("foo")).build();
+		HttpEntity x7 = readerEntity(reader("foo"));
 		client().build().post("/",x7).run().assertContent("foo");
 
-		HttpEntity x8 = readerEntity(reader("foo")).cached().build();
+		HttpEntity x8 = readerEntity(reader("foo")).setCached();
 		client().build().post("/",x8).run().assertContent("foo");
 		client().build().post("/",x8).run().assertContent("foo");
 
-		HttpEntity x9 = readerEntity(null).build();
-		client().build().post("/",x9).run().assertContent().isEmpty();
-
-		BasicHttpEntity x12 = stringEntity("foo").build();
+		BasicHttpEntity x12 = stringEntity("foo");
 		x12.assertString().is("foo");
 		x12.assertBytes().asString().is("foo");
 	}
@@ -160,7 +153,7 @@ public class RestClient_Body_Test {
 	public void a03_SerializedHttpEntity() throws Exception {
 		Serializer js = JsonSerializer.DEFAULT;
 
-		SerializedEntity x1 = serializedEntity(ABean.get(),null,null).build();
+		SerializedEntity x1 = serializedEntity(ABean.get(),null,null);
 		client().build().post("/",x1).run()
 			.assertHeader("X-Content-Length").isNull()
 			.assertHeader("X-Content-Encoding").isNull()
@@ -168,14 +161,14 @@ public class RestClient_Body_Test {
 			.assertHeader("X-Transfer-Encoding").is("chunked")  // Because content length is -1.
 		;
 
-		SerializedEntity x2 = serializedEntity(ABean.get(),js,null).build();
+		SerializedEntity x2 = serializedEntity(ABean.get(),js,null);
 		client().build().post("/",x2).run()
 			.assertHeader("X-Content-Length").isNull()
 			.assertHeader("X-Content-Encoding").isNull()
 			.assertHeader("X-Content-Type").is("application/json")
 			.assertContent().as(ABean.class).asJson().is("{a:1,b:'foo'}");
 
-		SerializedEntity x3 = serializedEntity(()->ABean.get(),js,null).build();
+		SerializedEntity x3 = serializedEntity(()->ABean.get(),js,null);
 		client().build().post("/",x3).run()
 			.assertHeader("X-Content-Length").isNull()
 			.assertHeader("X-Content-Encoding").isNull()