juneau-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamesbog...@apache.org
Subject [juneau] branch master updated: Javadoc updates.
Date Thu, 01 Feb 2018 16:30:25 GMT
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 6df0514  Javadoc updates.
6df0514 is described below

commit 6df0514b3e47b622de55cdb10c8b211086b1a3b4
Author: JamesBognar <jamesbognar@apache.org>
AuthorDate: Thu Feb 1 11:30:23 2018 -0500

    Javadoc updates.
---
 .../java/org/apache/juneau/ini/ConfigFile.java     |  36 +-
 .../main/java/org/apache/juneau/BeanContext.java   |   6 +-
 .../main/java/org/apache/juneau/BeanSession.java   |   6 +-
 .../main/java/org/apache/juneau/parser/Parser.java |   6 +-
 .../org/apache/juneau/parser/ParserSession.java    |   6 +-
 juneau-doc/src/main/javadoc/overview.html          | 618 ++++++++++++++++-----
 .../juneau/rest/test/PropertiesResource.java       |   6 +-
 .../org/apache/juneau/rest/client/RestCall.java    |   6 +-
 .../org/apache/juneau/rest/ReaderResource.java     | 150 +----
 .../apache/juneau/rest/ReaderResourceBuilder.java  | 128 +++++
 .../main/java/org/apache/juneau/rest/Redirect.java |  52 +-
 .../java/org/apache/juneau/rest/RequestBody.java   |  59 +-
 .../org/apache/juneau/rest/RequestFormData.java    | 156 +++---
 .../org/apache/juneau/rest/RequestHeaders.java     |  87 +--
 .../org/apache/juneau/rest/RequestPathMatch.java   |  60 +-
 .../java/org/apache/juneau/rest/RequestQuery.java  | 178 +++---
 .../java/org/apache/juneau/rest/RestContext.java   |   2 +-
 .../java/org/apache/juneau/rest/RestRequest.java   |  35 +-
 .../java/org/apache/juneau/rest/RestResponse.java  | 127 ++++-
 .../org/apache/juneau/rest/StreamResource.java     | 139 +----
 .../apache/juneau/rest/StreamResourceBuilder.java  | 116 ++++
 .../juneau/rest/annotation/RestResource.java       |   2 +-
 .../juneau/rest/response/DefaultHandler.java       |   2 +-
 .../juneau/rest/response/StreamableHandler.java    |   5 +-
 .../juneau/rest/response/WritableHandler.java      |   5 +-
 25 files changed, 1240 insertions(+), 753 deletions(-)

diff --git a/juneau-core/juneau-config/src/main/java/org/apache/juneau/ini/ConfigFile.java b/juneau-core/juneau-config/src/main/java/org/apache/juneau/ini/ConfigFile.java
index 8544360..325744f 100644
--- a/juneau-core/juneau-config/src/main/java/org/apache/juneau/ini/ConfigFile.java
+++ b/juneau-core/juneau-config/src/main/java/org/apache/juneau/ini/ConfigFile.java
@@ -343,12 +343,10 @@ public abstract class ConfigFile implements Map<String,Section> {
 	 * @param key The key.  See {@link #getString(String)} for a description of the key.
 	 * @param type
 	 * 	The object type to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @throws ParseException If parser could not parse the value or if a parser is not registered with this config file.
 	 * @return The value, or <jk>null</jk> if the section or key does not exist.
@@ -366,12 +364,10 @@ public abstract class ConfigFile implements Map<String,Section> {
 	 * 	If <jk>null</jk>, then uses the predefined parser on the config file.
 	 * @param type
 	 * 	The object type to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @throws ParseException If parser could not parse the value or if a parser is not registered with this config file.
 	 * @return The value, or <jk>null</jk> if the section or key does not exist.
@@ -486,12 +482,10 @@ public abstract class ConfigFile implements Map<String,Section> {
 	 * @param def The default value if section or key does not exist.
 	 * @param type
 	 * 	The object type to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @throws ParseException If parser could not parse the value or if a parser is not registered with this config file.
 	 * @return The value, or <jk>null</jk> if the section or key does not exist.
@@ -511,12 +505,10 @@ public abstract class ConfigFile implements Map<String,Section> {
 	 * @param def The default value if section or key does not exist.
 	 * @param type
 	 * 	The object type to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @throws ParseException If parser could not parse the value or if a parser is not registered with this config file.
 	 * @return The value, or <jk>null</jk> if the section or key does not exist.
@@ -572,12 +564,10 @@ public abstract class ConfigFile implements Map<String,Section> {
 	 * @param sectionKey The section key.  Must not be <jk>null</jk>.
 	 * @param type
 	 * 	The object type to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @throws ParseException If parser could not parse the value or if a parser is not registered with this config file.
 	 * @return The value, or <jk>null</jk> if the section or key does not exist.
@@ -597,12 +587,10 @@ public abstract class ConfigFile implements Map<String,Section> {
 	 * 	If <jk>null</jk>, then uses the predefined parser on the config file.
 	 * @param type
 	 * 	The object type to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @throws ParseException If parser could not parse the value or if a parser is not registered with this config file.
 	 * @return The value, or <jk>null</jk> if the section or key does not exist.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index 52ef3d2..3b8e6f6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -2130,12 +2130,10 @@ public class BeanContext extends Context {
 	 * 
 	 * @param type
 	 * 	The class to resolve.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @return The resolved class meta.
 	 */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
index 2b63b07..114eeda 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanSession.java
@@ -917,12 +917,10 @@ public class BeanSession extends Session {
 	 * 
 	 * @param type
 	 * 	The class to resolve.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @return The class meta.
 	 */
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
index 2b7be72..250e11b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
@@ -656,12 +656,10 @@ public abstract class Parser extends BeanContext {
 	 * 	</ul>
 	 * @param type
 	 * 	The object type to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @return The parsed object.
 	 * @throws ParseException
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
index 405e628..70654a1 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
@@ -412,12 +412,10 @@ public abstract class ParserSession extends BeanSession {
 	 * 	</ul>
 	 * @param type
 	 * 	The object type to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @return The parsed object.
 	 * @throws ParseException
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index 355cb3f..b6c10ea 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -169,11 +169,12 @@
 				<li><p><a class='doclink' href='#juneau-rest-server.RequestHeaders'><i>RequestHeaders</i></a></p>
 				<li><p><a class='doclink' href='#juneau-rest-server.RequestQuery'><i>RequestQuery</i></a></p>
 				<li><p><a class='doclink' href='#juneau-rest-server.RequestFormData'><i>RequestFormData</i></a></p>
+				<li><p><a class='doclink' href='#juneau-rest-server.RestMethodPath'><i>@RestMethod.path()</i></a></p>
+				<li><p><a class='doclink' href='#juneau-rest-server.RequestPathMatch'><i>RequestPathMatch</i></a></p>
 				<li><p><a class='doclink' href='#juneau-rest-server.MethodReturnTypes'><i>Method Return Types</i></a></p>
 				<li><p><a class='doclink' href='#juneau-rest-server.ReaderResource'><i>ReaderResource</i></a></p>
 				<li><p><a class='doclink' href='#juneau-rest-server.StreamResource'><i>StreamResource</i></a></p>
-				<li><p><a class='doclink' href='#juneau-rest-server.RestMethodPath'><i>@RestMethod.path()</i></a></p>
-				<li><p><a class='doclink' href='#juneau-rest-server.RequestPathMatch'><i>RequestPathMatch</i></a></p>
+				<li><p><a class='doclink' href='#juneau-rest-server.Redirect'><i>Redirect</i></a></p>
 				<li><p><a class='doclink' href='#juneau-rest-server.RestMethodMatchers'><i>@RestMethod.matchers()</i></a></p>
 			</ol>
 			<li><p><a class='doclink' href='#juneau-rest-server.Body'><i>@Body</i></a></p>
@@ -200,7 +201,7 @@
 			<ol>
 				<li><p><a class='doclink' href='#juneau-rest-server.InfoProviders'><i>Info Providers</i></a></p>
 			</ol>
-			<li><p><a class='doclink' href='#juneau-rest-server.HtmlDocAnnotation'><i> @HtmlDoc</i></a></p>
+			<li><p><a class='doclink' href='#juneau-rest-server.HtmlDocAnnotation'><i>@HtmlDoc</i></a></p>
 			<ol>
 				<li><p><a class='doclink' href='#juneau-rest-server.Widgets'><i>Widgets</i></a></p>
 				<li><p><a class='doclink' href='#juneau-rest-server.UiCustomization'><i>UI Customization</i></a></p>
@@ -4914,28 +4915,6 @@
 				support RDF. 
 			</p>
 			<p>
-				The {@link org.apache.juneau.rest.RestRequest} and {@link org.apache.juneau.rest.RestResponse} classes 
-				described later also extend from their servlet equivalents:
-			</p> 
-			<ul class='doctree'>
-				<li class='jic'>
-					{@link javax.servlet.http.HttpServletRequest javax.servlet.http.HttpServletRequest}
-					<ul>
-						<li class='jc'>
-							{@link org.apache.juneau.rest.RestRequest} 
-							- Augmented with specialized REST methods.
-					</ul>
-				</li> 
-				<li class='jic'>
-					{@link javax.servlet.http.HttpServletResponse javax.servlet.http.HttpServletResponse}
-					<ul>
-						<li class='jc'>
-							{@link org.apache.juneau.rest.RestResponse} 
-							- Augmented with specialized REST methods.
-					</ul>
-				</li> 
-			</ul>
-			<p>
 				Everything is configured through the following classes which you will see a lot:
 			</p>
 			<ul>
@@ -4983,7 +4962,7 @@
 					<br>However, the class does provide a couple of convenience methods to be aware of:
 				</p>
 				<ul class='doctree'>
-					<li class='jac'>{@link org.apache.juneau.rest.RestServlet}
+					<li class='jac'><code>{@link org.apache.juneau.rest.RestServlet} <jk>extends</jk> HttpServlet</code>
 					<ul>
 						<li class='jf'>{@link org.apache.juneau.rest.RestServlet#log(Level,String,Object...) log(Level,String,Object...)}
 						<li class='jf'>{@link org.apache.juneau.rest.RestServlet#log(Level,Throwable,String,Object...) log(Level,Throwable,String,Object...)}
@@ -5304,7 +5283,11 @@
 		<a id="juneau-rest-server.RestResource"></a>
 		<h4 class='topic' onclick='toggle(this)'>3.1.4 - @RestResource</h4>
 		<div class='topic'>
-			TODO
+			<p>
+				The {@link org.apache.juneau.rest.annotation.RestResource @RestResource} annotation is the primary way of defining
+				and configuring REST resource classes.
+				<br>The functionality of the class itself is covered in detail in the topics below.
+			</p>
 
 			<!-- ======================================================================================================== -->
 			<a id="juneau-rest-server.AnnotationInheritance"></a>
@@ -5447,7 +5430,53 @@
 		<a id="juneau-rest-server.RestContext"></a>
 		<h4 class='topic' onclick='toggle(this)'>3.1.5 - RestContext</h4>
 		<div class='topic'>
-			TODO
+			<p>
+				The {@link org.apache.juneau.rest.RestContext} object is the workhorse class for all of the configuration
+				of a single REST resource class.
+				<br>It's by-far the most important class in the REST API.
+			</p>
+			<p>
+				Every class annotated with <l>@RestResource</l> ends up with an instance of this object.
+				<br>The object itself is read-only and unchangeable.
+				<br>It is populated through the following:
+			</p>
+			<ul>
+				<li class='ja'>{@link org.apache.juneau.rest.annotation.RestResource} - Settings copied from the annotation during servlet initialization.
+				<li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder} - Builder used during servlet initialization.
+			</ul>
+			<p>
+				The annotation should be self-explanatory at this point.
+				<br>The builder allows you to perform all of the same configuration as the annotation programmatically.
+			</p>
+			<p>
+				The {@link org.apache.juneau.rest.RestContextBuilder} class extends {@link org.apache.juneau.BeanContextBuilder}
+				allowing you to programmatically set any properties defined on that builder class.
+				<br>It also implements {@link javax.servlet.ServletConfig}
+			</p>
+			<p>
+				To access this object, simply pass it in as a constructor argument or in an INIT hook:
+			</p>
+			<p class='bcode'>
+	<jc>// Option #1 - Pass in through constructor.</jc>
+	<jk>public</jk> MyResource(RestContextBuilder builder) {
+			builder
+				.pojoSwaps(CalendarSwap.<jsf>RFC2822DTZ</jsf>.<jk>class</jk>)
+				.set(<jsf>PARSER_debug</jsf>, <jk>true</jk>);
+	}
+
+	<jc>// Option #2 - Use an INIT hook.</jc>
+	<ja>@RestHook</ja>(<jsf>INIT</jsf>)
+	<jk>public void</jk> init(RestContextBuilder builder) <jk>throws</jk> Exception {
+			builder
+				.pojoSwaps(CalendarSwap.<jsf>RFC2822DTZ</jsf>.<jk>class</jk>)
+				.set(<jsf>PARSER_debug</jsf>, <jk>true</jk>);
+	}
+			</p>
+			<p>
+				Warning:  This class is huge.
+				<br>Through it, you can configure bean/serializer/parser settings, define config files, children, 
+					resource finders, info providers, etc...
+			</p>
 		</div>
 		
 		<!-- ======================================================================================================== -->
@@ -5619,7 +5648,7 @@
 					There are many useful methods on this object, but the main ones are shown below:
 				</p>
 				<ul class='doctree'>
-					<li class='jc'>{@link org.apache.juneau.rest.RestRequest} 
+					<li class='jc'><code>{@link org.apache.juneau.rest.RestRequest} <jk>extends</jk> HttpServletRequest</code>
 					<ul>
 						<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getHeaders() getHeaders()}
 						<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getQuery() getQuery()}
@@ -5632,6 +5661,7 @@
 						<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getConfigFile() getConfigFile()}
 						<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getVarResolverSession() getVarResolverSession()}
 						<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMessageBundle() getMessageBundle()}
+						<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getProperties() getProperties()}
 						<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getClasspathReaderResource(String,boolean,MediaType) getClasspathReaderResource(String,boolean,MediaType)}
 					</ul>
 				</ul>
@@ -5641,47 +5671,353 @@
 			<a id="juneau-rest-server.RestResponse"></a>
 			<h4 class='topic' onclick='toggle(this)'>3.1.6.3 - RestResponse</h4>
 			<div class='topic'>
-				TODO
+				<p>
+					The {@link org.apache.juneau.rest.RestResponse} object is an extension of the <l>HttpServletResponse</l> class
+					with various built-in convenience methods for use in building REST interfaces.
+					<br>It can be accessed by passing it as a parameter on your REST Java method:
+				</p>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Object myMethod(RestResponse req) {...}			
+				</p>
+				<p>
+					The important methods on this class are shown below:
+				</p>
+				<ul class='doctree'>
+					<li class='jc'><code>{@link org.apache.juneau.rest.RestResponse} <jk>extends</jk> HttpServletResponse</code>
+					<ul>
+						<li class='jm'>{@link org.apache.juneau.rest.RestResponse#setOutput(Object) setOutput(Object)}
+						<li class='jm'>{@link org.apache.juneau.rest.RestResponse#getProperties() getProperties()}
+						<li class='jm'>{@link org.apache.juneau.rest.RestResponse#getHtmlDocBuilder() getHtmlDocBuilder()}
+						<li class='jm'>{@link org.apache.juneau.rest.RestResponse#getDirectWriter(String) getDirectWriter(String)}
+					</ul>
+				</ul>
 			</div>
 
 			<!-- ======================================================================================================== -->
 			<a id="juneau-rest-server.RequestBody"></a>
 			<h4 class='topic' onclick='toggle(this)'>3.1.6.4 - RequestBody</h4>
 			<div class='topic'>
-				TODO
+				<p>
+					The {@link org.apache.juneau.rest.RequestBody} object is the API for accessing the body of an HTTP request.
+					<br>It can be accessed by passing it as a parameter on your REST Java method:
+				</p>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Object myMethod(RequestBody body) {...}			
+				</p>
+				<h6 class='figure'>Example:</h6>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(...)
+	<jk>public void</jk> doPost(RequestBody body) {
+		<jc>// Convert body to a linked list of Person objects.</jc>
+		List&lt;Person&gt; l = body.asType(LinkedList.<jk>class</jk>, Person.<jk>class</jk>);
+		...
+	}
+				</p>
+				<p>
+					The important methods on this class are:
+				</p>
+				<ul class='doctree'>
+					<li class='jc'>{@link org.apache.juneau.rest.RequestBody} 
+					<ul>
+						<li class='jm'>{@link org.apache.juneau.rest.RequestBody#getReader() getReader()}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestBody#getInputStream() getInputStream()}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestBody#asType(Class) asType(Class)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestBody#asType(Type,Type...) asType(Type,Type...)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestBody#asString() asString()}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestBody#asHex() asHex()}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestBody#asSpacedHex() asSpacedHex()}
+					</ul>
+				</ul>
 			</div>
 
 			<!-- ======================================================================================================== -->
 			<a id="juneau-rest-server.RequestHeaders"></a>
 			<h4 class='topic' onclick='toggle(this)'>3.1.6.5 - RequestHeaders</h4>
 			<div class='topic'>
-				TODO
+				<p>
+					The {@link org.apache.juneau.rest.RequestHeaders} object is the API for accessing the headers of an HTTP request.
+					<br>It can be accessed by passing it as a parameter on your REST Java method:
+				</p>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Object myMethod(RequestHeaders headers) {...}			
+				</p>
+				<h6 class='figure'>Example:</h6>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Object myMethod(RequestHeaders headers) {
+
+		<jc>// Add a default value.</jc>
+		headers.addDefault(<js>"ETag"</js>, <jsf>DEFAULT_UUID</jsf>);
+	
+		<jc>// Get a header value as a POJO.</jc>
+		UUID etag = headers.get(<js>"ETag"</js>, UUID.<jk>class</jk>);
+	
+		<jc>// Get a standard header.</jc>
+		CacheControl = headers.getCacheControl();
+	 }			
+				</p>
+				<p>
+					The important methods on this class are:
+				</p>
+				<ul class='doctree'>
+					<li class='jc'><code>{@link org.apache.juneau.rest.RequestHeaders} <jk>extends</jk> TreeMap&lt;String,String[]&gt;</code>
+					<ul>
+						<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#get(String,Class) get(String,Class)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#get(String,Type,Type...) get(String,Type,Type)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#getString(String,String) getString(String,String)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#getInt(String,int) getInt(String,int)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#getBoolean(String,boolean) getBoolean(String,boolean)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestHeaders#addDefault(String,Object) addDefault(String,Object)}
+					</ul>
+				</ul>
 			</div>
 
 			<!-- ======================================================================================================== -->
 			<a id="juneau-rest-server.RequestQuery"></a>
 			<h4 class='topic' onclick='toggle(this)'>3.1.6.6 - RequestQuery</h4>
 			<div class='topic'>
-				TODO
+				<p>
+					The {@link org.apache.juneau.rest.RequestQuery} object is the API for accessing the GET query parameters of an HTTP request.
+					<br>It can be accessed by passing it as a parameter on your REST Java method:
+				</p>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Object myMethod(RequestQuery query) {...}			
+				</p>
+				<h6 class='figure'>Example:</h6>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Object myMethod(RequestQuery query) {
+
+		<jc>// Get query parameters converted to various types.</jc>
+		<jk>int</jk> p1 = query.get(<js>"p1"</js>, 0, <jk>int</jk>.<jk>class</jk>);
+		String p2 = query.get(<js>"p2"</js>, String.<jk>class</jk>);
+		UUID p3 = query.get(<js>"p3"</js>, UUID.<jk>class</jk>);
+	 }			
+				</p>
+				<p>
+					An important distinction between the behavior of this object and <l>HttpServletRequest.getParameter(String)</l> is
+					that the former will NOT load the body of the request on FORM POSTS and will only look at parameters
+					found in the query string.
+					<br>This can be useful in cases where you're mixing GET parameters and FORM POSTS and you don't want to 
+					inadvertantly read the body of the request to get a query parameter.
+				</p>
+				<p>
+					The important methods on this class are:
+				</p>
+				<ul class='doctree'>
+					<li class='jc'><code>{@link org.apache.juneau.rest.RequestQuery} <jk>extends</jk> LinkedHashMap&lt;String,String[]&gt;</code>
+					<ul>
+						<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#get(String,Class) get(String,Class)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#get(String,Type,Type...) get(String,Type,Type)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#getString(String,String) getString(String,String)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#getInt(String,int) getInt(String,int)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#getBoolean(String,boolean) getBoolean(String,boolean)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#addDefault(String,Object) addDefault(String,Object)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestQuery#getSearchArgs() getSearchArgs()}
+					</ul>
+				</ul>
 			</div>
 
 			<!-- ======================================================================================================== -->
 			<a id="juneau-rest-server.RequestFormData"></a>
 			<h4 class='topic' onclick='toggle(this)'>3.1.6.7 - RequestFormData</h4>
 			<div class='topic'>
-				TODO
+				<p>
+					The {@link org.apache.juneau.rest.RequestFormData} object is the API for accessing the HTTP request body as form data.
+					<br>It can be accessed by passing it as a parameter on your REST Java method:
+				</p>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Object myMethod(RequestFormData query) {...}			
+				</p>
+				<h6 class='figure'>Example:</h6>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Object myMethod(RequestFormData formData) {
+
+		<jc>// Get query parameters converted to various types.</jc>
+		<jk>int</jk> p1 = formData.get(<js>"p1"</js>, 0, <jk>int</jk>.<jk>class</jk>);
+		String p2 = formData.get(<js>"p2"</js>, String.<jk>class</jk>);
+		UUID p3 = formData.get(<js>"p3"</js>, UUID.<jk>class</jk>);
+	 }			
+				</p>
+				<p>
+					Note that this object does NOT take GET parameters into account and only returns values found in the body of the request.
+				</p>
+				<p>
+					The important methods on this class are:
+				</p>
+				<ul class='doctree'>
+					<li class='jc'><code>{@link org.apache.juneau.rest.RequestFormData} <jk>extends</jk> LinkedHashMap&lt;String,String[]&gt;</code>
+					<ul>
+						<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#get(String,Class) get(String,Class)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#get(String,Type,Type...) get(String,Type,Type)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#getString(String,String) getString(String,String)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#getInt(String,int) getInt(String,int)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#getBoolean(String,boolean) getBoolean(String,boolean)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestFormData#addDefault(String,Object) addDefault(String,Object)}
+					</ul>
+				</ul>
 			</div>
 
 			<!-- ======================================================================================================== -->
+			<a id="juneau-rest-server.RestMethodPath"></a>
+			<h4 class='topic' onclick='toggle(this)'>3.1.6.8 - @RestMethod.path()</h4>
+			<div class='topic'>
+				<p>
+					The {@link org.apache.juneau.rest.annotation.RestMethod#path() @RestMethod.path()} annotation allows 
+					you to define URL path patterns to match against.
+					<br>These patterns can contain variables of the form <l>"{xxx}"</l> that can be passed in directly to the
+					Java methods as extra parameters.
+				</p>
+				<p>
+					In the following example, 3 separate GET request handlers are defined with different path patterns.
+					<br>Note how the variables are passed in as additional arguments on the method, and how those arguments are 
+					automatically converted to the specified class type...
+				</p>
+				<p class='bcode'>
+	<jc>// Default method</jc>
+	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
+	<jk>public void</jk> doGetDefault() {
+		...
+	}
+
+	<jc>// Method with path pattern</jc>
+	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/xxx"</js>)
+	<jk>public void</jk> doGetNoArgs(...) {
+		...
+	}
+
+	<jc>// Method with path pattern with arguments</jc>
+	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/xxx/{foo}/{bar}/{baz}/{bing}"</js>)
+	<jk>public void</jk> doGetWithArgs(<ja>@Path</ja> String foo, <ja>@Path</ja> <jk>int</jk> bar, <ja>@Path</ja> MyEnum baz, <ja>@Path</ja> UUID bing) {
+		...
+	}
+				</p>
+				<p>
+					By default, path patterns are matched using a best-match heuristic. 
+					<br>When overlaps occur, URLs are matched from most-specific to most-general order:
+				</p>
+				<p class='bcode'>
+	<jc>// Try first </jc>
+	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foo/bar"</js>)
+	<jk>public void</jk> method1() {
+		...
+	}
+
+	<jc>// Try second</jc>
+	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foo/{bar}"</js>)
+	<jk>public void</jk> method2(...) {
+		...
+	}
+
+	<jc>// Try third</jc>
+	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foo/*"</js>)
+	<jk>public void</jk> method3(...) {
+		...
+	}
+
+	<jc>// Try last</jc>
+	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
+	<jk>public void</jk> method4(...) {
+		...
+	}
+				</p>
+				<p>
+					The match heuristic behavior can be overridden by the 
+					{@link org.apache.juneau.rest.annotation.RestMethod#priority() @RestMethod.priority()} annotation 
+					property.
+					<br>However, in practice this is almost never needed.
+				</p>
+				<p>
+					Paths that end with <js>"/*"</js> will do a prefix match on the incoming URL.  
+					<br>Any remainder after the match can be accessed through 
+					{@link org.apache.juneau.rest.RequestPathMatch#getRemainder()} or parameters with the 
+					{@link org.apache.juneau.rest.annotation.PathRemainder @PathRemainder} annotation.
+					<br>On the other hand, paths that don't end with <js>"/*"</js> (e.g. <js>"/"</js> or <js>"/foo"</js>) will 
+					require an exact URL match, and if any remainder exists, a 404 (not found) error will be thrown.
+				</p>
+				<p>
+					The following example shows the distinction.
+				</p>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
+	<jk>public void</jk> doGet(<ja>@PathRemainder</ja> String remainder) {
+		<jc>// URL path pattern can have remainder accessible through req.getRemainder().</jc>
+	}
+
+	<ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/"</js>)
+	<jk>public void</jk> doPut() {
+		<jc>// URL path pattern must match exactly and will cause a 404 error if a remainder exists.</jc>
+	}
+				</p>
+				<p>
+					Annotations are provided for easy access to URL parameters with automatic conversion to any parsable object type.
+					<br>For example, the following example can process the URL <l>"/urlWithParams?foo=foo&amp;bar=[1,2,3]&amp;baz=067e6162-3b6f-4ae2-a171-2470b63dff00"</l>...
+				</p>
+				<p class='bcode'>
+	<jc>// Example GET request with access to query parameters</jc>
+	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/urlWithParams"</js>)
+	<jk>public</jk> String doGetWithParams(<ja>@Query</ja>(<js>"foo"</js>) String foo, <ja>@Query</ja>(<js>"bar"</js>) <jk>int</jk> bar, <ja>@Query</ja>(<js>"baz"</js>) UUID baz) <jk>throws</jk> Exception {
+		<jk>return</jk> <js>"GET /urlWithParams?foo="</js>+foo+<js>"&amp;bar="</js>+bar+<js>"&amp;baz="</js>+baz;
+	}
+				</p>
+				<h6 class='section'>See Also:</h6>
+				<ul>
+					<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_path}
+					<li class='ja'>{@link org.apache.juneau.rest.annotation.Path}
+					<li class='ja'>{@link org.apache.juneau.rest.annotation.PathRemainder}
+					<li class='jc'>{@link org.apache.juneau.rest.RequestPathMatch}
+				</ul>
+			</div>	
+	
+			<!-- ======================================================================================================== -->
 			<a id="juneau-rest-server.RequestPathMatch"></a>
-			<h4 class='topic' onclick='toggle(this)'>3.1.6.X - RequestPathMatch</h4>
+			<h4 class='topic' onclick='toggle(this)'>3.1.6.9 - RequestPathMatch</h4>
 			<div class='topic'>
-				TODO
+				<p>
+					The {@link org.apache.juneau.rest.RequestPathMatch} object is the API for accessing the matched variables
+					and remainder on the URL path.
+				</p>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Object myMethod(RequestPathMatch path) {...}			
+				</p>
+				<h6 class='figure'>Example:</h6>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(..., path=<js>"/{foo}/{bar}/{baz}/*"</js>)
+	<jk>public void</jk> doGet(RequestPathMatch path) {
+		<jc>// Example URL:  /123/qux/true/quux</jc>
+	 	
+		<jk>int</jk> foo = pm.getInt(<js>"foo"</js>);  <jc>// =123</jc>
+		String bar = pm.getString(<js>"bar"</js>);  <jc>// =qux</jc>
+		<jk>boolean</jk> baz = pm.getBoolean(<js>"baz"</js>);  <jc>// =true</jc>
+		String remainder = pm.getRemainder();  <jc>// =quux</jc>
+	}
+				</p>
+				<p>
+					The important methods on this class are:
+				</p>
+				<ul class='doctree'>
+					<li class='jc'><code>{@link org.apache.juneau.rest.RequestPathMatch} <jk>extends</jk> TreeMap&lt;String,String&gt;</code>
+					<ul>
+						<li class='jm'>{@link org.apache.juneau.rest.RequestPathMatch#get(String,Class) get(String,Class)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestPathMatch#get(String,Type,Type...) get(String,Type,Type)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestPathMatch#getString(String) getString(String)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestPathMatch#getInt(String) getInt(String)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestPathMatch#getBoolean(String) getBoolean(String)}
+						<li class='jm'>{@link org.apache.juneau.rest.RequestPathMatch#getRemainder() getRemainder()}
+					</ul>
+				</ul>
 			</div>
 
 			<!-- ======================================================================================================== -->
 			<a id="juneau-rest-server.MethodReturnTypes"></a>
-			<h4 class='topic' onclick='toggle(this)'>3.1.6.8 - Method Return Types</h4>
+			<h4 class='topic' onclick='toggle(this)'>3.1.6.10 - Method Return Types</h4>
 			<div class='topic'>
 				<p>
 					The return type can be any serializable POJO as defined in <a class='doclink' href='#juneau-marshall.PojoCategories'>POJO Categories</a>.
@@ -5782,139 +6118,145 @@
 		
 			<!-- ======================================================================================================== -->
 			<a id="juneau-rest-server.ReaderResource"></a>
-			<h4 class='topic' onclick='toggle(this)'>3.1.6.9 - ReaderResource</h4>
+			<h4 class='topic' onclick='toggle(this)'>3.1.6.11 - ReaderResource</h4>
 			<div class='topic'>
-				TODO
+				<p>
+					The {@link org.apache.juneau.rest.ReaderResource} class is a convenience object for defining thread-safe
+					reusable character-based responses.
+					<br>In essence, it's a container for character data with optional response headers and support for
+					resolving SVL variables.
+				</p>
+				<p>
+					The {@link org.apache.juneau.rest.ReaderResource} class implements the {@link org.apache.juneau.Writable}
+					interface which is handled by the {@link org.apache.juneau.rest.response.WritableHandler} class.
+					<br>This allows these objects to be returned as responses by REST methods.
+				</p>
+				<h6 class='figure'>Example:</h6>
+				<p class='bcode'>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Object sayHello(RestRequest req) {
+	
+		<jc>// Return a reader resource loaded from a file with support for request-time SVL variables.</jc>
+		<jk>return</jk> ReaderResource.<jsm>create</jsm>()
+			.contents(<jk>new</jk> File(<js>"helloWorld.txt"</js>))
+			.varResolver(req.getVarResolver()) 
+			.header(<js>"Cache-Control"</js>, <js>"no-cache"</js>)
+			.mediaType(<jsf>TEXT_PLAIN</jsf>)
+			.build();
+	}
+				</p>
+				<p>
+					The important methods on this class are:
+				</p>
+				<ul class='doctree'>
+					<li class='jc'>{@link org.apache.juneau.rest.ReaderResourceBuilder}
+					<ul>
+						<li class='jm'>{@link org.apache.juneau.rest.ReaderResourceBuilder#contents(Object...) contents(Object...)}
+						<li class='jm'>{@link org.apache.juneau.rest.ReaderResourceBuilder#header(String,Object) header(String,Object)}
+						<li class='jm'>{@link org.apache.juneau.rest.ReaderResourceBuilder#mediaType(MediaType) mediaType(MediaType)}
+						<li class='jm'>{@link org.apache.juneau.rest.ReaderResourceBuilder#varResolver(VarResolverSession) varResolver(VarResolverSession)}
+					</ul>
+				</ul>
 			</div>
 		
 			<!-- ======================================================================================================== -->
-			<a id="juneau-rest-server.ReaderResource"></a>
-			<h4 class='topic' onclick='toggle(this)'>3.1.6.10 - StreamResource</h4>
-			<div class='topic'>
-				TODO
-			</div>
-
-			<!-- ======================================================================================================== -->
-			<a id="juneau-rest-server.RestMethodPath"></a>
-			<h4 class='topic' onclick='toggle(this)'>3.1.6.11 - @RestMethod.path()</h4>
+			<a id="juneau-rest-server.StreamResource"></a>
+			<h4 class='topic' onclick='toggle(this)'>3.1.6.12 - StreamResource</h4>
 			<div class='topic'>
 				<p>
-					The {@link org.apache.juneau.rest.annotation.RestMethod#path() @RestMethod.path()} annotation allows 
-					you to define URL path patterns to match against.
-					<br>These patterns can contain variables of the form <l>"{xxx}"</l> that can be passed in directly to the
-					Java methods as extra parameters.
+					The {@link org.apache.juneau.rest.StreamResource} class is the binary equivalent to the {@link org.apache.juneau.rest.ReaderResource} object.
+					<br>In essence, it's a container for binary data with optional response headers.
 				</p>
 				<p>
-					In the following example, 3 separate GET request handlers are defined with different path patterns.
-					<br>Note how the variables are passed in as additional arguments on the method, and how those arguments are 
-					automatically converted to the specified class type...
+					The {@link org.apache.juneau.rest.StreamResource} class implements the {@link org.apache.juneau.Streamable}
+					interface which is handled by the {@link org.apache.juneau.rest.response.StreamableHandler} class.
+					<br>This allows these objects to be returned as responses by REST methods.
 				</p>
+				<h6 class='figure'>Example:</h6>
 				<p class='bcode'>
-	<jc>// Default method</jc>
-	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
-	<jk>public void</jk> doGetDefault() {
-		...
-	}
-
-	<jc>// Method with path pattern</jc>
-	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/xxx"</js>)
-	<jk>public void</jk> doGetNoArgs(...) {
-		...
-	}
-
-	<jc>// Method with path pattern with arguments</jc>
-	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/xxx/{foo}/{bar}/{baz}/{bing}"</js>)
-	<jk>public void</jk> doGetWithArgs(<ja>@Path</ja> String foo, <ja>@Path</ja> <jk>int</jk> bar, <ja>@Path</ja> MyEnum baz, <ja>@Path</ja> UUID bing) {
-		...
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Object showPicture(RestRequest req) {
+	
+		<jc>// Return a stream resource loaded from a file.</jc>
+		<jk>return</jk> StreamResource.<jsm>create</jsm>()
+			.contents(<jk>new</jk> File(<js>"mypicture.png"</js>))
+			.header(<js>"Cache-Control"</js>, <js>"no-cache"</js>)
+			.mediaType(<jsf>IMAGE_PNG</jsf>)
+			.build();
 	}
 				</p>
 				<p>
-					By default, path patterns are matched using a best-match heuristic. 
-					<br>When overlaps occur, URLs are matched from most-specific to most-general order:
+					The important methods on this class are:
 				</p>
-				<p class='bcode'>
-	<jc>// Try first </jc>
-	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foo/bar"</js>)
-	<jk>public void</jk> method1() {
-		...
-	}
-
-	<jc>// Try second</jc>
-	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foo/{bar}"</js>)
-	<jk>public void</jk> method2(...) {
-		...
-	}
-
-	<jc>// Try third</jc>
-	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foo/*"</js>)
-	<jk>public void</jk> method3(...) {
-		...
-	}
+				<ul class='doctree'>
+					<li class='jc'>{@link org.apache.juneau.rest.StreamResourceBuilder}
+					<ul>
+						<li class='jm'>{@link org.apache.juneau.rest.StreamResourceBuilder#contents(Object...) contents(Object...)}
+						<li class='jm'>{@link org.apache.juneau.rest.StreamResourceBuilder#header(String,Object) header(String,Object)}
+						<li class='jm'>{@link org.apache.juneau.rest.StreamResourceBuilder#mediaType(MediaType) mediaType(MediaType)}
+					</ul>
+				</ul>
+			</div>
 
-	<jc>// Try last</jc>
-	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
-	<jk>public void</jk> method4(...) {
-		...
-	}
-				</p>
+			<!-- ======================================================================================================== -->
+			<a id="juneau-rest-server.Redirect"></a>
+			<h4 class='topic' onclick='toggle(this)'>3.1.6.13 - Redirect</h4>
+			<div class='topic'>
 				<p>
-					The match heuristic behavior can be overridden by the 
-					{@link org.apache.juneau.rest.annotation.RestMethod#priority() @RestMethod.priority()} annotation 
-					property.
-					<br>However, in practice this is almost never needed.
+					The {@link org.apache.juneau.rest.Redirect} object is a convenience shortcut for performing <code>HTTP 302</code> redirects.
 				</p>
 				<p>
-					Paths that end with <js>"/*"</js> will do a prefix match on the incoming URL.  
-					<br>Any remainder after the match can be accessed through 
-					{@link org.apache.juneau.rest.RequestPathMatch#getRemainder()} or parameters with the 
-					{@link org.apache.juneau.rest.annotation.PathRemainder @PathRemainder} annotation.
-					<br>On the other hand, paths that don't end with <js>"/*"</js> (e.g. <js>"/"</js> or <js>"/foo"</js>) will 
-					require an exact URL match, and if any remainder exists, a 404 (not found) error will be thrown.
+					<l>Redirect</l> objects are handled by the {@link org.apache.juneau.rest.response.RedirectHandler} class.
+					<br>This allows these objects to be returned as responses by REST methods.
 				</p>
 				<p>
-					The following example shows the distinction.
+					The following example shows the difference between handling redirects via <l>RestResponse</l> and the simplified approach of using this class.
 				</p>
+				<h6 class='figure'>Example:</h6>
 				<p class='bcode'>
-	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/*"</js>)
-	<jk>public void</jk> doGet(<ja>@PathRemainder</ja> String remainder) {
-		<jc>// URL path pattern can have remainder accessible through req.getRemainder().</jc>
-	}
+	<jc>// Redirect to "/contextPath/servletPath/foobar"</jc>
 
-	<ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/"</js>)
-	<jk>public void</jk> doPut() {
-		<jc>// URL path pattern must match exactly and will cause a 404 error if a remainder exists.</jc>
+	<jc>// Using RestRequest/RestResponse</jc>
+	<ja>@RestMethod</ja>(...)
+	<jk>public void</jk> redirectExample1(RestRequest req, RestResponse res) <jk>throws</jk> IOException {
+		res.sendRedirect(req.getServletURI() + <js>"/foobar"</js>);
+	}
+	
+	<jc>// Using Redirect</jc>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Redirect redirectExample2() {
+		<jk>return new</jk> Redirect(<js>"foobar"</js>);
 	}
 				</p>
 				<p>
-					Annotations are provided for easy access to URL parameters with automatic conversion to any parsable object type.
-					<br>For example, the following example can process the URL <l>"/urlWithParams?foo=foo&amp;bar=[1,2,3]&amp;baz=067e6162-3b6f-4ae2-a171-2470b63dff00"</l>...
+					The constructor can use a <l>MessageFormat</l>-style pattern with multiple arguments.
 				</p>
+				<h6 class='figure'>Example:</h6>
 				<p class='bcode'>
-	<jc>// Example GET request with access to query parameters</jc>
-	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/urlWithParams"</js>)
-	<jk>public</jk> String doGetWithParams(<ja>@Query</ja>(<js>"foo"</js>) String foo, <ja>@Query</ja>(<js>"bar"</js>) <jk>int</jk> bar, <ja>@Query</ja>(<js>"baz"</js>) UUID baz) <jk>throws</jk> Exception {
-		<jk>return</jk> <js>"GET /urlWithParams?foo="</js>+foo+<js>"&amp;bar="</js>+bar+<js>"&amp;baz="</js>+baz;
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Redirect redirectExample3() {
+		<jk>return new</jk> Redirect(<js>"foo/{0}/bar/{1}"</js>, id1, id2);
+	}
+				</p>
+				<p>
+					The arguments are automatically URL-encoded.
+				</p>
+				<p>
+					Redirecting to the servlet root can be accomplished by simply using the no-arg constructor.
+				<h6 class='figure'>Example:</h6>
+				<p class='bcode'>
+	<jc>// Simply redirect to the servlet root.
+	// Equivalent to res.sendRedirect(req.getServletURI()).</jc>
+	<ja>@RestMethod</ja>(...)
+	<jk>public</jk> Redirect redirectExample4() {
+		<jk>return new</jk> Redirect();
 	}
 				</p>
-				<h6 class='section'>See Also:</h6>
-				<ul>
-					<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_path}
-					<li class='ja'>{@link org.apache.juneau.rest.annotation.Path}
-					<li class='ja'>{@link org.apache.juneau.rest.annotation.PathRemainder}
-					<li class='jc'>{@link org.apache.juneau.rest.RequestPathMatch}
-				</ul>
-			</div>	
-	
-			<!-- ======================================================================================================== -->
-			<a id="juneau-rest-server.RequestFormData"></a>
-			<h4 class='topic' onclick='toggle(this)'>3.1.6.12 - RequestPathMatch</h4>
-			<div class='topic'>
-				TODO
 			</div>
-
+			
 			<!-- ======================================================================================================== -->
 			<a id="juneau-rest-server.RestMethodMatchers"></a>
-			<h4 class='topic' onclick='toggle(this)'>3.1.6.13 - @RestMethod.matchers()</h4>
+			<h4 class='topic' onclick='toggle(this)'>3.1.6.14 - @RestMethod.matchers()</h4>
 			<div class='topic'>
 				<p>
 					{@link org.apache.juneau.rest.RestMatcher RestMatchers} are used to allow multiple Java methods to be 
@@ -17828,7 +18170,7 @@
 		<h6 class='topic'>REST server updates</h6>
 		<ul class='spaced-list'>
  			<li>
-				Support for overriding bean context and serializer properties in a REST method call through new {@link org.apache.juneau.rest.RestResponse#setProperty(String,Object)} method.<br>
+				Support for overriding bean context and serializer properties in a REST method call through new <code><del>RestResponse.setProperty(String,Object)</del></code> method.<br>
 				For example, allows you to control whitespace options on a per-request basis.
 			</li>
 			<li>
diff --git a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java
index 0b60531..8f8dc5c 100644
--- a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java
+++ b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java
@@ -53,9 +53,9 @@ public class PropertiesResource extends RestServletDefault {
 		serializers=PropertySerializer1.class
 	)
 	public void testPropertiesDefinedOnMethod(RestResponse res) {
-		res.setProperty("A2", "c");
-		res.setProperty("B2", "c");
-		res.setProperty("C", "c");
+		res.prop("A2", "c");
+		res.prop("B2", "c");
+		res.prop("C", "c");
 		res.setOutput(null);
 	}
 
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
index dba8902..aa58fc5 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
@@ -1969,12 +1969,10 @@ public final class RestCall extends BeanSession {
 	 * 	See {@link #getResponse(Type, Type...)} for details.
 	 * @param type
 	 * 	The object type to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @return The parsed object.
 	 * @throws RestCallException If the executor service was not defined.
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ReaderResource.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ReaderResource.java
index da111e1..12ee539 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ReaderResource.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ReaderResource.java
@@ -19,7 +19,6 @@ import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.*;
-import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.response.*;
 import org.apache.juneau.svl.*;
 
@@ -29,6 +28,14 @@ import org.apache.juneau.svl.*;
  * 
  * <p>
  * This class is handled special by the {@link WritableHandler} class.
+ * <br>This allows these objects to be returned as responses by REST methods.
+ * 
+ * <p>
+ * <l>ReaderResources</l> are meant to be thread-safe and reusable objects.
+ * <br>The contents of the request passed into the constructor are immediately converted to read-only strings.
+ * 
+ * <p>
+ * Instances of this class can be built using {@link ReaderResourceBuilder}.
  * 
  * 
  * <h5 class='section'>Documentation:</h5>
@@ -41,25 +48,15 @@ public class ReaderResource implements Writable {
 	private final MediaType mediaType;
 	private final String[] contents;
 	private final VarResolverSession varSession;
-	private final Map<String,String> headers;
-
+	private final Map<String,Object> headers;
+	
 	/**
-	 * Constructor.
+	 * Creates a new instance of a {@link ReaderResourceBuilder}
 	 * 
-	 * @param mediaType The HTTP media type.
-	 * @param contents
-	 * 	The contents of this resource.
-	 * 	<br>If multiple contents are specified, the results will be concatenated.
-	 * 	<br>Contents can be any of the following:
-	 * 	<ul>
-	 * 		<li><code>CharSequence</code>
-	 * 		<li><code>Reader</code>
-	 * 		<li><code>File</code>
-	 * 	</ul>
-	 * @throws IOException
+	 * @return A new instance of a {@link ReaderResourceBuilder}
 	 */
-	protected ReaderResource(MediaType mediaType, Object...contents) throws IOException {
-		this(mediaType, null, null, contents);
+	public static ReaderResourceBuilder create() {
+		return new ReaderResourceBuilder();
 	}
 
 	/**
@@ -80,15 +77,11 @@ public class ReaderResource implements Writable {
 	 * 	</ul>
 	 * @throws IOException
 	 */
-	public ReaderResource(MediaType mediaType, Map<String,String> headers, VarResolverSession varSession, Object...contents) throws IOException {
+	public ReaderResource(MediaType mediaType, Map<String,Object> headers, VarResolverSession varSession, Object...contents) throws IOException {
 		this.mediaType = mediaType;
 		this.varSession = varSession;
 
-		Map<String,String> m = new LinkedHashMap<>();
-		if (headers != null)
-			for (Map.Entry<String,String> e : headers.entrySet())
-				m.put(e.getKey(), StringUtils.toString(e.getValue()));
-		this.headers = Collections.unmodifiableMap(m);
+		this.headers = headers == null ? Collections.EMPTY_MAP : Collections.unmodifiableMap(new LinkedHashMap<>(headers));
 
 		this.contents = new String[contents.length];
 		for (int i = 0; i < contents.length; i++) {
@@ -109,115 +102,14 @@ public class ReaderResource implements Writable {
 	}
 
 	/**
-	 * Builder class for constructing {@link ReaderResource} objects.
-	 */
-	public static final class Builder {
-		ArrayList<Object> contents = new ArrayList<>();
-		MediaType mediaType;
-		VarResolverSession varResolver;
-		Map<String,String> headers = new LinkedHashMap<>();
-
-		/**
-		 * Specifies the resource media type string.
-		 * 
-		 * @param mediaType The resource media type string.
-		 * @return This object (for method chaining).
-		 */
-		public Builder mediaType(String mediaType) {
-			this.mediaType = MediaType.forString(mediaType);
-			return this;
-		}
-
-		/**
-		 * Specifies the resource media type string.
-		 * 
-		 * @param mediaType The resource media type string.
-		 * @return This object (for method chaining).
-		 */
-		public Builder mediaType(MediaType mediaType) {
-			this.mediaType = mediaType;
-			return this;
-		}
-
-		/**
-		 * Specifies the contents for this resource.
-		 * 
-		 * <p>
-		 * This method can be called multiple times to add more content.
-		 * 
-		 * @param contents
-		 * 	The resource contents.
-		 * 	<br>If multiple contents are specified, the results will be concatenated.
-		 * 	<br>Contents can be any of the following:
-		 * 	<ul>
-		 * 		<li><code>InputStream</code>
-		 * 		<li><code>Reader</code> - Converted to UTF-8 bytes.
-		 * 		<li><code>File</code>
-		 * 		<li><code>CharSequence</code> - Converted to UTF-8 bytes.
-		 * 	</ul>
-		 * @return This object (for method chaining).
-		 */
-		public Builder contents(Object...contents) {
-			this.contents.addAll(Arrays.asList(contents));
-			return this;
-		}
-
-		/**
-		 * Specifies an HTTP response header value.
-		 * 
-		 * @param name The HTTP header name.
-		 * @param value
-		 * 	The HTTP header value.
-		 * 	Will be converted to a <code>String</code> using {@link Object#toString()}.
-		 * @return This object (for method chaining).
-		 */
-		public Builder header(String name, Object value) {
-			this.headers.put(name, StringUtils.toString(value));
-			return this;
-		}
-
-		/**
-		 * Specifies HTTP response header values.
-		 * 
-		 * @param headers
-		 * 	The HTTP headers.
-		 * 	Values will be converted to <code>Strings</code> using {@link Object#toString()}.
-		 * @return This object (for method chaining).
-		 */
-		public Builder headers(Map<String,Object> headers) {
-			for (Map.Entry<String,Object> e : headers.entrySet())
-				header(e.getKey(), e.getValue());
-			return this;
-		}
-
-		/**
-		 * Specifies the variable resolver to use for this resource.
-		 * 
-		 * @param varResolver The variable resolver.
-		 * @return This object (for method chaining).
-		 */
-		public Builder varResolver(VarResolverSession varResolver) {
-			this.varResolver = varResolver;
-			return this;
-		}
-
-		/**
-		 * Create a new {@link ReaderResource} using values in this builder.
-		 * 
-		 * @return A new immutable {@link ReaderResource} object.
-		 * @throws IOException
-		 */
-		public ReaderResource build() throws IOException {
-			return new ReaderResource(mediaType, headers, varResolver, contents.toArray());
-		}
-	}
-
-	/**
 	 * Get the HTTP response headers.
 	 * 
-	 * @return The HTTP response headers.
+	 * @return 
+	 * 	The HTTP response headers.  
+	 * 	<br>An unmodifiable map.  
+	 * 	<br>Never <jk>null</jk>.
 	 */
-	public Map<String,String> getHeaders() {
+	public Map<String,Object> getHeaders() {
 		return headers;
 	}
 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ReaderResourceBuilder.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ReaderResourceBuilder.java
new file mode 100644
index 0000000..33bd48e
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/ReaderResourceBuilder.java
@@ -0,0 +1,128 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              * 
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.http.*;
+import org.apache.juneau.svl.*;
+
+/**
+ * Builder class for constructing {@link ReaderResource} objects.
+ * 
+ * 
+ * <h5 class='section'>Documentation:</h5>
+ * <ul>
+ * 	<li><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.ReaderResource">Overview &gt; ReaderResource</a>
+ * </ul>
+ */
+public final class ReaderResourceBuilder {
+	ArrayList<Object> contents = new ArrayList<>();
+	MediaType mediaType;
+	VarResolverSession varResolver;
+	Map<String,Object> headers = new LinkedHashMap<>();
+
+	/**
+	 * Specifies the resource media type string.
+	 * 
+	 * @param mediaType The resource media type string.
+	 * @return This object (for method chaining).
+	 */
+	public ReaderResourceBuilder mediaType(String mediaType) {
+		this.mediaType = MediaType.forString(mediaType);
+		return this;
+	}
+
+	/**
+	 * Specifies the resource media type string.
+	 * 
+	 * @param mediaType The resource media type string.
+	 * @return This object (for method chaining).
+	 */
+	public ReaderResourceBuilder mediaType(MediaType mediaType) {
+		this.mediaType = mediaType;
+		return this;
+	}
+
+	/**
+	 * Specifies the contents for this resource.
+	 * 
+	 * <p>
+	 * This method can be called multiple times to add more content.
+	 * 
+	 * @param contents
+	 * 	The resource contents.
+	 * 	<br>If multiple contents are specified, the results will be concatenated.
+	 * 	<br>Contents can be any of the following:
+	 * 	<ul>
+	 * 		<li><code>InputStream</code>
+	 * 		<li><code>Reader</code> - Converted to UTF-8 bytes.
+	 * 		<li><code>File</code>
+	 * 		<li><code>CharSequence</code> - Converted to UTF-8 bytes.
+	 * 	</ul>
+	 * @return This object (for method chaining).
+	 */
+	public ReaderResourceBuilder contents(Object...contents) {
+		this.contents.addAll(Arrays.asList(contents));
+		return this;
+	}
+
+	/**
+	 * Specifies an HTTP response header value.
+	 * 
+	 * @param name The HTTP header name.
+	 * @param value
+	 * 	The HTTP header value.
+	 * 	<br>Will be converted to a <code>String</code> using {@link Object#toString()}.
+	 * @return This object (for method chaining).
+	 */
+	public ReaderResourceBuilder header(String name, Object value) {
+		this.headers.put(name, value);
+		return this;
+	}
+
+	/**
+	 * Specifies HTTP response header values.
+	 * 
+	 * @param headers
+	 * 	The HTTP headers.
+	 * 	<br>Values will be converted to <code>Strings</code> using {@link Object#toString()}.
+	 * @return This object (for method chaining).
+	 */
+	public ReaderResourceBuilder headers(Map<String,Object> headers) {
+		this.headers.putAll(headers);
+		return this;
+	}
+
+	/**
+	 * Specifies the variable resolver to use for this resource.
+	 * 
+	 * @param varResolver The variable resolver.
+	 * @return This object (for method chaining).
+	 */
+	public ReaderResourceBuilder varResolver(VarResolverSession varResolver) {
+		this.varResolver = varResolver;
+		return this;
+	}
+
+	/**
+	 * Create a new {@link ReaderResource} using values in this builder.
+	 * 
+	 * @return A new immutable {@link ReaderResource} object.
+	 * @throws IOException
+	 */
+	public ReaderResource build() throws IOException {
+		return new ReaderResource(mediaType, headers, varResolver, contents.toArray());
+	}
+}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/Redirect.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/Redirect.java
index 41e9cb6..0d85d31 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/Redirect.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/Redirect.java
@@ -17,63 +17,13 @@ import static org.apache.juneau.internal.StringUtils.*;
 import java.net.*;
 import java.text.*;
 
-import org.apache.juneau.urlencoding.*;
-
 /**
  * REST methods can return this object as a shortcut for performing <code>HTTP 302</code> redirects.
  * 
- * <p>
- * The following example shows the difference between handling redirects via the {@link RestRequest}/{@link RestResponse},
- * and the simplified approach of using this class.
- * <p class='bcode'>
- * 	<jc>// Redirect to "/contextPath/servletPath/foobar"</jc>
- * 
- * 	<jc>// Using RestRequest and RestResponse</jc>
- * 	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example1"</js>)
- * 	<jk>public void</jk> example1(RestRequest req, RestResponse res) <jk>throws</jk> IOException {
- * 		res.sendRedirect(req.getServletURI() + <js>"/foobar"</js>);
- * 	}
- * 
- * 	<jc>// Using Redirect</jc>
- * 	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example2"</js>)
- * 	<jk>public</jk> Redirect example2() {
- * 		<jk>return new</jk> Redirect(<js>"foobar"</js>);
- * 	}
- * </p>
- * 
- * <p>
- * The constructor can use a {@link MessageFormat}-style pattern with multiple arguments:
- * <p class='bcode'>
- * 	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example3"</js>)
- * 	<jk>public</jk> Redirect example3() {
- * 		<jk>return new</jk> Redirect(<js>"foo/{0}/bar/{1}"</js>, id1, id2);
- * 	}
- * </p>
- * 
- * <p>
- * The arguments are serialized to strings using the servlet's {@link UrlEncodingSerializer}, so any filters defined on
- * the serializer or REST method/class will be used when present.
- * The arguments will also be automatically URL-encoded.
- * 
- * <p>
- * Redirecting to the servlet root can be accomplished by simply using the no-arg constructor.
- * <p class='bcode'>
- * 	<jc>// Simply redirect to the servlet root.
- * 	// Equivalent to res.sendRedirect(req.getServletURI()).</jc>
- * 	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/example4"</js>)
- * 	<jk>public</jk> Redirect exmaple4() {
- * 		<jk>return new</jk> Redirect();
- * 	}
- * </p>
- * 
- * <p>
- * This class is handled by {@link org.apache.juneau.rest.response.RedirectHandler}, a built-in default response
- * handler created in {@link RestContextBuilder}.
- * 
  * 
  * <h5 class='section'>Documentation:</h5>
  * <ul>
- * 	<li><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.MethodReturnTypes">Overview &gt; Method Return Types</a>
+ * 	<li><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Redirect">Overview &gt; Redirect</a>
  * </ul>
  */
 public final class Redirect {
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
index 9139d65..e4c9ee7 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
@@ -89,11 +89,10 @@ public class RequestBody {
 	}
 
 	/**
-	 * Reads the input from the HTTP request as JSON, XML, or HTML and converts the input to a POJO.
+	 * Reads the input from the HTTP request parsed into a POJO.
 	 * 
 	 * <p>
-	 * If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &body=xxx} in the URL
-	 * query string.
+	 * The parser used is determined by the matching <code>Content-Type</code> header on the request.
 	 * 
 	 * <p>
 	 * If type is <jk>null</jk> or <code>Object.<jk>class</jk></code>, then the actual type will be determined
@@ -160,6 +159,11 @@ public class RequestBody {
 	 * 	Map body = req.getBody().asType(TreeMap.<jk>class</jk>);
 	 * </p>
 	 * 
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li>If {@code allowHeaderParams} init parameter is true, then first looks for {@code &body=xxx} in the URL query string.
+	 * </ul>
+	 * 
 	 * @param type The class type to instantiate.
 	 * @param <T> The class type to instantiate.
 	 * @return The input parsed to a POJO.
@@ -173,7 +177,10 @@ public class RequestBody {
 	}
 
 	/**
-	 * Reads the input from the HTTP request as JSON, XML, or HTML and converts the input to a POJO.
+	 * Reads the input from the HTTP request parsed into a POJO.
+	 * 
+	 * <p>
+	 * This is similar to {@link #asType(Class)} but allows for complex collections of POJOs to be created.
 	 * 
 	 * <h5 class='section'>Examples:</h5>
 	 * <p class='bcode'>
@@ -190,14 +197,19 @@ public class RequestBody {
 	 * 	Map&lt;String,List&lt;MyBean&gt;&gt; body = req.getBody().asType(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
 	 * </p>
 	 * 
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li><code>Collections</code> must be followed by zero or one parameter representing the value type.
+	 * 	<li><code>Maps</code> must be followed by zero or two parameters representing the key and value types.
+	 * 	<li>If {@code allowHeaderParams} init parameter is true, then first looks for {@code &body=xxx} in the URL query string.
+	 * </ul>
+	 * 
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @param <T> The class type to instantiate.
 	 * @return The input parsed to a POJO.
@@ -209,9 +221,10 @@ public class RequestBody {
 	/**
 	 * Returns the HTTP body content as a plain string.
 	 * 
-	 * <p>
-	 * If {@code allowHeaderParams} init parameter is true, then first looks for {@code &body=xxx} in the URL query
-	 * string.
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li>If {@code allowHeaderParams} init parameter is true, then first looks for {@code &body=xxx} in the URL query string.
+	 * </ul>
 	 * 
 	 * @return The incoming input from the connection as a plain string.
 	 * @throws IOException If a problem occurred trying to read from the reader.
@@ -225,6 +238,11 @@ public class RequestBody {
 	/**
 	 * Returns the HTTP body content as a simple hexadecimal character string.
 	 * 
+	 * <h6 class='section'>Example:</h6>
+	 * <p class='bcode'>
+	 * 	0123456789ABCDEF
+	 * </p>
+	 * 
 	 * @return The incoming input from the connection as a plain string.
 	 * @throws IOException If a problem occurred trying to read from the reader.
 	 */
@@ -237,6 +255,11 @@ public class RequestBody {
 	/**
 	 * Returns the HTTP body content as a simple space-delimited hexadecimal character string.
 	 * 
+	 * <h6 class='section'>Example:</h6>
+	 * <p class='bcode'>
+	 * 	01 23 45 67 89 AB CD EF
+	 * </p>
+	 * 
 	 * @return The incoming input from the connection as a plain string.
 	 * @throws IOException If a problem occurred trying to read from the reader.
 	 */
@@ -249,12 +272,11 @@ public class RequestBody {
 	/**
 	 * Returns the HTTP body content as a {@link Reader}.
 	 * 
-	 * <p>
-	 * If {@code allowHeaderParams} init parameter is true, then first looks for {@code &body=xxx} in the URL query
-	 * string.
-	 * 
-	 * <p>
-	 * Automatically handles GZipped input streams.
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li>If {@code allowHeaderParams} init parameter is true, then first looks for {@code &body=xxx} in the URL query string.
+	 * 	<li>Automatically handles GZipped input streams.
+	 * </ul>
 	 * 
 	 * @return The body contents as a reader.
 	 * @throws IOException
@@ -283,9 +305,6 @@ public class RequestBody {
 	/**
 	 * Returns the HTTP body content as an {@link InputStream}.
 	 * 
-	 * <p>
-	 * Automatically handles GZipped input streams.
-	 * 
 	 * @return The negotiated input stream.
 	 * @throws IOException If any error occurred while trying to get the input stream or wrap it in the GZIP wrapper.
 	 */
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java
index 46811dd..602e69b 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java
@@ -17,15 +17,33 @@ import static org.apache.juneau.internal.ArrayUtils.*;
 import java.lang.reflect.*;
 import java.util.*;
 
+import javax.servlet.http.*;
+
 import org.apache.juneau.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.annotation.*;
 
 /**
- * Represents the parsed form data parameters in an HTTP request.
+ * Represents the parsed form-data parameters in an HTTP request.
+ * 
+ * <p>
+ * Similar in functionality to the {@link HttpServletRequest#getParameter(String)} except only looks in the body of the request, not parameters from
+ * the URL query string.
+ * <br>This can be useful in cases where you're using GET parameters on FORM POSTs, and you don't want the body of the request to be read.
  * 
+ * <p>
+ * Use of this object is incompatible with using any other methods that access the body of the request (since this object will
+ * consume the body).
+ * <br>Some examples:
+ * <ul>
+ * 	<li class='jm'>{@link RestRequest#getBody()}
+ * 	<li class='jm'>{@link RestRequest#getReader()}
+ * 	<li class='jm'>{@link RestRequest#getInputStream()}
+ * 	<li class='ja'>{@link Header}
+ * </ul>
  * 
  * <h5 class='section'>Documentation:</h5>
  * <ul>
@@ -53,9 +71,11 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * Adds default entries to these form-data parameters.
 	 * 
 	 * <p>
-	 * This includes the default form-data parameters defined on the servlet and method levels.
+	 * This includes the default form-data parameters defined on the resource and method levels.
 	 * 
-	 * @param defaultEntries The default entries.  Can be <jk>null</jk>.
+	 * @param defaultEntries 
+	 * 	The default entries.  
+	 * 	<br>Can be <jk>null</jk>.
 	 * @return This object (for method chaining).
 	 */
 	public RequestFormData addDefault(Map<String,Object> defaultEntries) {
@@ -72,7 +92,25 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	}
 
 	/**
-	 * Sets a request form data parameter value.
+	 * Adds a default entries to these form-data parameters.
+	 * 
+	 * <p>
+	 * Similar to {@link #put(String, Object)} but doesn't override existing values.
+	 * 
+	 * @param name 
+	 * 	The form-data parameter name.  
+	 * @param value
+	 * 	The form-data parameter value.  
+	 * 	<br>Converted to a String using <code>toString()</code>.
+	 * 	<br>Ignored if value is <jk>null</jk> or blank.
+	 * @return This object (for method chaining).
+	 */
+	public RequestFormData addDefault(String name, Object value) {
+		return addDefault(Collections.singletonMap(name, value));
+	}
+
+	/**
+	 * Sets a request form-data parameter value.
 	 * 
 	 * @param name The parameter name.
 	 * @param value The parameter value.
@@ -82,17 +120,15 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	}
 
 	/**
-	 * Returns a form data parameter value.
+	 * Returns a form-data parameter value.
 	 * 
 	 * <p>
 	 * Parameter lookup is case-insensitive (consistent with WAS, but differs from Tomcat).
 	 * 
 	 * <h5 class='section'>Notes:</h5>
 	 * <ul>
-	 * 	<li>Calling this method on URL-Encoded FORM posts causes the body content to be loaded and parsed by the
-	 * 		underlying servlet API.
 	 * 	<li>This method returns the raw unparsed value, and differs from calling
-	 * 		<code>getFormDataParameter(name, String.<jk>class</js>)</code> which will convert the value from UON
+	 * 		<code>get(name, String.<jk>class</js>)</code> which will convert the value from UON
 	 * 		notation:
 	 * 		<ul>
 	 * 			<li><js>"null"</js> =&gt; <jk>null</jk>
@@ -102,7 +138,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * 		</ul>
 	 * </ul>
 	 * 
-	 * @param name The form data parameter name.
+	 * @param name The form-data parameter name.
 	 * @return The parameter value, or <jk>null</jk> if parameter does not exist.
 	 */
 	public String getString(String name) {
@@ -122,7 +158,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	/**
 	 * Same as {@link #getString(String)} except returns a default value if <jk>null</jk> or empty.
 	 * 
-	 * @param name The form data parameter name.
+	 * @param name The form-data parameter name.
 	 * @param def The default value.
 	 * @return The parameter value, or the default value if parameter does not exist or is <jk>null</jk> or empty.
 	 */
@@ -134,7 +170,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	/**
 	 * Same as {@link #getString(String)} but converts the value to an integer.
 	 * 
-	 * @param name The form data parameter name.
+	 * @param name The form-data parameter name.
 	 * @return The parameter value, or <code>0</code> if parameter does not exist or is <jk>null</jk> or empty.
 	 */
 	public int getInt(String name) {
@@ -144,7 +180,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	/**
 	 * Same as {@link #getString(String,String)} but converts the value to an integer.
 	 * 
-	 * @param name The form data parameter name.
+	 * @param name The form-data parameter name.
 	 * @param def The default value.
 	 * @return The parameter value, or the default value if parameter does not exist or is <jk>null</jk> or empty.
 	 */
@@ -156,7 +192,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	/**
 	 * Same as {@link #getString(String)} but converts the value to a boolean.
 	 * 
-	 * @param name The form data parameter name.
+	 * @param name The form-data parameter name.
 	 * @return The parameter value, or <jk>false</jk> if parameter does not exist or is <jk>null</jk> or empty.
 	 */
 	public boolean getBoolean(String name) {
@@ -166,7 +202,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	/**
 	 * Same as {@link #getString(String,String)} but converts the value to a boolean.
 	 * 
-	 * @param name The form data parameter name.
+	 * @param name The form-data parameter name.
 	 * @param def The default value.
 	 * @return The parameter value, or the default value if parameter does not exist or is <jk>null</jk> or empty.
 	 */
@@ -176,31 +212,29 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	}
 
 	/**
-	 * Returns the specified form data parameter value converted to a POJO using the {@link HttpPartParser}
-	 * registered with this servlet.
+	 * Returns the specified form-data parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
 	 * 
 	 * <h5 class='section'>Examples:</h5>
 	 * <p class='bcode'>
 	 * 	<jc>// Parse into an integer.</jc>
-	 * 	<jk>int</jk> myparam = req.getFormDataParameter(<js>"myparam"</js>, <jk>int</jk>.<jk>class</jk>);
+	 * 	<jk>int</jk> myparam = formData.get(<js>"myparam"</js>, <jk>int</jk>.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into an int array.</jc>
-	 * 	<jk>int</jk>[] myparam = req.getFormDataParameter(<js>"myparam"</js>, <jk>int</jk>[].<jk>class</jk>);
+	 * 	<jk>int</jk>[] myparam = formData.get(<js>"myparam"</js>, <jk>int</jk>[].<jk>class</jk>);
 
 	 * 	<jc>// Parse into a bean.</jc>
-	 * 	MyBean myparam = req.getFormDataParameter(<js>"myparam"</js>, MyBean.<jk>class</jk>);
+	 * 	MyBean myparam = formData.get(<js>"myparam"</js>, MyBean.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a linked-list of objects.</jc>
-	 * 	List myparam = req.getFormDataParameter(<js>"myparam"</js>, LinkedList.<jk>class</jk>);
+	 * 	List myparam = formData.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a map of object keys/values.</jc>
-	 * 	Map myparam = req.getFormDataParameter(<js>"myparam"</js>, TreeMap.<jk>class</jk>);
+	 * 	Map myparam = formData.get(<js>"myparam"</js>, TreeMap.<jk>class</jk>);
 	 * </p>
 	 * 
-	 * <h5 class='section'>Notes:</h5>
+	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li>Calling this method on URL-Encoded FORM posts causes the body content to be loaded and parsed by the
-	 * 		underlying servlet API.
+	 * 	<li class='jf'>{@link RestContext#REST_partParser}
 	 * </ul>
 	 * 
 	 * @param name The parameter name.
@@ -218,7 +252,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The parameter name.
 	 * @param type The class type to convert the parameter value to.
 	 * @param <T> The class type to convert the parameter value to.
@@ -248,7 +282,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The parameter name.
 	 * @param def The default value if the parameter was not specified or is <jk>null</jk>.
 	 * @param type The class type to convert the parameter value to.
@@ -262,7 +296,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 
 	/**
 	 * Same as {@link #get(String, Class)} except for use on multi-part parameters
-	 * (e.g. <js>"key=1&amp;key=2&amp;key=3"</js> instead of <js>"key=(1,2,3)"</js>)
+	 * (e.g. <js>"key=1&amp;key=2&amp;key=3"</js> instead of <js>"key=@(1,2,3)"</js>)
 	 * 
 	 * <p>
 	 * This method must only be called when parsing into classes of type Collection or array.
@@ -284,7 +318,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The parameter name.
 	 * @param type The class type to convert the parameter value to.
 	 * @return The parameter value converted to the specified class type.
@@ -295,40 +329,44 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	}
 
 	/**
-	 * Returns the specified form data parameter value converted to a POJO using the {@link HttpPartParser}
-	 * registered with this servlet.
+	 * Returns the specified form-data parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
 	 * 
-	 * <h5 class='section'>Notes:</h5>
-	 * <ul>
-	 * 	<li>Calling this method on URL-Encoded FORM posts causes the body content to be loaded and parsed by the
-	 * 		underlying servlet API.
-	 * 	<li>Use this method if you want to parse into a parameterized <code>Map</code>/<code>Collection</code> object.
-	 * </ul>
+	 * <p>
+	 * Similar to {@link #get(String,Class)} but allows for complex collections of POJOs to be created.
 	 * 
 	 * <h5 class='section'>Examples:</h5>
 	 * <p class='bcode'>
 	 * 	<jc>// Parse into a linked-list of strings.</jc>
-	 * 	List&lt;String&gt; myparam = req.getFormDataParameter(<js>"myparam"</js>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
+	 * 	List&lt;String&gt; myparam = formData.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a linked-list of linked-lists of strings.</jc>
-	 * 	List&lt;List&lt;String&gt;&gt; myparam = req.getFormDataParameter(<js>"myparam"</js>, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
+	 * 	List&lt;List&lt;String&gt;&gt; myparam = formData.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a map of string keys/values.</jc>
-	 * 	Map&lt;String,String&gt; myparam = req.getFormDataParameter(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
+	 * 	Map&lt;String,String&gt; myparam = formData.getr(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
-	 * 	Map&lt;String,List&lt;MyBean&gt;&gt; myparam = req.getFormDataParameter(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
+	 * 	Map&lt;String,List&lt;MyBean&gt;&gt; myparam = formData.get(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
 	 * </p>
 	 * 
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li><code>Collections</code> must be followed by zero or one parameter representing the value type.
+	 * 	<li><code>Maps</code> must be followed by zero or two parameters representing the key and value types.
+	 * </ul>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link RestContext#REST_partParser}
+	 * </ul>
+	 * 
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
@@ -342,16 +380,14 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
@@ -362,7 +398,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 
 	/**
 	 * Same as {@link #get(String, Type, Type...)} except for use on multi-part parameters
-	 * (e.g. <js>"key=1&amp;key=2&amp;key=3"</js> instead of <js>"key=(1,2,3)"</js>)
+	 * (e.g. <js>"key=1&amp;key=2&amp;key=3"</js> instead of <js>"key=@(1,2,3)"</js>)
 	 * 
 	 * <p>
 	 * This method must only be called when parsing into classes of type Collection or array.
@@ -370,12 +406,10 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
@@ -389,16 +423,14 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @return The parameter value converted to the specified class type.
 	 * @throws ParseException
@@ -464,10 +496,10 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	}
 
 	/**
-	 * Converts the form data parameters to a readable string.
+	 * Converts the form-data parameters to a readable string.
 	 * 
-	 * @param sorted Sort the form data parameters by name.
-	 * @return A JSON string containing the contents of the form data parameters.
+	 * @param sorted Sort the form-data parameters by name.
+	 * @return A JSON string containing the contents of the form-data parameters.
 	 */
 	public String toString(boolean sorted) {
 		Map<String,Object> m = (sorted ? new TreeMap<String,Object>() : new LinkedHashMap<String,Object>());
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java
index d403bad..b3fff26 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java
@@ -35,7 +35,7 @@ import org.apache.juneau.parser.*;
  * 
  * <h5 class='section'>Documentation:</h5>
  * <ul>
- * 	<li><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Header">Overview &gt; @Header</a>
+ * 	<li><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestHeaders">Overview &gt; RequestHeaders</a>
  * </ul>
  */
 public class RequestHeaders extends TreeMap<String,String[]> {
@@ -68,9 +68,11 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * Adds default entries to these headers.
 	 * 
 	 * <p>
-	 * This includes the default headers defined on the servlet and method levels.
+	 * Similar to {@link #put(String, Object)} but doesn't override existing values.
 	 * 
-	 * @param defaultEntries The default entries.  Can be <jk>null</jk>.
+	 * @param defaultEntries 
+	 * 	The default entries.  
+	 * 	<br>Can be <jk>null</jk>.
 	 * @return This object (for method chaining).
 	 */
 	public RequestHeaders addDefault(Map<String,Object> defaultEntries) {
@@ -89,6 +91,9 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	/**
 	 * Adds a default header value on this request.
 	 * 
+	 * <p>
+	 * Similar to {@link #put(String, Object)} but doesn't override existing values.
+	 * 
 	 * @param name 
 	 * 	The header name.  
 	 * @param value
@@ -121,11 +126,12 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	}
 
 	/**
-	 * Returns the specified header value, or <jk>null</jk> if the header doesn't exist.
+	 * Returns the specified header value as a string.
 	 * 
-	 * <p>
-	 * If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the
-	 * URL query string.
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li>If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
+	 * </ul>
 	 * 
 	 * @param name The header name.
 	 * @return The header value, or <jk>null</jk> if it doesn't exist.
@@ -142,11 +148,12 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	}
 
 	/**
-	 * Returns the specified header value, or a default value if the header doesn't exist.
+	 * Returns the specified header value as a string.
 	 * 
-	 * <p>
-	 * If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the
-	 * URL query string.
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li>If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
+	 * </ul>
 	 * 
 	 * @param name The HTTP header name.
 	 * @param def The default value to return if the header value isn't found.
@@ -204,6 +211,9 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	/**
 	 * Sets a request header value.
 	 * 
+	 * <p>
+	 * This overwrites any previous value.
+	 * 
 	 * @param name The header name.
 	 * @param value The header value.
 	 */
@@ -212,11 +222,7 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	}
 
 	/**
-	 * Returns the specified header value converted to a POJO.
-	 * 
-	 * <p>
-	 * The type can be any POJO type convertible from a <code>String</code>
-	 * (See <a class="doclink" href="package-summary.html#PojosConvertableFromString">POJOs Convertible From Strings</a>).
+	 * Returns the specified header value converted to a POJO using the {@link HttpPartParser} registered with the resource.
 	 * 
 	 * <h5 class='section'>Examples:</h5>
 	 * <p class='bcode'>
@@ -227,6 +233,16 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * 	UUID myheader = req.getHeader(<js>"My-Header"</js>, UUID.<jk>class</jk>);
 	 * </p>
 	 * 
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li>If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
+	 * </ul>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link RestContext#REST_partParser}
+	 * </ul>
+	 * 
 	 * @param name The HTTP header name.
 	 * @param type The class type to convert the header value to.
 	 * @param <T> The class type to convert the header value to.
@@ -242,7 +258,7 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string header.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The HTTP header name.
 	 * @param type The class type to convert the header value to.
 	 * @param <T> The class type to convert the header value to.
@@ -272,7 +288,7 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string header.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The HTTP header name.
 	 * @param def The default value if the header was not specified or is <jk>null</jk>.
 	 * @param type The class type to convert the header value to.
@@ -290,11 +306,10 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	}
 
 	/**
-	 * Returns the specified header value converted to a POJO.
+	 * Returns the specified header value converted to a POJO using the {@link HttpPartParser} registered with the resource.
 	 * 
 	 * <p>
-	 * The type can be any POJO type convertible from a <code>String</code>
-	 * (See <a class="doclink" href="package-summary.html#PojosConvertableFromString">POJOs Convertible From Strings</a>).
+	 * Similar to {@link #get(String,Class)} but allows for complex collections of POJOs to be created.
 	 * 
 	 * <h5 class='section'>Examples:</h5>
 	 * <p class='bcode'>
@@ -302,15 +317,25 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * 	List&lt;String&gt; myheader = req.getHeader(<js>"My-Header"</js>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
 	 * </p>
 	 * 
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li><code>Collections</code> must be followed by zero or one parameter representing the value type.
+	 * 	<li><code>Maps</code> must be followed by zero or two parameters representing the key and value types.
+	 * 	<li>If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string.
+	 * </ul>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link RestContext#REST_partParser}
+	 * </ul>
+	 * 
 	 * @param name The HTTP header name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @param <T> The class type to convert the header value to.
 	 * @return The parameter value converted to the specified class type.
@@ -325,17 +350,15 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string header.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name 
 	 * 	The HTTP header name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @param <T> The class type to convert the header value to.
 	 * @return The parameter value converted to the specified class type.
@@ -352,7 +375,7 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	}
 
 	/**
-	 * Returns a copy of this object, but only with the specified header names copied.
+	 * Returns a copy of this object but only with the specified header names copied.
 	 * 
 	 * @param headers The headers to include in the copy.
 	 * @return A new headers object.
@@ -366,7 +389,7 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	}
 
 	/**
-	 * Same as {@link #subset(String...)}, but allows you to specify header names as a comma-delimited list.
+	 * Same as {@link #subset(String...)} but allows you to specify header names as a comma-delimited list.
 	 * 
 	 * @param headers The headers to include in the copy.
 	 * @return A new headers object.
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java
index eec2bc3..6372467 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java
@@ -109,30 +109,31 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	}
 
 	/**
-	 * Returns the specified path parameter converted to a POJO.
-	 * 
-	 * <p>
-	 * The type can be any POJO type convertible from a <code>String</code> (See <a class="doclink"
-	 * href="package-summary.html#PojosConvertibleFromString">POJOs Convertible From Strings</a>).
+	 * Returns the specified path parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
 	 * 
 	 * <h5 class='section'>Examples:</h5>
 	 * <p class='bcode'>
 	 * 	<jc>// Parse into an integer.</jc>
-	 * 	<jk>int</jk> myparam = req.getPathParameter(<js>"myparam"</js>, <jk>int</jk>.<jk>class</jk>);
+	 * 	<jk>int</jk> myparam = path.get(<js>"myparam"</js>, <jk>int</jk>.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into an int array.</jc>
-	 * 	<jk>int</jk>[] myparam = req.getPathParameter(<js>"myparam"</js>, <jk>int</jk>[].<jk>class</jk>);
+	 * 	<jk>int</jk>[] myparam = path.get(<js>"myparam"</js>, <jk>int</jk>[].<jk>class</jk>);
 
 	 * 	<jc>// Parse into a bean.</jc>
-	 * 	MyBean myparam = req.getPathParameter(<js>"myparam"</js>, MyBean.<jk>class</jk>);
+	 * 	MyBean myparam = path.get(<js>"myparam"</js>, MyBean.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a linked-list of objects.</jc>
-	 * 	List myparam = req.getPathParameter(<js>"myparam"</js>, LinkedList.<jk>class</jk>);
+	 * 	List myparam = path.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a map of object keys/values.</jc>
-	 * 	Map myparam = req.getPathParameter(<js>"myparam"</js>, TreeMap.<jk>class</jk>);
+	 * 	Map myparam = path.get(<js>"myparam"</js>, TreeMap.<jk>class</jk>);
 	 * </p>
 	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link RestContext#REST_partParser}
+	 * </ul>
+	 * 
 	 * @param name The attribute name.
 	 * @param type The class type to convert the attribute value to.
 	 * @param <T> The class type to convert the attribute value to.
@@ -148,7 +149,7 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The attribute name.
 	 * @param type The class type to convert the attribute value to.
 	 * @param <T> The class type to convert the attribute value to.
@@ -160,11 +161,10 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	}
 
 	/**
-	 * Returns the specified path parameter converted to a POJO.
+	 * Returns the specified query parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
 	 * 
 	 * <p>
-	 * The type can be any POJO type convertible from a <code>String</code> (See <a class="doclink"
-	 * href="package-summary.html#PojosConvertibleFromString">POJOs Convertible From Strings</a>).
+	 * Similar to {@link #get(String,Class)} but allows for complex collections of POJOs to be created.
 	 * 
 	 * <p>
 	 * Use this method if you want to parse into a parameterized <code>Map</code>/<code>Collection</code> object.
@@ -184,15 +184,24 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * 	Map&lt;String,List&lt;MyBean&gt;&gt; myparam = req.getPathParameter(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
 	 * </p>
 	 * 
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li><code>Collections</code> must be followed by zero or one parameter representing the value type.
+	 * 	<li><code>Maps</code> must be followed by zero or two parameters representing the key and value types.
+	 * </ul>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link RestContext#REST_partParser}
+	 * </ul>
+	 * 
 	 * @param name The attribute name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @param <T> The class type to convert the attribute value to.
 	 * @return The attribute value converted to the specified class type.
@@ -207,16 +216,14 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The attribute name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @param <T> The class type to convert the attribute value to.
 	 * @return The attribute value converted to the specified class type.
@@ -284,12 +291,9 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * <p class='bcode'>
 	 * 	<jc>// REST method</jc>
 	 * 	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>,path=<js>"/foo/{bar}/*"</js>)
-	 * 	<jk>public</jk> String doGetById(RequestPathParams pathParams, <jk>int</jk> bar) {
-	 * 		<jk>return</jk> pathParams.getRemainder();
+	 * 	<jk>public</jk> String doGetById(RequestPathMatch path, <jk>int</jk> bar) {
+	 * 		<jk>return</jk> path.getRemainder();
 	 * 	}
-	 * 
-	 * 	<jc>// Prints "path/remainder"</jc>
-	 * 	<jk>new</jk> RestCall(servletPath + <js>"/foo/123/path/remainder"</js>).connect();
 	 * </p>
 	 * 
 	 * @return The path remainder string.
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java
index 5596489..e525a4c 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java
@@ -30,6 +30,10 @@ import org.apache.juneau.xml.*;
 /**
  * Represents the query parameters in an HTTP request.
  * 
+ * <p>
+ * Similar in functionality to the {@link HttpServletRequest#getParameter(String)} except only looks in the URL string, not parameters from
+ * URL-Encoded FORM posts.
+ * <br>This can be useful in cases where you're using GET parameters on FORM POSTs, and you don't want the body of the request to be read.
  * 
  * <h5 class='section'>Documentation:</h5>
  * <ul>
@@ -53,7 +57,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 		return this;
 	}
 
-	/**
+	/*
 	 * Create a copy of the request query parameters.
 	 */
 	RequestQuery copy() {
@@ -66,9 +70,11 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * Adds default entries to these query parameters.
 	 * 
 	 * <p>
-	 * This includes the default queries defined on the servlet and method levels.
+	 * This includes the default queries defined at the resource and method levels.
 	 * 
-	 * @param defaultEntries The default entries.  Can be <jk>null</jk>.
+	 * @param defaultEntries 
+	 * 	The default entries.  
+	 * 	<br>Can be <jk>null</jk>.
 	 * @return This object (for method chaining).
 	 */
 	public RequestQuery addDefault(Map<String,Object> defaultEntries) {
@@ -85,31 +91,50 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	}
 
 	/**
-	 * Sets a request query parameter value.
+	 * Adds a default entries to these query parameters.
 	 * 
-	 * @param name The parameter name.
-	 * @param value The parameter value.
+	 * <p>
+	 * Similar to {@link #put(String, Object)} but doesn't override existing values.
+	 * 
+	 * @param name 
+	 * 	The query parameter name.  
+	 * @param value
+	 * 	The query parameter value.  
+	 * 	<br>Converted to a String using <code>toString()</code>.
+	 * 	<br>Ignored if value is <jk>null</jk> or blank.
+	 * @return This object (for method chaining).
 	 */
-	public void put(String name, Object value) {
-		put(name, new String[]{StringUtils.toString(value)});
+	public RequestQuery addDefault(String name, Object value) {
+		return addDefault(Collections.singletonMap(name, value));
 	}
 
 	/**
-	 * Returns a query parameter value.
+	 * Sets a request query parameter value.
 	 * 
 	 * <p>
-	 * Same as {@link HttpServletRequest#getParameter(String)} except only looks in the URL string, not parameters from
-	 * URL-Encoded FORM posts.
+	 * This overwrites any existing value.
 	 * 
-	 * <p>
-	 * This method can be used to retrieve a parameter without triggering the underlying servlet API to load and parse
-	 * the request body.
+	 * @param name The parameter name.
+	 * @param value 
+	 * 	The parameter value.
+	 * 	<br>Can be <jk>null</jk>.
+	 */
+	public void put(String name, Object value) {
+		if (value == null)
+			put(name, null);
+		else
+			put(name, new String[]{StringUtils.toString(value)});
+	}
+
+	/**
+	 * Returns a query parameter value as a string.
 	 * 
 	 * <p>
 	 * If multiple query parameters have the same name, this returns only the first instance.
 	 * 
 	 * @param name The URL parameter name.
-	 * @return The parameter value, or <jk>null</jk> if parameter not specified or has no value (e.g. <js>"&amp;foo"</js>.
+	 * @return 
+	 * 	The parameter value, or <jk>null</jk> if parameter not specified or has no value (e.g. <js>"&amp;foo"</js>).
 	 */
 	public String getString(String name) {
 		String[] v = get(name);
@@ -132,8 +157,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @param name The URL parameter name.
 	 * @param def The default value.
 	 * @return
-	 * 	The parameter value, or the default value if parameter not specified or has no value
-	 * 	(e.g. <js>"&amp;foo"</js>.
+	 * 	The parameter value, or the default value if parameter not specified or has no value (e.g. <js>"&amp;foo"</js>).
 	 */
 	public String getString(String name, String def) {
 		String s = getString(name);
@@ -145,8 +169,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param name The URL parameter name.
 	 * @return
-	 * 	The parameter value, or <code>0</code> if parameter not specified or has no value
-	 * 	(e.g. <js>"&amp;foo"</js>.
+	 * 	The parameter value, or <code>0</code> if parameter not specified or has no value (e.g. <js>"&amp;foo"</js>).
 	 */
 	public int getInt(String name) {
 		return getInt(name, 0);
@@ -158,8 +181,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @param name The URL parameter name.
 	 * @param def The default value.
 	 * @return
-	 * 	The parameter value, or the default value if parameter not specified or has no value
-	 * 	(e.g. <js>"&amp;foo"</js>.
+	 * 	The parameter value, or the default value if parameter not specified or has no value (e.g. <js>"&amp;foo"</js>).
 	 */
 	public int getInt(String name, int def) {
 		String s = getString(name);
@@ -171,8 +193,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param name The URL parameter name.
 	 * @return
-	 * 	The parameter value, or <jk>false</jk> if parameter not specified or has no value
-	 * 	(e.g. <js>"&amp;foo"</js>.
+	 * 	The parameter value, or <jk>false</jk> if parameter not specified or has no value (e.g. <js>"&amp;foo"</js>).
 	 */
 	public boolean getBoolean(String name) {
 		return getBoolean(name, false);
@@ -184,8 +205,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @param name The URL parameter name.
 	 * @param def The default value.
 	 * @return
-	 * 	The parameter value, or the default value if parameter not specified or has no value
-	 * 	(e.g. <js>"&amp;foo"</js>.
+	 * 	The parameter value, or the default value if parameter not specified or has no value (e.g. <js>"&amp;foo"</js>).
 	 */
 	public boolean getBoolean(String name, boolean def) {
 		String s = getString(name);
@@ -193,30 +213,31 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	}
 
 	/**
-	 * Returns the specified query parameter value converted to a POJO.
-	 * 
-	 * <p>
-	 * This method can be used to retrieve a parameter without triggering the underlying servlet API to load and parse
-	 * the request body.
+	 * Returns the specified query parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
 	 * 
 	 * <h5 class='section'>Examples:</h5>
 	 * <p class='bcode'>
 	 * 	<jc>// Parse into an integer.</jc>
-	 * 	<jk>int</jk> myparam = req.getQueryParameter(<js>"myparam"</js>, <jk>int</jk>.<jk>class</jk>);
+	 * 	<jk>int</jk> myparam = query.get(<js>"myparam"</js>, <jk>int</jk>.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into an int array.</jc>
-	 * 	<jk>int</jk>[] myparam = req.getQueryParameter(<js>"myparam"</js>, <jk>int</jk>[].<jk>class</jk>);
+	 * 	<jk>int</jk>[] myparam = query.get(<js>"myparam"</js>, <jk>int</jk>[].<jk>class</jk>);
 
 	 * 	<jc>// Parse into a bean.</jc>
-	 * 	MyBean myparam = req.getQueryParameter(<js>"myparam"</js>, MyBean.<jk>class</jk>);
+	 * 	MyBean myparam = query.get(<js>"myparam"</js>, MyBean.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a linked-list of objects.</jc>
-	 * 	List myparam = req.getQueryParameter(<js>"myparam"</js>, LinkedList.<jk>class</jk>);
+	 * 	List myparam = query.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a map of object keys/values.</jc>
-	 * 	Map myparam = req.getQueryParameter(<js>"myparam"</js>, TreeMap.<jk>class</jk>);
+	 * 	Map myparam = query.get(<js>"myparam"</js>, TreeMap.<jk>class</jk>);
 	 * </p>
 	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link RestContext#REST_partParser}
+	 * </ul>
+	 * 
 	 * @param name The parameter name.
 	 * @param type The class type to convert the parameter value to.
 	 * @param <T> The class type to convert the parameter value to.
@@ -232,7 +253,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The parameter name.
 	 * @param type The class type to convert the parameter value to.
 	 * @param <T> The class type to convert the parameter value to.
@@ -262,7 +283,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The parameter name.
 	 * @param def The default value if the parameter was not specified or is <jk>null</jk>.
 	 * @param type The class type to convert the parameter value to.
@@ -275,39 +296,44 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	}
 
 	/**
-	 * Returns the specified query parameter value converted to a POJO.
-	 * 
-	 * <p>
-	 * This method can be used to retrieve a parameter without triggering the underlying servlet API to load and parse
-	 * the request body.
+	 * Returns the specified query parameter value converted to a POJO using the {@link HttpPartParser} registered with the resource.
 	 * 
 	 * <p>
-	 * Use this method if you want to parse into a parameterized <code>Map</code>/<code>Collection</code> object.
+	 * Similar to {@link #get(String,Class)} but allows for complex collections of POJOs to be created.
 	 * 
 	 * <h5 class='section'>Examples:</h5>
 	 * <p class='bcode'>
 	 * 	<jc>// Parse into a linked-list of strings.</jc>
-	 * 	List&lt;String&gt; myparam = req.getQueryParameter(<js>"myparam"</js>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
+	 * 	List&lt;String&gt; myparam = query.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a linked-list of linked-lists of strings.</jc>
-	 * 	List&lt;List&lt;String&gt;&gt; myparam = req.getQueryParameter(<js>"myparam"</js>, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
+	 * 	List&lt;List&lt;String&gt;&gt; myparam = query.get(<js>"myparam"</js>, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a map of string keys/values.</jc>
-	 * 	Map&lt;String,String&gt; myparam = req.getQueryParameter(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
+	 * 	Map&lt;String,String&gt; myparam = query.get(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
 	 * 
 	 * 	<jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
-	 * 	Map&lt;String,List&lt;MyBean&gt;&gt; myparam = req.getQueryParameter(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
+	 * 	Map&lt;String,List&lt;MyBean&gt;&gt; myparam = query.get(<js>"myparam"</js>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
 	 * </p>
 	 * 
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li><code>Collections</code> must be followed by zero or one parameter representing the value type.
+	 * 	<li><code>Maps</code> must be followed by zero or two parameters representing the key and value types.
+	 * </ul>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link RestContext#REST_partParser}
+	 * </ul>
+	 * 
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @param <T> The class type to convert the parameter value to.
 	 * @return The parameter value converted to the specified class type.
@@ -322,17 +348,15 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * 
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @param <T> The class type to convert the parameter value to.
 	 * @return The parameter value converted to the specified class type.
@@ -348,12 +372,10 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @param def The default value if the parameter was not specified or is <jk>null</jk>.
 	 * @param <T> The class type to convert the parameter value to.
@@ -369,16 +391,14 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The parameter name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @param def The default value if the parameter was not specified or is <jk>null</jk>.
 	 * @param <T> The class type to convert the parameter value to.
@@ -391,7 +411,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 
 	/**
 	 * Same as {@link #get(String, Class)} except for use on multi-part parameters
-	 * (e.g. <js>"&amp;key=1&amp;key=2&amp;key=3"</js> instead of <js>"&amp;key=(1,2,3)"</js>).
+	 * (e.g. <js>"&amp;key=1&amp;key=2&amp;key=3"</js> instead of <js>"&amp;key=@(1,2,3)"</js>).
 	 * 
 	 * <p>
 	 * This method must only be called when parsing into classes of type Collection or array.
@@ -408,7 +428,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 
 	/**
 	 * Same as {@link #get(String, Type, Type...)} except for use on multi-part parameters
-	 * (e.g. <js>"&amp;key=1&amp;key=2&amp;key=3"</js> instead of <js>"&amp;key=(1,2,3)"</js>).
+	 * (e.g. <js>"&amp;key=1&amp;key=2&amp;key=3"</js> instead of <js>"&amp;key=@(1,2,3)"</js>).
 	 * 
 	 * <p>
 	 * This method must only be called when parsing into classes of type Collection or array.
@@ -416,12 +436,10 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @param name The query parameter name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @param <T> The class type to convert the parameter value to.
 	 * @return The query parameter value converted to the specified class type.
@@ -436,16 +454,14 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * 
 	 * @param parser
 	 * 	The parser to use for parsing the string value.
-	 * 	<br>If <jk>null</jk>, uses the part parser defined on the servlet/method. 
+	 * 	<br>If <jk>null</jk>, uses the part parser defined on the resource/method. 
 	 * @param name The query parameter name.
 	 * @param type
 	 * 	The type of object to create.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * @param args
 	 * 	The type arguments of the class if it's a collection or map.
-	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType},
-	 * 	{@link GenericArrayType}
+	 * 	<br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
 	 * 	<br>Ignored if the main type is not a map or collection.
 	 * @param <T> The class type to convert the parameter value to.
 	 * @return The query parameter value converted to the specified class type.
@@ -473,7 +489,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * 
 	 * <p>
 	 * The query arguments are as follows:
-	 * <ul>
+	 * <ul class='spaced-list'>
 	 * 	<li>
 	 * 		<js>"&amp;s="</js> - A comma-delimited list of column-name/search-token pairs.
 	 * 		<br>Example: <js>"&amp;s=column1=foo*,column2=*bar"</js>
@@ -496,12 +512,14 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * 		<br>Example: <js>"&amp;i=true"</js>
 	 * </ul>
 	 * 
-	 * <p>
-	 * Whitespace is trimmed in the parameters.
+	 * <h5 class='section'>Notes:</h5>
+	 * <ul>
+	 * 	<li>Whitespace is trimmed in the parameters.
+	 * </ul>
 	 * 
 	 * @return
 	 * 	A new {@link SearchArgs} object initialized with the special search query arguments.
-	 * 	<jk>null</jk> if no search arguments were found.
+	 * 	<br>Returns <jk>null</jk> if no search arguments were found.
 	 */
 	public SearchArgs getSearchArgs() {
 		if (hasAny("s","v","o","p","l","i")) {
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index adcd3c9..3d0298a 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -3226,7 +3226,7 @@ public final class RestContext extends BeanContext {
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
 	 * 	<li class='jm'>{@link org.apache.juneau.rest.RestContextBuilder#vars(Class...)} - For adding custom vars.
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.SvlVariables">Overview &gt; SVL Variables</a
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.SvlVariables">Overview &gt; SVL Variables</a>
 	 * </ul>
 	 * 
 	 * @return The var resolver in use by this resource.
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
index 8ce396a..09e56cf 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -271,7 +271,8 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Properties">Overview &gt; Properties</a
+	 * 	<li class='jm'>{@link #prop(String, Object)}
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Properties">Overview &gt; Properties</a>
 	 * </ul>
 	 * 
 	 * @return The properties active for this request.
@@ -332,7 +333,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestHeaders">Overview &gt; RequestHeaders</a
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestHeaders">Overview &gt; RequestHeaders</a>
 	 * </ul>
 	 * 
 	 * @return 
@@ -471,7 +472,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestQuery">Overview &gt; RequestQuery</a
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestQuery">Overview &gt; RequestQuery</a>
 	 * </ul>
 	 * 
 	 * @return 
@@ -531,7 +532,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestFormData">Overview &gt; RequestFormData</a
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestFormData">Overview &gt; RequestFormData</a>
 	 * </ul>
 	 * 
 	 * @return 
@@ -609,7 +610,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestPathMatch">Overview &gt; RequestPathMatch</a
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestPathMatch">Overview &gt; RequestPathMatch</a>
 	 * </ul>
 	 * 
 	 * @return 
@@ -659,7 +660,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestBody">Overview &gt; RequestBody</a
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestBody">Overview &gt; RequestBody</a>
 	 * </ul>
 	 * 
 	 * @return 
@@ -836,7 +837,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 	<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getResourceDescription()}
 	 * 	<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMethodSummary()}
 	 * 	<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getMethodDescription()}
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.OptionsPages">Overview &gt; OPTIONS Pages</a
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.OptionsPages">Overview &gt; OPTIONS Pages</a>
 	 * </ul>
 	 * 
 	 * @return 
@@ -871,7 +872,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 	<li class='jf'>{@link org.apache.juneau.rest.RestContext#REST_infoProvider}
 	 * 	<li class='jic'>{@link org.apache.juneau.rest.RestInfoProvider}
 	 * 	<li class='jm'>{@link org.apache.juneau.rest.RestRequest#getInfoProvider()}
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.OptionsPages">Overview &gt; OPTIONS Pages</a
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.OptionsPages">Overview &gt; OPTIONS Pages</a>
 	 * </ul>
 	 * 
 	 * @return
@@ -1002,6 +1003,11 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	/**
 	 * Returns the serializers associated with this request.
 	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Serializers">Overview &gt; Serializers</a>
+	 * </ul>
+	 * 
 	 * @return The serializers associated with this request.
 	 */
 	public SerializerGroup getSerializers() {
@@ -1011,6 +1017,11 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	/**
 	 * Returns the parsers associated with this request.
 	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Parsers">Overview &gt; Parsers</a>
+	 * </ul>
+	 * 
 	 * @return The parsers associated with this request.
 	 */
 	public ParserGroup getParsers() {
@@ -1182,7 +1193,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
 	 * 	<li class='jm'>{@link org.apache.juneau.rest.RestContext#getVarResolver()}
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.SvlVariables">Overview &gt; SVL Variables</a
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.SvlVariables">Overview &gt; SVL Variables</a>
 	 * </ul>
 	 * 
 	 * @return The variable resolver for this request.
@@ -1228,7 +1239,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 		String s = context.getClasspathResourceAsString(name, getLocale());
 		if (s == null)
 			return null;
-		ReaderResource.Builder b = new ReaderResource.Builder().mediaType(mediaType).contents(s);
+		ReaderResourceBuilder b = new ReaderResourceBuilder().mediaType(mediaType).contents(s);
 		if (resolveVars)
 			b.varResolver(getVarResolverSession());
 		return b.build();
@@ -1296,7 +1307,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.ConfigurationFiles">Overview &gt; Configuration Files</a
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.ConfigurationFiles">Overview &gt; Configuration Files</a>
 	 * </ul>
 	 * 
 	 * @return
@@ -1374,7 +1385,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	 * 	<li class='jac'>{@link org.apache.juneau.rest.RestLogger}
 	 * 	<li class='jm'>{@link org.apache.juneau.rest.RestServlet#log(Level, String, Object...)}
 	 * 	<li class='jm'>{@link org.apache.juneau.rest.RestServlet#logObjects(Level, String, Object...)}
-	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.LoggingAndErrorHandling">Overview &gt; Logging and Error Handling</a
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.LoggingAndErrorHandling">Overview &gt; Logging and Error Handling</a>
 	 * </ul>
 	 * 
 	 * @return 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
index 220dd58..7069b34 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
@@ -24,6 +24,7 @@ import org.apache.juneau.encoders.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
+import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.serializer.*;
 
 /**
@@ -41,8 +42,7 @@ import org.apache.juneau.serializer.*;
  * <p class='bcode'>
  * 	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
  * 	<jk>public void</jk> doGet(RestRequest req, RestResponse res) {
- * 		res.setPageTitle(<js>"My title"</js>)
- * 			.setOutput(<js>"Simple string response"</js>);
+ * 		res.setOutput(<js>"Simple string response"</js>);
  * 	}
  * </p>
  * 
@@ -118,9 +118,14 @@ public final class RestResponse extends HttpServletResponseWrapper {
 	/**
 	 * Gets the serializer group for the response.
 	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Serializers">Overview &gt; Serializers</a>
+	 * </ul>
+	 * 
 	 * @return The serializer group for the response.
 	 */
-	public SerializerGroup getSerializerGroup() {
+	public SerializerGroup getSerializers() {
 		return restJavaMethod.serializers;
 	}
 
@@ -148,20 +153,33 @@ public final class RestResponse extends HttpServletResponseWrapper {
 	 * Sets the HTTP output on the response.
 	 * 
 	 * <p>
-	 * Calling this method is functionally equivalent to returning the object in the REST Java method.
+	 * The object type can be anything allowed by the registered response handlers.
 	 * 
 	 * <p>
-	 * Can be of any of the following types:
+	 * Calling this method is functionally equivalent to returning the object in the REST Java method.
+	 * 
+	 * <h5 class='section'>Example:</h5>
+	 * <p class='bcode'>
+	 * 	<ja>@RestMethod</ja>(..., path=<js>"/example2/{personId}"</js>)
+	 * 	<jk>public void</jk> doGet2(RestResponse res, <ja>@Path</ja> UUID personId) {
+	 * 		Person p = getPersonById(personId);
+	 * 		res.setOutput(p);
+	 * 	}
+	 * </p>
+	 * 
+	 * <h5 class='section'>Notes:</h5>
 	 * <ul>
-	 * 	<li> {@link InputStream}
-	 * 	<li> {@link Reader}
-	 * 	<li> Any serializable type defined in <a class="doclink"
-	 * 		href="../../../../overview-summary.html#juneau-marshall.PojoCategories">POJO Categories</a>
+	 * 	<li>Calling this method with a <jk>null</jk> value is NOT the same as not calling this method at all.
+	 * 		<br>A <jk>null</jk> output value means we want to serialize <jk>null</jk> as a response (e.g. as a JSON <code>null</code>).
+	 * 		<br>Not calling this method or returning a value means you're handing the response yourself via the underlying stream or writer.
+	 * 		<br>This distinction affects the {@link #hasOutput()} method behavior.
 	 * </ul>
 	 * 
-	 * <p>
-	 * If it's an {@link InputStream} or {@link Reader}, you must also specify the <code>Content-Type</code> using the
-	 * {@link #setContentType(String)} method.
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link RestContext#REST_responseHandlers}
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.MethodReturnTypes">Overview &gt; Method Return Types</a>
+	 * </ul>
 	 * 
 	 * @param output The output to serialize to the connection.
 	 * @return This object (for method chaining).
@@ -175,6 +193,37 @@ public final class RestResponse extends HttpServletResponseWrapper {
 	/**
 	 * Returns a programmatic interface for setting properties for the HTML doc view.
 	 * 
+	 * <p>
+	 * This is the programmatic equivalent to the {@link RestMethod#htmldoc() @RestMethod.htmldoc()} annotation.
+	 * 
+	 * <h5 class='section'>Example:</h5>
+	 * <p class='bcode'>
+	 * 	<jc>// Declarative approach.</jc>
+	 * 	<ja>@RestMethod</ja>(
+	 * 		htmldoc=<ja>@HtmlDoc</ja>(
+	 * 			header={
+	 * 				<js>"&lt;p&gt;This is my REST interface&lt;/p&gt;"</js>
+	 * 			},
+	 * 			aside={
+	 * 				<js>"&lt;p&gt;Custom aside content&lt;/p&gt;"</js>
+	 * 			}
+	 * 		)
+	 * 	)
+	 * 	<jk>public</jk> Object doGet(RestResponse res) {
+	 * 		
+	 * 		<jc>// Equivalent programmatic approach.</jc>
+	 * 		res.getHtmlDocBuilder()
+	 * 			.header(<js>"&lt;p&gt;This is my REST interface&lt;/p&gt;"</js>)
+	 * 			.aside(<js>"&lt;p&gt;Custom aside content&lt;/p&gt;"</js>);
+	 * 	}
+	 * </p>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='ja'>{@link RestMethod#htmldoc()}
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.HtmlDocAnnotation">Overview &gt; @HtmlDoc</a>
+	 * </ul>
+	 * 
 	 * @return A new programmatic interface for setting properties for the HTML doc view.
 	 */
 	public HtmlDocBuilder getHtmlDocBuilder() {
@@ -184,24 +233,45 @@ public final class RestResponse extends HttpServletResponseWrapper {
 	}
 
 	/**
-	 * Add a serializer property to send to the serializers to override a default value.
+	 * Retrieve the properties active for this request.
 	 * 
 	 * <p>
-	 * Can be any value specified on any of the serializers or parsers.
+	 * This contains all resource and method level properties from the following:
+	 * <ul>
+	 * 	<li class='ja'>{@link RestResource#properties()}
+	 * 	<li class='ja'>{@link RestMethod#properties()}
+	 * 	<li class='jm'>{@link RestContextBuilder#set(String, Object)}
+	 * </ul>
 	 * 
-	 * @param key The setting name.
-	 * @param value The setting value.
-	 * @return This object (for method chaining).
-	 */
-	public RestResponse setProperty(String key, Object value) {
-		properties.put(key, value);
-		return this;
-	}
-
-	/**
-	 * Returns the properties set via {@link #setProperty(String, Object)}.
+	 * <p>
+	 * The returned object is modifiable and allows you to override session-level properties before
+	 * they get passed to the serializers.
+	 * <br>However, properties are open-ended, and can be used for any purpose.
 	 * 
-	 * @return A map of all the property values set.
+	 * <h5 class='section'>Example:</h5>
+	 * <p class='bcode'>
+	 * 	<ja>@RestMethod</ja>(
+	 * 		properties={
+	 * 			<ja>@Property</ja>(name=<jsf>SERIALIZER_sortMaps</jsf>, value=<js>"false"</js>)
+	 * 		}
+	 * 	)
+	 * 	<jk>public</jk> Map doGet(RestResponse res, <ja>@Query</ja>(<js>"sortMaps"</js>) Boolean sortMaps) {
+	 * 		
+	 * 		<jc>// Override value if specified through query parameter.</jc>
+	 * 		<jk>if</jk> (sortMaps != <jk>null</jk>)
+	 * 			res.getProperties().put(<jsf>SERIALIZER_sortMaps</jsf>, sortMaps);
+	 * 
+	 * 		<jk>return</jk> <jsm>getMyMap</jsm>();
+	 * 	}
+	 * </p>
+	 * 
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jm'>{@link #prop(String, Object)}
+	 * 	<li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.Properties">Overview &gt; Properties</a>
+	 * </ul>
+	 * 
+	 * @return The properties active for this request.
 	 */
 	public RequestProperties getProperties() {
 		return properties;
@@ -251,7 +321,7 @@ public final class RestResponse extends HttpServletResponseWrapper {
 	/**
 	 * Returns <jk>true</jk> if this response has any output associated with it.
 	 * 
-	 * @return <jk>true</jk> if {@code setInput()} has been called.
+	 * @return <jk>true</jk> if {@link #setOutput(Object)} has been called, even if the value passed was <jk>null</jk>.
 	 */
 	public boolean hasOutput() {
 		return output != null || isNullOutput;
@@ -372,6 +442,9 @@ public final class RestResponse extends HttpServletResponseWrapper {
 	 * Sets the header <js>"x-content-type-options=nosniff"</js> so that output is rendered immediately on IE and Chrome
 	 * without any buffering for content-type sniffing.
 	 * 
+	 * <p>
+	 * This can be useful if you want to render a streaming 'console' on a web page.
+	 * 
 	 * @param contentType The value to set as the <code>Content-Type</code> on the response.
 	 * @return The raw writer.
 	 * @throws IOException
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java
index b8668c4..6d6f075 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java
@@ -19,20 +19,21 @@ import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.*;
-import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.response.*;
 
 /**
  * Represents the contents of a byte stream file with convenience methods for adding HTTP response headers.
  * 
  * <p>
- * The purpose of this class is to maintain an in-memory reusable byte array of a streamed resource for the fastest
- * possible streaming.
- * Therefore, this object is designed to be reused and thread-safe.
+ * This class is handled special by the {@link StreamableHandler} class.
+ * <br>This allows these objects to be returned as responses by REST methods.
  * 
  * <p>
- * This class is handled special by the {@link StreamableHandler} class.
- * This allows these objects to be returned as responses by REST methods.
+ * <l>StreamResources</l> are meant to be thread-safe and reusable objects.
+ * <br>The contents of the request passed into the constructor are immediately converted to read-only byte arrays.
+ * 
+ * <p>
+ * Instances of this class can be built using {@link StreamResourceBuilder}.
  * 
  * 
  * <h5 class='section'>Documentation:</h5>
@@ -44,29 +45,17 @@ public class StreamResource implements Streamable {
 
 	private final MediaType mediaType;
 	private final byte[][] contents;
-	private final Map<String,String> headers;
+	private final Map<String,Object> headers;
 
 	/**
-	 * Constructor.
+	 * Creates a new instance of a {@link StreamResourceBuilder}
 	 * 
-	 * @param mediaType The resource media type.
-	 * @param contents
-	 * 	The resource contents.
-	 * 	<br>If multiple contents are specified, the results will be concatenated.
-	 * 	<br>Contents can be any of the following:
-	 * 	<ul>
-	 * 		<li><code><jk>byte</jk>[]</code>
-	 * 		<li><code>InputStream</code>
-	 * 		<li><code>Reader</code> - Converted to UTF-8 bytes.
-	 * 		<li><code>File</code>
-	 * 		<li><code>CharSequence</code> - Converted to UTF-8 bytes.
-	 * 	</ul>
-	 * @throws IOException
+	 * @return A new instance of a {@link StreamResourceBuilder}
 	 */
-	public StreamResource(MediaType mediaType, Object...contents) throws IOException {
-		this(mediaType, null, contents);
+	public static StreamResourceBuilder create() {
+		return new StreamResourceBuilder();
 	}
-
+	
 	/**
 	 * Constructor.
 	 * 
@@ -88,11 +77,7 @@ public class StreamResource implements Streamable {
 	public StreamResource(MediaType mediaType, Map<String,Object> headers, Object...contents) throws IOException {
 		this.mediaType = mediaType;
 
-		Map<String,String> m = new LinkedHashMap<>();
-		if (headers != null)
-			for (Map.Entry<String,Object> e : headers.entrySet())
-				m.put(e.getKey(), StringUtils.toString(e.getValue()));
-		this.headers = Collections.unmodifiableMap(m);
+		this.headers = headers == null ? Collections.EMPTY_MAP : Collections.unmodifiableMap(new LinkedHashMap<>(headers));
 
 		this.contents = new byte[contents.length][];
 		for (int i = 0; i < contents.length; i++) {
@@ -115,100 +100,14 @@ public class StreamResource implements Streamable {
 	}
 
 	/**
-	 * Builder class for constructing {@link StreamResource} objects.
-	 */
-	public static final class Builder {
-		ArrayList<Object> contents = new ArrayList<>();
-		MediaType mediaType;
-		Map<String,String> headers = new LinkedHashMap<>();
-
-		/**
-		 * Specifies the resource media type string.
-		 * 
-		 * @param mediaType The resource media type string.
-		 * @return This object (for method chaining).
-		 */
-		public Builder mediaType(String mediaType) {
-			this.mediaType = MediaType.forString(mediaType);
-			return this;
-		}
-
-		/**
-		 * Specifies the resource media type string.
-		 * 
-		 * @param mediaType The resource media type string.
-		 * @return This object (for method chaining).
-		 */
-		public Builder mediaType(MediaType mediaType) {
-			this.mediaType = mediaType;
-			return this;
-		}
-
-		/**
-		 * Specifies the contents for this resource.
-		 * 
-		 * <p>
-		 * This method can be called multiple times to add more content.
-		 * 
-		 * @param contents
-		 * 	The resource contents.
-		 * 	<br>If multiple contents are specified, the results will be concatenated.
-		 * 	<br>Contents can be any of the following:
-		 * 	<ul>
-		 * 		<li><code><jk>byte</jk>[]</code>
-		 * 		<li><code>InputStream</code>
-		 * 		<li><code>Reader</code> - Converted to UTF-8 bytes.
-		 * 		<li><code>File</code>
-		 * 		<li><code>CharSequence</code> - Converted to UTF-8 bytes.
-		 * 	</ul>
-		 * @return This object (for method chaining).
-		 */
-		public Builder contents(Object...contents) {
-			this.contents.addAll(Arrays.asList(contents));
-			return this;
-		}
-
-		/**
-		 * Specifies an HTTP response header value.
-		 * 
-		 * @param name The HTTP header name.
-		 * @param value The HTTP header value.  Will be converted to a <code>String</code> using {@link Object#toString()}.
-		 * @return This object (for method chaining).
-		 */
-		public Builder header(String name, Object value) {
-			this.headers.put(name, StringUtils.toString(value));
-			return this;
-		}
-
-		/**
-		 * Specifies HTTP response header values.
-		 * 
-		 * @param headers The HTTP headers.  Values will be converted to <code>Strings</code> using {@link Object#toString()}.
-		 * @return This object (for method chaining).
-		 */
-		public Builder headers(Map<String,Object> headers) {
-			for (Map.Entry<String,Object> e : headers.entrySet())
-				header(e.getKey(), e.getValue());
-			return this;
-		}
-
-		/**
-		 * Create a new {@link StreamResource} using values in this builder.
-		 * 
-		 * @return A new immutable {@link StreamResource} object.
-		 * @throws IOException
-		 */
-		public StreamResource build() throws IOException {
-			return new StreamResource(mediaType, headers, contents.toArray());
-		}
-	}
-
-	/**
 	 * Get the HTTP response headers.
 	 * 
-	 * @return The HTTP response headers.  An unmodifiable map.  Never <jk>null</jk>.
+	 * @return 
+	 * 	The HTTP response headers.  
+	 * 	<br>An unmodifiable map.  
+	 * 	<br>Never <jk>null</jk>.
 	 */
-	public Map<String,String> getHeaders() {
+	public Map<String,Object> getHeaders() {
 		return headers;
 	}
 
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResourceBuilder.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResourceBuilder.java
new file mode 100644
index 0000000..f92b8be
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResourceBuilder.java
@@ -0,0 +1,116 @@
+// ***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                                                              * 
+// *                                                                                                                         *
+// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
+// *                                                                                                                         *
+// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the License.                                              *
+// ***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.http.*;
+
+/**
+ * Builder class for constructing {@link StreamResource} objects.
+ * 
+ * 
+ * <h5 class='section'>Documentation:</h5>
+ * <ul>
+ * 	<li><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.StreamResource">Overview &gt; StreamResource</a>
+ * </ul>
+ */
+public final class StreamResourceBuilder {
+	ArrayList<Object> contents = new ArrayList<>();
+	MediaType mediaType;
+	Map<String,Object> headers = new LinkedHashMap<>();
+
+	/**
+	 * Specifies the resource media type string.
+	 * 
+	 * @param mediaType The resource media type string.
+	 * @return This object (for method chaining).
+	 */
+	public StreamResourceBuilder mediaType(String mediaType) {
+		this.mediaType = MediaType.forString(mediaType);
+		return this;
+	}
+
+	/**
+	 * Specifies the resource media type string.
+	 * 
+	 * @param mediaType The resource media type string.
+	 * @return This object (for method chaining).
+	 */
+	public StreamResourceBuilder mediaType(MediaType mediaType) {
+		this.mediaType = mediaType;
+		return this;
+	}
+
+	/**
+	 * Specifies the contents for this resource.
+	 * 
+	 * <p>
+	 * This method can be called multiple times to add more content.
+	 * 
+	 * @param contents
+	 * 	The resource contents.
+	 * 	<br>If multiple contents are specified, the results will be concatenated.
+	 * 	<br>Contents can be any of the following:
+	 * 	<ul>
+	 * 		<li><code><jk>byte</jk>[]</code>
+	 * 		<li><code>InputStream</code>
+	 * 		<li><code>Reader</code> - Converted to UTF-8 bytes.
+	 * 		<li><code>File</code>
+	 * 		<li><code>CharSequence</code> - Converted to UTF-8 bytes.
+	 * 	</ul>
+	 * @return This object (for method chaining).
+	 */
+	public StreamResourceBuilder contents(Object...contents) {
+		this.contents.addAll(Arrays.asList(contents));
+		return this;
+	}
+
+	/**
+	 * Specifies an HTTP response header value.
+	 * 
+	 * @param name The HTTP header name.
+	 * @param value 
+	 * 	The HTTP header value.  
+	 * 	<br>Will be converted to a <code>String</code> using {@link Object#toString()}.
+	 * @return This object (for method chaining).
+	 */
+	public StreamResourceBuilder header(String name, Object value) {
+		this.headers.put(name, value);
+		return this;
+	}
+
+	/**
+	 * Specifies HTTP response header values.
+	 * 
+	 * @param headers 
+	 * 	The HTTP headers.  
+	 * 	<br>Values will be converted to <code>Strings</code> using {@link Object#toString()}.
+	 * @return This object (for method chaining).
+	 */
+	public StreamResourceBuilder headers(Map<String,Object> headers) {
+		this.headers.putAll(headers);
+		return this;
+	}
+
+	/**
+	 * Create a new {@link StreamResource} using values in this builder.
+	 * 
+	 * @return A new immutable {@link StreamResource} object.
+	 * @throws IOException
+	 */
+	public StreamResource build() throws IOException {
+		return new StreamResource(mediaType, headers, contents.toArray());
+	}
+}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
index 72c8ba6..c0e8b8e 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResource.java
@@ -681,7 +681,7 @@ public @interface RestResource {
 	 * 
 	 * <p>
 	 * In some cases, properties can be overridden at runtime through the
-	 * {@link RestResponse#setProperty(String, Object)} method or through an {@link RequestProperties} 
+	 * {@link RestResponse#prop(String, Object)} method or through an {@link RequestProperties} 
 	 * method parameter.
 	 * 
 	 * <p>
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
index ca5bc7d..a947ba1 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
@@ -46,7 +46,7 @@ public class DefaultHandler implements ResponseHandler {
 	@SuppressWarnings("resource")
 	@Override /* ResponseHandler */
 	public boolean handle(RestRequest req, RestResponse res, Object output) throws IOException, RestException {
-		SerializerGroup g = res.getSerializerGroup();
+		SerializerGroup g = res.getSerializers();
 		String accept = req.getHeaders().getString("Accept", "");
 		SerializerMatch sm = g.getSerializerMatch(accept);
 		if (sm != null) {
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/StreamableHandler.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/StreamableHandler.java
index ca71ac1..86ad884 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/StreamableHandler.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/StreamableHandler.java
@@ -17,6 +17,7 @@ import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.*;
 
 /**
@@ -42,8 +43,8 @@ public final class StreamableHandler implements ResponseHandler {
 				MediaType mediaType = r.getMediaType();
 				if (mediaType != null)
 					res.setContentType(mediaType.toString());
-				for (Map.Entry<String,String> h : r.getHeaders().entrySet())
-					res.setHeader(h.getKey(), h.getValue());
+				for (Map.Entry<String,Object> h : r.getHeaders().entrySet())
+					res.setHeader(h.getKey(), StringUtils.toString(h.getValue()));
 			}
 			try (OutputStream os = res.getOutputStream()) {
 				((Streamable)output).streamTo(os);
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/WritableHandler.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/WritableHandler.java
index a0ae81f..4979db9 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/WritableHandler.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/WritableHandler.java
@@ -17,6 +17,7 @@ import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.*;
 
 /**
@@ -41,8 +42,8 @@ public final class WritableHandler implements ResponseHandler {
 				MediaType mediaType = r.getMediaType();
 				if (mediaType != null)
 					res.setContentType(mediaType.toString());
-				for (Map.Entry<String,String> h : r.getHeaders().entrySet())
-					res.setHeader(h.getKey(), h.getValue());
+				for (Map.Entry<String,Object> h : r.getHeaders().entrySet())
+					res.setHeader(h.getKey(), StringUtils.toString(h.getValue()));
 			}
 			try (Writer w = res.getNegotiatedWriter()) {
 				((Writable)output).writeTo(w);

-- 
To stop receiving notification emails like this one, please contact
jamesbognar@apache.org.

Mime
View raw message