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 15fa71d  Fix bugs in @Response annotation support.
15fa71d is described below

commit 15fa71d1bb2987711e649978c261a48255ca1e76
Author: JamesBognar <jamesbog...@apache.org>
AuthorDate: Sat Jul 28 14:54:55 2018 -0400

    Fix bugs in @Response annotation support.
---
 .../httppart/HttpPartSchemaTest_Response.java      |  38 --
 .../juneau/http/annotation/AnnotationUtils.java    |   1 +
 .../apache/juneau/http/annotation/RequestBean.java |   8 -
 .../apache/juneau/http/annotation/Response.java    |   2 +-
 .../org/apache/juneau/http/annotation/Schema.java  |  45 ++
 .../juneau/httppart/HttpPartSchemaBuilder.java     |   1 +
 .../httppart/OpenApiPartSerializerSession.java     |   5 +-
 .../apache/juneau/remoteable/RemoteMethodArg.java  |  10 -
 juneau-doc/src/main/javadoc/overview.html          | 351 +++++++++++++++-
 .../09.HttpPartAnnotations/08.RequestBean.html     |  54 ++-
 .../09.HttpPartAnnotations/09.Response.html        | 296 ++++++++++++-
 .../apache/juneau/rest/BasicRestCallHandler.java   | 115 +++---
 .../org/apache/juneau/rest/RestCallHandler.java    |  15 +-
 .../org/apache/juneau/rest/RestCallRouter.java     |   2 +-
 .../java/org/apache/juneau/rest/RestContext.java   |  12 +-
 .../org/apache/juneau/rest/RestContextBuilder.java |   8 +
 .../java/org/apache/juneau/rest/RestException.java |   9 +-
 .../org/apache/juneau/rest/RestJavaMethod.java     |  20 +-
 .../org/apache/juneau/rest/RestMethodReturn.java   |  38 +-
 .../org/apache/juneau/rest/RestMethodThrown.java   |  38 +-
 .../org/apache/juneau/rest/RestParamDefaults.java  |  13 +-
 .../java/org/apache/juneau/rest/RestRequest.java   |  23 ++
 .../juneau/rest/annotation/RestResource.java       |   6 +-
 .../juneau/rest/mock/MockServletRequest.java       |  36 ++
 .../juneau/rest/response/DefaultHandler.java       |  35 +-
 .../rest/annotation/ResponseAnnotationTest.java    | 458 +++++++++++++++++++++
 26 files changed, 1454 insertions(+), 185 deletions(-)

diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Response.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Response.java
index c3c0df5..03f98ad 100644
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Response.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/HttpPartSchemaTest_Response.java
@@ -52,44 +52,6 @@ public class HttpPartSchemaTest_Response {
                
assertObjectEquals("{description:'b1\\nb2',example:'f1',schema:{'$ref':'c1'},_value:'{g1:true}'}",
 s.getApi());
        }
 
-       public static class A03 {
-               public void a(
-                               @Response(
-                                       description={"b1","b2"},
-                                       schema=@Schema($ref="c1"),
-                                       example="f1",
-                                       api="{g1:true}"
-                               ) String x
-                       ) {
-
-               }
-       }
-
-       @Test
-       public void a03_basic_onParameter() throws Exception {
-               HttpPartSchema s = 
HttpPartSchema.create().apply(Response.class, A03.class.getMethod("a", 
String.class), 0).noValidate().build();
-               
assertObjectEquals("{description:'b1\\nb2',example:'f1',schema:{'$ref':'c1'},_value:'{g1:true}'}",
 s.getApi());
-       }
-
-       public static class A04 {
-               public void a(
-                               @Response(
-                                       description={"b3","b3"},
-                                       schema=@Schema($ref="c3"),
-                                       example="f2",
-                                       api="{g2:true}"
-                               ) A02 x
-                       ) {
-
-               }
-       }
-
-       @Test
-       public void a04_basic_onParameterAndClass() throws Exception {
-               HttpPartSchema s = 
HttpPartSchema.create().apply(Response.class, A04.class.getMethod("a", 
A02.class), 0).noValidate().build();
-               
assertObjectEquals("{description:'b3\\nb3',example:'f2',schema:{'$ref':'c3'},_value:'{g2:true}'}",
 s.getApi());
-       }
-
        @Response(
                schema=@Schema(
                        type="number",
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
index a4739b6..2b51f45 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/AnnotationUtils.java
@@ -90,6 +90,7 @@ public class AnnotationUtils {
                return om
                        .appendSkipEmpty("additionalProperties", 
toObjectMap(a.additionalProperties()))
                        .appendSkipEmpty("allOf", joinnl(a.allOf()))
+                       .appendSkipEmpty("collectionFormat", 
a.collectionFormat())
                        .appendSkipEmpty("default", joinnl(a._default()))
                        .appendSkipEmpty("discriminator", a.discriminator())
                        .appendSkipEmpty("description", joinnl(a.description()))
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/RequestBean.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/RequestBean.java
index 3b8bb29..b20f863 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/RequestBean.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/RequestBean.java
@@ -55,10 +55,6 @@ import org.apache.juneau.httppart.*;
  *             <ja>@Query</ja>
  *             String getQ1();
  *
- *             <ja>@Query</ja>
- *             <ja>@BeanProperty</ja>(name=<js>"q2"</js>)
- *             String getQuery2();
- *
  *             <jc>// Schema-based query parameter:  Pipe-delimited lists of 
comma-delimited lists of integers.</jc>
  *             <ja>@Query</ja>(
  *                     collectionFormat=<js>"pipes"</js>
@@ -121,10 +117,6 @@ import org.apache.juneau.httppart.*;
  *             <ja>@Query</ja>
  *             <jk>public</jk> String getQ1() {...}
  *
- *             <ja>@Query</ja>
- *             <ja>@BeanProperty</ja>(name=<js>"q2"</js>)
- *             <jk>public</jk> String getQuery2() {...}
- *
  *             <jc>// Schema-based query parameter:  Pipe-delimited lists of 
comma-delimited lists of integers.</jc>
  *             <ja>@Query</ja>(
  *                     collectionFormat=<js>"pipes"</js>
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Response.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Response.java
index 7f3efd3..4f3527a 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Response.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Response.java
@@ -115,7 +115,7 @@ import org.apache.juneau.jsonschema.*;
  * </ul>
  */
 @Documented
-@Target({PARAMETER,TYPE})
+@Target({PARAMETER,TYPE,METHOD})
 @Retention(RUNTIME)
 @Inherited
 public @interface Response {
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Schema.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Schema.java
index 1bb9490..4eebb27 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Schema.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/annotation/Schema.java
@@ -497,6 +497,51 @@ public @interface Schema {
        Items items() default @Items;
 
        /**
+        * <mk>collectionFormat</mk> field.
+        *
+        * <p>
+        * Note that this field isn't part of the Swagger 2.0 specification, 
but the specification does not specify how
+        * items are supposed to be represented.
+        *
+        * <p>
+        * Determines the format of the array if <code>type</code> 
<js>"array"</js> is used.
+        * <br>Can only be used if <code>type</code> is <js>"array"</js>.
+        *
+        * <br>Possible values are:
+        * <ul class='spaced-list'>
+        *      <li>
+        *              <js>"csv"</js> (default) - Comma-separated values (e.g. 
<js>"foo,bar"</js>).
+        *      <li>
+        *              <js>"ssv"</js> - Space-separated values (e.g. <js>"foo 
bar"</js>).
+        *      <li>
+        *              <js>"tsv"</js> - Tab-separated values (e.g. 
<js>"foo\tbar"</js>).
+        *      <li>
+        *              <js>"pipes</js> - Pipe-separated values (e.g. 
<js>"foo|bar"</js>).
+        *      <li>
+        *              <js>"multi"</js> - Corresponds to multiple parameter 
instances instead of multiple values for a single instance (e.g. 
<js>"foo=bar&amp;foo=baz"</js>).
+        *      <li>
+        *              <js>"uon"</js> - UON notation (e.g. 
<js>"@(foo,bar)"</js>).
+        * </ul>
+        *
+        * <p>
+        * Static strings are defined in {@link CollectionFormatType}.
+        *
+        * <p>
+        * Note that for collections/arrays parameters with POJO element types, 
the input is broken into a string array before being converted into POJO 
elements.
+        *
+        * <h5 class='section'>Used for:</h5>
+        * <ul class='spaced-list'>
+        *      <li>
+        *              Server-side schema-based parsing.
+        *      <li>
+        *              Server-side generated Swagger documentation.
+        *      <li>
+        *              Client-side schema-based serializing.
+        * </ul>
+        */
+       String collectionFormat() default "";
+
+       /**
         * <mk>allOf</mk> field of the Swagger <a class="doclink" 
href="https://swagger.io/specification/v2/#schemaObject";>Schema</a> object.
         *
         * <h5 class='section'>Notes:</h5>
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
index 9c902ba..ba00a97 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSchemaBuilder.java
@@ -337,6 +337,7 @@ public class HttpPartSchemaBuilder {
                type(a.type());
                format(a.format());
                items(a.items());
+               collectionFormat(a.collectionFormat());
                _default(joinnl(a._default()));
                maximum(HttpPartSchema.toNumber(a.maximum()));
                exclusiveMaximum(a.exclusiveMaximum());
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializerSession.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializerSession.java
index 62e820b..14829b3 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializerSession.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializerSession.java
@@ -68,6 +68,7 @@ public class OpenApiPartSerializerSession extends 
UonPartSerializerSession {
        // Cache these for faster lookup
        private static final BeanContext BC = BeanContext.DEFAULT;
        private static final ClassMeta<byte[]> CM_ByteArray = 
BC.getClassMeta(byte[].class);
+       private static final ClassMeta<String[]> CM_StringArray = 
BC.getClassMeta(String[].class);
        private static final ClassMeta<Calendar> CM_Calendar = 
BC.getClassMeta(Calendar.class);
        private static final ClassMeta<Long> CM_Long = 
BC.getClassMeta(Long.class);
        private static final ClassMeta<Integer> CM_Integer = 
BC.getClassMeta(Integer.class);
@@ -173,7 +174,9 @@ public class OpenApiPartSerializerSession extends 
UonPartSerializerSession {
                                                for (Object o : 
(Collection<?>)value)
                                                        
l.add(serialize(partType, items, o));
                                        } else if 
(vt.hasTransformTo(String[].class)) {
-                                               l.add(serialize(partType, 
items, value));
+                                               String[] ss = toType(value, 
CM_StringArray);
+                                               for (int i = 0; i < ss.length; 
i++)
+                                                       
l.add(serialize(partType, items, ss[i]));
                                        }
 
                                        if (cf == PIPES)
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteMethodArg.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteMethodArg.java
index 71bb648..eb7501c 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteMethodArg.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/remoteable/RemoteMethodArg.java
@@ -20,7 +20,6 @@ import java.lang.reflect.*;
 
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.httppart.*;
-import org.apache.juneau.internal.*;
 
 /**
  * Represents the metadata about an annotated argument of a method on a remote 
proxy interface.
@@ -48,15 +47,6 @@ public final class RemoteMethodArg {
                this.skipIfEmpty = schema == null ? false : 
schema.isSkipIfEmpty();
        }
 
-       RemoteMethodArg(HttpPartType partType, HttpPartSchema schema, String 
defaultName) {
-               this.index = -1;
-               this.partType = partType;
-               this.serializer = createSerializer(partType, schema);
-               this.schema = schema;
-               this.name = StringUtils.firstNonEmpty(schema == null ? null : 
schema.getName(), defaultName);
-               this.skipIfEmpty = schema == null ? false : 
schema.isSkipIfEmpty();
-       }
-
        private static HttpPartSerializer createSerializer(HttpPartType 
partType, HttpPartSchema schema) {
                if (schema == null)
                        return null;
diff --git a/juneau-doc/src/main/javadoc/overview.html 
b/juneau-doc/src/main/javadoc/overview.html
index ce0516d..2e1cd6f 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -312,8 +312,8 @@
                        <li><p class='new'><a class='doclink' 
href='#juneau-rest-server.HttpPartAnnotations.HasQuery'>@HasQuery</a></p>
                        <li><p class='new'><a class='doclink' 
href='#juneau-rest-server.HttpPartAnnotations.Header'>@Header</a></p>
                        <li><p class='new'><a class='doclink' 
href='#juneau-rest-server.HttpPartAnnotations.Path'>@Path</a></p>
-                       <li><p class='todo'><a class='doclink' 
href='#juneau-rest-server.HttpPartAnnotations.RequestBean'>RequestBean</a></p>
-                       <li><p class='todo'><a class='doclink' 
href='#juneau-rest-server.HttpPartAnnotations.Response'>@Response</a></p>
+                       <li><p class='new'><a class='doclink' 
href='#juneau-rest-server.HttpPartAnnotations.RequestBean'>@RequestBean</a></p>
+                       <li><p class='new'><a class='doclink' 
href='#juneau-rest-server.HttpPartAnnotations.Response'>@Response</a></p>
                        <li><p class='todo'><a class='doclink' 
href='#juneau-rest-server.HttpPartAnnotations.ResponseHeader'>@ResponseHeader</a></p>
                        <li><p class='todo'><a class='doclink' 
href='#juneau-rest-server.HttpPartAnnotations.ResponseStatus'>@ResponseStatus</a></p>
                        <li><p class='todo'><a class='doclink' 
href='#juneau-rest-server.HttpPartAnnotations.ResponseStatuses'>@ResponseStatuses</a></p>
@@ -15350,16 +15350,316 @@ VariantAlsoNegotiates
 
 <!-- 
====================================================================================================
 -->
 
-<h4 class='topic todo' onclick='toggle(this)'><a 
href='#juneau-rest-server.HttpPartAnnotations.RequestBean' 
id='juneau-rest-server.HttpPartAnnotations.RequestBean'>7.9.8 - 
RequestBean</a></h4>
+<h4 class='topic new' onclick='toggle(this)'><a 
href='#juneau-rest-server.HttpPartAnnotations.RequestBean' 
id='juneau-rest-server.HttpPartAnnotations.RequestBean'>7.9.8 - 
@RequestBean</a></h4>
 <div class='topic'><!-- START: 7.9.8 - 
juneau-rest-server.HttpPartAnnotations.RequestBean -->
-TODO(7.2.0)
+<p>
+       The {@link org.apache.juneau.http.annotation.RequestBean @RequestBean} 
annotation can be applied to a parameter or parameter type of a 
<ja>@RestMethod</ja>-annotated method 
+       to identify it as an interface for retrieving HTTP parts through a bean 
interface.
+</p>
+
+<h5 class='section'>Example:</h5>
+<p class='bpcode w800'>
+       <ja>@RestMethod</ja>(path=<js>"/mypath/{p1}/{p2}/*"</js>)
+       <jk>public void</jk> myMethod(<ja>@RequestBean</ja> MyRequestBean rb) 
{...}
+
+       <jk>public interface</jk> MyRequestBean {
+
+               <ja>@Path</ja> <jc>// Path variable name inferred from 
getter.</jc>
+               String getP1();
+
+               <ja>@Path</ja>(<js>"p2"</js>)
+               String getX();
+
+               <ja>@Path</ja>(<js>"/*"</js>)
+               String getRemainder();
+
+               <ja>@Query</ja>
+               String getQ1();
+
+               <jc>// Schema-based query parameter:  Pipe-delimited lists of 
comma-delimited lists of integers.</jc>
+               <ja>@Query</ja>(
+                       collectionFormat=<js>"pipes"</js>
+                       items=<ja>@Items</ja>(
+                               items=<ja>@SubItems</ja>(
+                                       collectionFormat=<js>"csv"</js>
+                                       type=<js>"integer"</js>
+                               )
+                       )
+               )
+               <jk>int</jk>[][] getQ3();
+
+               <ja>@Header</ja>(<js>"*"</js>)
+               Map&lt;String,Object&gt; getHeaders();
+</p>
+<p class='bpcode w800'>
+       <jc>// Same as above but annotation defined on interface.</jc>
+       <ja>@RestMethod</ja>(path=<js>"/mypath/{p1}/{p2}/*"</js>)
+       <jk>public void</jk> myMethod(MyRequestBean rb) {...}
+
+       <ja>@RequestBean</ja>
+       <jk>public interface</jk> MyRequestBean {...}
+</p>
+<p>
+       The return types of the getters must be the supported parameter types 
for the HTTP-part annotation used.
+       <br>Schema-based serialization and parsing is used just as if used as 
individual parameter types.
+</p>
 </div><!-- END: 7.9.8 - juneau-rest-server.HttpPartAnnotations.RequestBean -->
 
 <!-- 
====================================================================================================
 -->
 
-<h4 class='topic todo' onclick='toggle(this)'><a 
href='#juneau-rest-server.HttpPartAnnotations.Response' 
id='juneau-rest-server.HttpPartAnnotations.Response'>7.9.9 - @Response</a></h4>
+<h4 class='topic new' onclick='toggle(this)'><a 
href='#juneau-rest-server.HttpPartAnnotations.Response' 
id='juneau-rest-server.HttpPartAnnotations.Response'>7.9.9 - @Response</a></h4>
 <div class='topic'><!-- START: 7.9.9 - 
juneau-rest-server.HttpPartAnnotations.Response -->
-TODO(7.2.0)
+<p>
+       The {@link org.apache.juneau.http.annotation.Response @Response} 
annotation is used to identify schema information about an HTTP response.
+</p>
+<ul class='doctree'>
+       <li class='ja'>{@link org.apache.juneau.http.annotation.Response 
Response}
+       <ul>
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#api() api()} - Free-form Swagger 
JSON.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#code() code()} - HTTP status code.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#description() description()} - 
Description.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#example() example()} - Serialized 
example.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#examples() examples()} - Serialized 
examples per media type.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#headers() headers()} - Swagger about 
headers added to response.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#partSerializer() partSerializer()} - 
Override the part serializer.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#schema() schema()} - Swagger schema.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#usePartSerializer() 
usePartSerializer()} - Use the HTTP-Part serializer for serializing the body.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#value() value()} - Free-form Swagger 
JSON.
+       </ul>
+</ul>
+<p>
+       <br>It can be used in the following locations:
+<ul>
+       <li>Exception classes thrown from <ja>@RestMethod</ja>-annotated REST 
Java methods.
+       <li>Type classes returned by <ja>@RestMethod</ja>-annotated REST Java 
methods.
+       <li><ja>@RestMethod</ja>-annotated REST Java methods themselves.
+       <li>Java method arguments and argument-types of 
<ja>@RestMethod</ja>-annotated REST Java methods.
+</ul>
+
+<p>
+       When applied to exception classes, this annotation defines Swagger 
information on non-200 return types.
+</p>
+<p>
+       The following example shows the <ja>@Response</ja> annotation used to 
define a subclass of <code>Unauthorized</code> for an invalid login attempt.
+</p>
+<p class='bpcode w800'>
+       <jc>// Our REST method that throws an annotated exception.</jc>
+       <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
+       <jk>public</jk> Ok login(String username, String password) 
<jk>throws</jk> InvalidLogin {
+               checkCredentials(username, password);
+               <jk>return new</jk> Ok();
+       }
+
+       <jc>// Our annotated exception.</jc>
+       <ja>@Response</ja>(description=<js>"Invalid username or password 
provided"</js>)
+       <jk>public class</jk> InvalidLogin <jk>extends</jk> Unauthorized {
+               <jk>public</jk> InvalidLogin() {
+                       <jk>super</jk>(<js>"Invalid username or 
password."</js>);  <jc>// Message sent in response</jc>
+               }
+       }
+
+       <jc>// Parent exception class.</jc>
+       <jc>// Note that the default description is overridden above.</jc>
+       <ja>@Response</ja>(code=401, description=<js>"Unauthorized"</js>)
+       <jk>public class</jk> Unauthorized <jk>extends</jk> RestException { ... 
}
+</p>
+<p>
+       The attributes on this annotation are used to populate the generated 
Swagger for the method.
+       <br>In this case, the Swagger is populated with the following:
+</p>
+<p class='bpcode w800'>
+       <js>'/user/login'</js>: {
+               get: {
+                       responses: {
+                               401: {
+                                       description: <js>'Invalid username or 
password provided'</js>
+                               }
+                       }
+               }
+       }
+</p>
+<p>
+       When applied type classes returned by a Java method, this annotation 
defines Swagger information on the body of responses.
+</p>
+<p>
+       In the example above, we're using the <code>Ok</code> class which is 
defined like so:
+</p>
+<p class='bpcode w800'>
+       <ja>@Response</ja>(code=200, example=<js>"'OK'"</js>)
+       <jk>public class</jk> Ok { ... }
+</p>
+<p>
+       Another example is <code>Redirect</code> which is defined like so:
+</p>
+<p class='bpcode w800'>
+       <ja>@Response</ja>(
+               code=302,
+               description=<js>"Redirect"</js>,
+               headers={
+                       <ja>@ResponseHeader</ja>(
+                               name=<js>"Location"</js>,
+                               type=<js>"string"</js>,
+                               format=<js>"uri"</js>
+                       )
+               }
+       )
+       <jk>public class</jk> Redirect { ... }
+</p>
+<p>
+       The <ja>@Response</ja> annotation can also be applied to the Java 
method itself which is effectively
+       the same as applying it to the return type, albeit for this method only.
+</p>
+<p class='bpcode w800'>
+       <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
+       <ja>@Response</ja>(code=200, example=<js>"'OK'"</js>)
+       <jk>public</jk> Ok login(String username, String password) 
<jk>throws</jk> InvalidLogin {...}
+</p>
+<p>
+       The <ja>@Response</ja> annotation can also be applied to the Java 
method parameters when the parameter type 
+       is {@link org.apache.juneau.utils.Value} (a placeholder for objects).
+</p>
+<p class='bpcode w800'>
+       <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
+       <ja>@Response</ja>(code=200, example=<js>"'OK'"</js>)
+       <jk>public void</jk> login(
+                       String username, 
+                       String password, 
+                       <ja>@Response</ja>(code=200, example=<js>"'OK'"</js>) 
Value&lt;Object&gt;
+               ) <jk>throws</jk> InvalidLogin {...}
+</p>
+
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+
+<p>
+       Any of the following types can be used for the parameter or POJO class 
(matched in the specified order):
+</p>
+<ol class='spaced-list'>
+       <li>
+               {@link java.io.Reader}
+               <br><ja>@Body</ja> annotation is optional.
+               <br><code>Content-Type</code> is ignored.
+       <li>
+               {@link java.io.InputStream}
+               <br><ja>@Body</ja> annotation is optional.
+               <br><code>Content-Type</code> is ignored.
+       <li>
+               Any <a class='doclink' 
href='#juneau-marshall.PojoCategories'>Parsable POJO</a> type.
+               <br><code>Content-Type</code> is required to identify correct 
parser.
+       <li>
+               Objects convertible from {@link java.io.Reader} by having one 
of the following non-deprecated methods:
+               <ul>
+                       <li><code><jk>public</jk> T(Reader in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>create</jsm>(Reader in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>fromReader</jsm>(Reader in) {...}</code>
+               </ul>
+               <code>Content-Type</code> must not be present or match an 
existing parser so that it's not parsed as a POJO.
+       <li>
+               Objects convertible from {@link java.io.InputStream} by having 
one of the following non-deprecated methods:
+               <ul>
+                       <li><code><jk>public</jk> T(InputStream in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>create</jsm>(InputStream in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>fromInputStream</jsm>(InputStream in) {...}</code>
+               </ul>
+               <code>Content-Type</code> must not be present or match an 
existing parser so that it's not parsed as a POJO.
+       <li>
+               Objects convertible from {@link java.lang.String} by having one 
of the following non-deprecated methods:
+               <ul>
+                       <li><code><jk>public</jk> T(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>create</jsm>(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>fromString</jsm>(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>parse</jsm>(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>parseString</jsm>(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>forName</jsm>(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>forString</jsm>(String in) {...}</code>
+               </ul>
+               Note that this also includes all enums.
+</ol>
+<p>
+       If the {@link org.apache.juneau.http.annotation.Body#usePartParser 
usePartParser} flag is set on the annotation,
+       then the body can be parsed using the registered {@link 
org.apache.juneau.httppart.HttpPartParser} which by default
+       is {@link org.apache.juneau.httppart.OpenApiPartParser}.
+</p>
+<p>
+       For example, the following shows how a pipe-delimited list of 
comma-delimited numbers (e.g. <js>"1,2,3|4,5,6|7,8,9"</js>) can be converted to 
a 2-dimensional array of <code>Longs</code>:
+</p>
+<p class='bpcode w800'>
+       <jc>// Body is a pipe-delimited list of comma-delimited lists of 
longs.</jc>
+       <ja>@RestMethod</ja>(method=<js>"POST"</js>, path=<js>"/testBody"</js>) 
+       <jk>public void</jk> testBody(
+               <ja>@Body</ja>(
+                       usePartParser=<jk>true</jk>,
+                       schema=<ja>@Schema</ja>(
+                               items=<ja>@Items</ja>(
+                                       collectionFormat=<js>"pipes"</js>,
+                                       items=<ja>@SubItems</ja>(
+                                               collectionFormat=<js>"csv"</js>,
+                                               type=<js>"integer"</js>, 
+                                               format=<js>"int64"</js>,
+                                               minimum=<js>"0"</js>,
+                                               maximum=<js>"100"</js>
+                                               minLength=1,
+                                               maxLength=10
+                                       )
+                               ),
+                               minLength=1,
+                               maxLength=10
+                       )
+               )
+               Long[][] body
+       ) {...}
+</p>
+<p>
+       Input will be converted based on the types and formats defined in the 
schema definition.
+       <br>Input validations such as <code>minLength/maxLength</code> that 
don't match the input will result in automatic <code>400 Bad Request</code> 
responses.
+</p>
+<p>
+       For more information about valid parameter types when using OpenAPI 
parsing, see <a class='doclink' 
href='#juneau-marshall.OpenApiDetails.Parsers'>OpenAPI Parsers</a>
+</p>
+
+<p>
+       The <ja>@Body</ja> annotation is also used for supplying swagger 
information about the body of the request.
+       <br>This information is used to populate the auto-generated Swagger 
documentation and UI.
+</p>
+<h5 class='figure'>Examples:</h5>
+<p class='bpcode w800'>
+       <jc>// Normal</jc>
+       <ja>@Body</ja>(
+               description=<js>"Pet object to add to the store"</js>,
+               required=<jk>true</jk>,
+               
example=<js>"{name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']}"</js>
+       )
+</p>
+<p class='bpcode w800'>
+       <jc>// Free-form</jc>
+       <jc>// Note the extra field</jc>
+       <ja>@Body</ja>({
+               <js>"description: 'Pet object to add to the store',"</js>,
+               <js>"required: true,"</js>,
+               <js>"example: 
{name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']},"</js>
+               <js>"x-extra: 'extra field'"</js>
+       })
+</p>
+<p>
+       <a class='doclink' href='#DefaultRestSvlVariables'>Initialization and 
request-time variables</a> (e.g. "$L{my.localized.variable}")
+       are supported on annotation fields.
+</p>
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+       <jc>// Localized</jc>
+       <ja>@Body</ja>(
+               description=<js>"$L{PetObjectDescription}"</js>
+       )
+</p>
+
+
+
+<h5 class='section'>See Also:</h5>
+<ul>
+       <li class='jc'>{@link org.apache.juneau.rest.RequestBody}
+       <li class='link'><a class='doclink' 
href='#juneau-rest-server.OpenApiSchemaPartSerializing'>OpenAPI Schema Part 
Serializing</a>
+</ul>
 </div><!-- END: 7.9.9 - juneau-rest-server.HttpPartAnnotations.Response -->
 
 <!-- 
====================================================================================================
 -->
@@ -29796,6 +30096,45 @@ TODO(7.2.0)
                        <li><code>RdfParser.Turtle</code> -&gt; {@link 
org.apache.juneau.jena.TurtleParser}
                </ul>
        <li>
+               New API for pairing serializers and parsers for simplified 
syntax:
+               <h5 class='figure'>Examples:</h5>
+               <p class='bpcode w800'>
+       <jc>// Using instance.</jc>
+       Json json = <jk>new</jk> Json();
+       MyPojo myPojo = json.read(string, MyPojo.<jk>class</jk>);
+       String string = json.write(myPojo);
+               </p>
+               <p class='bpcode w800'>
+       <jc>// Using DEFAULT instance.</jc>
+       MyPojo myPojo = Json.<jsf>DEFAULT</jsf>.read(string, 
MyPojo.<jk>class</jk>);
+       String string = Json.<jsf>DEFAULT</jsf>.write(myPojo);
+               </p>
+               <ul class='doctree'>
+                       <li class='jac'>{@link 
org.apache.juneau.marshall.Marshall}
+                       <ul>
+                               <li class='jac'>{@link 
org.apache.juneau.marshall.CharMarshall}
+                               <ul>
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.Html}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.Json}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.PlainText}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.SimpleJson}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.Uon}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.UrlEncoding}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.Xml}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.N3}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.NTriple}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.RdfXml}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.RdfXmlAbbrev}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.Turtle}        
+                               </ul>
+                               <li class='jac'>{@link 
org.apache.juneau.marshall.StreamMarshall}
+                               <ul>
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.Jso}
+                                       <li class='jc'>{@link 
org.apache.juneau.marshall.MsgPack}
+                               </ul>
+                       </ul>
+               </ul>
+       <li>
                New/updated documentation:
                <ul>
                        <li><a 
href='#juneau-marshall.JsonDetails.SimplifiedJson'>2.15.3 - Simplified JSON</a>
diff --git 
a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/08.RequestBean.html
 
b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/08.RequestBean.html
index 85220da..5bd004d 100644
--- 
a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/08.RequestBean.html
+++ 
b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/08.RequestBean.html
@@ -13,6 +13,56 @@
  
***************************************************************************************************************************/
  -->
 
-{todo} RequestBean
+{new} @RequestBean
 
-TODO(7.2.0)
\ No newline at end of file
+<p>
+       The {@link org.apache.juneau.http.annotation.RequestBean @RequestBean} 
annotation can be applied to a parameter or parameter type of a 
<ja>@RestMethod</ja>-annotated method 
+       to identify it as an interface for retrieving HTTP parts through a bean 
interface.
+</p>
+
+<h5 class='section'>Example:</h5>
+<p class='bpcode w800'>
+       <ja>@RestMethod</ja>(path=<js>"/mypath/{p1}/{p2}/*"</js>)
+       <jk>public void</jk> myMethod(<ja>@RequestBean</ja> MyRequestBean rb) 
{...}
+
+       <jk>public interface</jk> MyRequestBean {
+
+               <ja>@Path</ja> <jc>// Path variable name inferred from 
getter.</jc>
+               String getP1();
+
+               <ja>@Path</ja>(<js>"p2"</js>)
+               String getX();
+
+               <ja>@Path</ja>(<js>"/*"</js>)
+               String getRemainder();
+
+               <ja>@Query</ja>
+               String getQ1();
+
+               <jc>// Schema-based query parameter:  Pipe-delimited lists of 
comma-delimited lists of integers.</jc>
+               <ja>@Query</ja>(
+                       collectionFormat=<js>"pipes"</js>
+                       items=<ja>@Items</ja>(
+                               items=<ja>@SubItems</ja>(
+                                       collectionFormat=<js>"csv"</js>
+                                       type=<js>"integer"</js>
+                               )
+                       )
+               )
+               <jk>int</jk>[][] getQ3();
+
+               <ja>@Header</ja>(<js>"*"</js>)
+               Map&lt;String,Object&gt; getHeaders();
+</p>
+<p class='bpcode w800'>
+       <jc>// Same as above but annotation defined on interface.</jc>
+       <ja>@RestMethod</ja>(path=<js>"/mypath/{p1}/{p2}/*"</js>)
+       <jk>public void</jk> myMethod(MyRequestBean rb) {...}
+
+       <ja>@RequestBean</ja>
+       <jk>public interface</jk> MyRequestBean {...}
+</p>
+<p>
+       The return types of the getters must be the supported parameter types 
for the HTTP-part annotation used.
+       <br>Schema-based serialization and parsing is used just as if used as 
individual parameter types.
+</p>
diff --git 
a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/09.Response.html
 
b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/09.Response.html
index 76c71ae..16b892c 100644
--- 
a/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/09.Response.html
+++ 
b/juneau-doc/src/main/resources/Topics/07.juneau-rest-server/09.HttpPartAnnotations/09.Response.html
@@ -13,6 +13,298 @@
  
***************************************************************************************************************************/
  -->
 
-{todo} @Response
+{new} @Response
+
+<p>
+       The {@link org.apache.juneau.http.annotation.Response @Response} 
annotation is used to identify schema information about an HTTP response.
+</p>
+<ul class='doctree'>
+       <li class='ja'>{@link org.apache.juneau.http.annotation.Response 
Response}
+       <ul>
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#api() api()} - Free-form Swagger 
JSON.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#code() code()} - HTTP status code.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#description() description()} - 
Description.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#example() example()} - Serialized 
example.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#examples() examples()} - Serialized 
examples per media type.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#headers() headers()} - Swagger about 
headers added to response.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#partSerializer() partSerializer()} - 
Override the part serializer.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#schema() schema()} - Swagger schema.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#usePartSerializer() 
usePartSerializer()} - Use the HTTP-Part serializer for serializing the body.
+               <li class='jf'>{@link 
org.apache.juneau.http.annotation.Response#value() value()} - Free-form Swagger 
JSON.
+       </ul>
+</ul>
+<p>
+       <br>It can be used in the following locations:
+<ul>
+       <li>Exception classes thrown from <ja>@RestMethod</ja>-annotated REST 
Java methods.
+       <li>Type classes returned by <ja>@RestMethod</ja>-annotated REST Java 
methods.
+       <li><ja>@RestMethod</ja>-annotated REST Java methods themselves.
+       <li>Java method arguments and argument-types of 
<ja>@RestMethod</ja>-annotated REST Java methods.
+</ul>
+
+<p>
+       When applied to exception classes, this annotation defines Swagger 
information on non-200 return types.
+</p>
+<p>
+       The following example shows the <ja>@Response</ja> annotation used to 
define a subclass of <code>Unauthorized</code> for an invalid login attempt.
+</p>
+<p class='bpcode w800'>
+       <jc>// Our REST method that throws an annotated exception.</jc>
+       <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
+       <jk>public</jk> Ok login(String username, String password) 
<jk>throws</jk> InvalidLogin {
+               checkCredentials(username, password);
+               <jk>return new</jk> Ok();
+       }
+
+       <jc>// Our annotated exception.</jc>
+       <ja>@Response</ja>(description=<js>"Invalid username or password 
provided"</js>)
+       <jk>public class</jk> InvalidLogin <jk>extends</jk> Unauthorized {
+               <jk>public</jk> InvalidLogin() {
+                       <jk>super</jk>(<js>"Invalid username or 
password."</js>);  <jc>// Message sent in response</jc>
+               }
+       }
+
+       <jc>// Parent exception class.</jc>
+       <jc>// Note that the default description is overridden above.</jc>
+       <ja>@Response</ja>(code=401, description=<js>"Unauthorized"</js>)
+       <jk>public class</jk> Unauthorized <jk>extends</jk> RestException { ... 
}
+</p>
+<p>
+       The attributes on this annotation are used to populate the generated 
Swagger for the method.
+       <br>In this case, the Swagger is populated with the following:
+</p>
+<p class='bpcode w800'>
+       <js>'/user/login'</js>: {
+               get: {
+                       responses: {
+                               401: {
+                                       description: <js>'Invalid username or 
password provided'</js>
+                               }
+                       }
+               }
+       }
+</p>
+<p>
+       When applied type classes returned by a Java method, this annotation 
defines Swagger information on the body of responses.
+</p>
+<p>
+       In the example above, we're using the <code>Ok</code> class which is 
defined like so:
+</p>
+<p class='bpcode w800'>
+       <ja>@Response</ja>(code=200, example=<js>"'OK'"</js>)
+       <jk>public class</jk> Ok { ... }
+</p>
+<p>
+       Another example is <code>Redirect</code> which is defined like so:
+</p>
+<p class='bpcode w800'>
+       <ja>@Response</ja>(
+               code=302,
+               description=<js>"Redirect"</js>,
+               headers={
+                       <ja>@ResponseHeader</ja>(
+                               name=<js>"Location"</js>,
+                               type=<js>"string"</js>,
+                               format=<js>"uri"</js>
+                       )
+               }
+       )
+       <jk>public class</jk> Redirect { ... }
+</p>
+<p>
+       The <ja>@Response</ja> annotation can also be applied to the Java 
method itself which is effectively
+       the same as applying it to the return type, albeit for this method only.
+</p>
+<p class='bpcode w800'>
+       <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
+       <ja>@Response</ja>(code=200, example=<js>"'OK'"</js>)
+       <jk>public</jk> Ok login(String username, String password) 
<jk>throws</jk> InvalidLogin {...}
+</p>
+<p>
+       The <ja>@Response</ja> annotation can also be applied to the Java 
method parameters when the parameter type 
+       is {@link org.apache.juneau.utils.Value} (a placeholder for objects).
+</p>
+<p class='bpcode w800'>
+       <ja>@RestMethod</ja>(name=<js>"GET"</js>, path=<js>"/user/login"</js>)
+       <ja>@Response</ja>(code=200, example=<js>"'OK'"</js>)
+       <jk>public void</jk> login(
+                       String username, 
+                       String password, 
+                       <ja>@Response</ja>(code=200, example=<js>"'OK'"</js>) 
Value&lt;Object&gt;
+               ) <jk>throws</jk> InvalidLogin {...}
+</p>
+
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+
+
+<p>
+       The return type can be any serializable POJO as defined in <a 
class='doclink' href='#juneau-marshall.PojoCategories'>POJO Categories</a>.
+       <br>It can also be <jk>void</jk> if the method is not sending any 
output (e.g. a request redirect) or is 
+       setting the output using the {@link 
org.apache.juneau.rest.RestResponse#setOutput(Object)} method.
+</p>
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+       <ja>@RestMethod</ja>(name=<jsf>GET</jsf>)
+       <jk>public</jk> String doGet() {
+               <jk>return</jk> <js>"Hello World!"</js>;
+       }
+</p>
+<p>
+       Out-of-the-box, besides POJOs, the following return types are handled 
as special cases:
+</p>
+<ul class='spaced-list'>
+       <li class='jc'>{@link java.io.InputStream}
+               <br>The contents are simply piped to the output stream returned 
by 
+               {@link 
org.apache.juneau.rest.RestResponse#getNegotiatedOutputStream()}.
+               <br>Note that you should call {@link 
org.apache.juneau.rest.RestResponse#setContentType(String)} to set 
+               the <l>Content-Type</l> header if you use this object type.
+       <li class='jc'>{@link java.io.InputStream}
+               <br>The contents are simply piped to the output stream returned 
by 
+               {@link 
org.apache.juneau.rest.RestResponse#getNegotiatedOutputStream()}.
+               <br>Note that you should call {@link 
org.apache.juneau.rest.RestResponse#setContentType(String)} to set 
+               the <l>Content-Type</l> header if you use this object type.
+       <li class='jc'>{@link java.io.Reader}
+               <br>The contents are simply piped to the output stream returned 
by 
+               {@link 
org.apache.juneau.rest.RestResponse#getNegotiatedWriter()}.
+               <br>Note that you should call {@link 
org.apache.juneau.rest.RestResponse#setContentType(String)} to set 
+               the <l>Content-Type</l> header if you use this object type.
+       <li class='jc'>{@link org.apache.juneau.rest.helper.Redirect}
+               <br>Represents an HTTP redirect response.
+       <li class='jc'>{@link org.apache.juneau.Streamable}
+               <br>Interface that identifies that an object can be serialized 
directly to an output stream.
+       <li class='jc'>{@link org.apache.juneau.Writable}
+               <br>Interface that identifies that an object can be serialized 
directly to a writer.
+       <li class='jc'>{@link org.apache.juneau.utils.ZipFileList}
+               <br>Special interface for sending zip files as responses.
+</ul>
+<p>
+       Any of the following types can be used for the parameter or POJO class 
(matched in the specified order):
+</p>
+<ol class='spaced-list'>
+       <li>
+               {@link java.io.Reader}
+               <br><ja>@Body</ja> annotation is optional.
+               <br><code>Content-Type</code> is ignored.
+       <li>
+               {@link java.io.InputStream}
+               <br><ja>@Body</ja> annotation is optional.
+               <br><code>Content-Type</code> is ignored.
+       <li>
+               Any <a class='doclink' 
href='#juneau-marshall.PojoCategories'>Parsable POJO</a> type.
+               <br><code>Content-Type</code> is required to identify correct 
parser.
+       <li>
+               Objects convertible from {@link java.io.Reader} by having one 
of the following non-deprecated methods:
+               <ul>
+                       <li><code><jk>public</jk> T(Reader in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>create</jsm>(Reader in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>fromReader</jsm>(Reader in) {...}</code>
+               </ul>
+               <code>Content-Type</code> must not be present or match an 
existing parser so that it's not parsed as a POJO.
+       <li>
+               Objects convertible from {@link java.io.InputStream} by having 
one of the following non-deprecated methods:
+               <ul>
+                       <li><code><jk>public</jk> T(InputStream in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>create</jsm>(InputStream in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>fromInputStream</jsm>(InputStream in) {...}</code>
+               </ul>
+               <code>Content-Type</code> must not be present or match an 
existing parser so that it's not parsed as a POJO.
+       <li>
+               Objects convertible from {@link java.lang.String} by having one 
of the following non-deprecated methods:
+               <ul>
+                       <li><code><jk>public</jk> T(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>create</jsm>(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>fromString</jsm>(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>parse</jsm>(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>parseString</jsm>(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>forName</jsm>(String in) {...}</code>
+                       <li><code><jk>public static</jk> T 
<jsm>forString</jsm>(String in) {...}</code>
+               </ul>
+               Note that this also includes all enums.
+</ol>
+<p>
+       If the {@link org.apache.juneau.http.annotation.Body#usePartParser 
usePartParser} flag is set on the annotation,
+       then the body can be parsed using the registered {@link 
org.apache.juneau.httppart.HttpPartParser} which by default
+       is {@link org.apache.juneau.httppart.OpenApiPartParser}.
+</p>
+<p>
+       For example, the following shows how a pipe-delimited list of 
comma-delimited numbers (e.g. <js>"1,2,3|4,5,6|7,8,9"</js>) can be converted to 
a 2-dimensional array of <code>Longs</code>:
+</p>
+<p class='bpcode w800'>
+       <jc>// Body is a pipe-delimited list of comma-delimited lists of 
longs.</jc>
+       <ja>@RestMethod</ja>(method=<js>"POST"</js>, path=<js>"/testBody"</js>) 
+       <jk>public void</jk> testBody(
+               <ja>@Body</ja>(
+                       usePartParser=<jk>true</jk>,
+                       schema=<ja>@Schema</ja>(
+                               items=<ja>@Items</ja>(
+                                       collectionFormat=<js>"pipes"</js>,
+                                       items=<ja>@SubItems</ja>(
+                                               collectionFormat=<js>"csv"</js>,
+                                               type=<js>"integer"</js>, 
+                                               format=<js>"int64"</js>,
+                                               minimum=<js>"0"</js>,
+                                               maximum=<js>"100"</js>
+                                               minLength=1,
+                                               maxLength=10
+                                       )
+                               ),
+                               minLength=1,
+                               maxLength=10
+                       )
+               )
+               Long[][] body
+       ) {...}
+</p>
+<p>
+       Input will be converted based on the types and formats defined in the 
schema definition.
+       <br>Input validations such as <code>minLength/maxLength</code> that 
don't match the input will result in automatic <code>400 Bad Request</code> 
responses.
+</p>
+<p>
+       For more information about valid parameter types when using OpenAPI 
parsing, see <a class='doclink' 
href='#juneau-marshall.OpenApiDetails.Parsers'>OpenAPI Parsers</a>
+</p>
+
+<p>
+       The <ja>@Body</ja> annotation is also used for supplying swagger 
information about the body of the request.
+       <br>This information is used to populate the auto-generated Swagger 
documentation and UI.
+</p>
+<h5 class='figure'>Examples:</h5>
+<p class='bpcode w800'>
+       <jc>// Normal</jc>
+       <ja>@Body</ja>(
+               description=<js>"Pet object to add to the store"</js>,
+               required=<jk>true</jk>,
+               
example=<js>"{name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']}"</js>
+       )
+</p>
+<p class='bpcode w800'>
+       <jc>// Free-form</jc>
+       <jc>// Note the extra field</jc>
+       <ja>@Body</ja>({
+               <js>"description: 'Pet object to add to the store',"</js>,
+               <js>"required: true,"</js>,
+               <js>"example: 
{name:'Doggie',price:9.99,species:'Dog',tags:['friendly','cute']},"</js>
+               <js>"x-extra: 'extra field'"</js>
+       })
+</p>
+<p>
+       <a class='doclink' href='#DefaultRestSvlVariables'>Initialization and 
request-time variables</a> (e.g. "$L{my.localized.variable}")
+       are supported on annotation fields.
+</p>
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+       <jc>// Localized</jc>
+       <ja>@Body</ja>(
+               description=<js>"$L{PetObjectDescription}"</js>
+       )
+</p>
+
+
+
+<h5 class='section'>See Also:</h5>
+<ul>
+       <li class='jc'>{@link org.apache.juneau.rest.RequestBody}
+       <li class='link'><a class='doclink' 
href='#juneau-rest-server.OpenApiSchemaPartSerializing'>OpenAPI Schema Part 
Serializing</a>
+</ul>
 
-TODO(7.2.0)
\ No newline at end of file
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
index a9f9c7c..4b1a0d5 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
@@ -23,8 +23,7 @@ import java.util.*;
 import javax.servlet.*;
 import javax.servlet.http.*;
 
-import org.apache.juneau.http.annotation.*;
-import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.httppart.*;
 import org.apache.juneau.rest.exception.*;
 import org.apache.juneau.rest.helper.*;
 import org.apache.juneau.rest.util.*;
@@ -107,6 +106,7 @@ public class BasicRestCallHandler implements 
RestCallHandler {
 
                logger.log(FINE, "HTTP: {0} {1}", r1.getMethod(), 
r1.getRequestURI());
                long startTime = System.currentTimeMillis();
+               RestRequest req = null;
 
                try {
                        context.checkForInitException();
@@ -138,7 +138,7 @@ public class BasicRestCallHandler implements 
RestCallHandler {
 
                        context.startCall(r1, r2);
 
-                       RestRequest req = createRequest(r1);
+                       req = createRequest(r1);
                        RestResponse res = createResponse(req, r2);
                        String method = req.getMethod();
                        String methodUC = method.toUpperCase(Locale.ENGLISH);
@@ -192,23 +192,10 @@ public class BasicRestCallHandler implements 
RestCallHandler {
 
                        r1.setAttribute("ExecTime", System.currentTimeMillis() 
- startTime);
 
-               } catch (RestException e) {
-                       r1.setAttribute("Exception", e);
-                       r1.setAttribute("ExecTime", System.currentTimeMillis() 
- startTime);
-                       handleError(r1, r2, e);
                } catch (Throwable e) {
-                       Response ri = 
e.getClass().getAnnotation(Response.class);
-                       int code = SC_INTERNAL_SERVER_ERROR;
-                       if (ri != null) {
-                               if (ri.code().length > 0)
-                                       code = ri.code()[0];
-                               else if (ri.value().length > 0)
-                                       code = ri.value()[0];
-                       }
-                       RestException e2 = new RestException(e, code);
                        r1.setAttribute("Exception", e);
                        r1.setAttribute("ExecTime", System.currentTimeMillis() 
- startTime);
-                       handleError(r1, r2, e2);
+                       handleError(r1, r2, req, e);
                }
 
                context.finishCall(r1, r2);
@@ -274,10 +261,6 @@ public class BasicRestCallHandler implements 
RestCallHandler {
         * Method for handling response errors.
         *
         * <p>
-        * The default implementation logs the error and calls
-        * {@link 
#renderError(HttpServletRequest,HttpServletResponse,RestException)}.
-        *
-        * <p>
         * Subclasses can override this method to provide their own custom 
error response handling.
         *
         * @param req The servlet request.
@@ -286,64 +269,62 @@ public class BasicRestCallHandler implements 
RestCallHandler {
         * @throws IOException Can be thrown if a problem occurred trying to 
write to the output stream.
         */
        @Override /* RestCallHandler */
-       public synchronized void handleError(HttpServletRequest req, 
HttpServletResponse res, RestException e) throws IOException {
-               if (context.isDebug()) {
-                       String qs = req.getQueryString();
-                       int c = e.getOccurrence();
-                       String msg = '[' + Integer.toHexString(e.hashCode()) + 
'.' + e.getStatus() + '.' + c + "] HTTP " + req.getMethod() + " " + 
e.getStatus() + " " + req.getRequestURI() + (qs == null ? "" : "?" + qs);
-                       System.err.println(msg);
-                       e.printStackTrace(System.err);
-               }
-               e.setOccurrence(context == null ? 0 : 
context.getStackTraceOccurrence(e));
-               logger.onError(req, res, e);
-               renderError(req, res, e);
-       }
+       public synchronized void handleError(HttpServletRequest req, 
HttpServletResponse res, RestRequest rreq, Throwable e) throws IOException {
 
-       /**
-        * Method for rendering response errors.
-        *
-        * <p>
-        * The default implementation renders a plain text English message, 
optionally with a stack trace if
-        * {@link RestResource#renderResponseStackTraces() 
@RestResource.renderResponseStackTraces()} is enabled.
-        *
-        * <p>
-        * Subclasses can override this method to provide their own custom 
error response handling.
-        *
-        * @param req The servlet request.
-        * @param res The servlet response.
-        * @param e The exception that occurred.
-        * @throws IOException Can be thrown if a problem occurred trying to 
write to the output stream.
-        */
-       @Override /* RestCallHandler */
-       public void renderError(HttpServletRequest req, HttpServletResponse 
res, RestException e) throws IOException {
+               RestMethodThrown rmt = rreq == null ? null : 
rreq.getRestMethodThrown(e);
+               int occurrence = context == null ? 0 : 
context.getStackTraceOccurrence(e);
+               RestException e2 = (e instanceof RestException ? 
(RestException)e : new RestException(e, rmt == null ? 500 : 
rmt.getCode())).setOccurrence(occurrence);
 
-               int status = e.getStatus();
-               res.setStatus(status);
-               res.setContentType("text/plain");
-               res.setHeader("Content-Encoding", "identity");
+               HttpPartSerializer ps = rmt == null ? null : 
rmt.getPartSerializer();
 
-               Throwable t = e.getRootCause();
+               Throwable t = e2.getRootCause();
                if (t != null) {
                        res.setHeader("Exception-Name", t.getClass().getName());
                        res.setHeader("Exception-Message", t.getMessage());
                }
 
-               PrintWriter w = null;
                try {
-                       w = res.getWriter();
-               } catch (IllegalStateException e2) {
-                       w = new PrintWriter(new 
OutputStreamWriter(res.getOutputStream(), UTF8));
+                       res.setContentType("text/plain");
+                       res.setHeader("Content-Encoding", "identity");
+                       res.setStatus(e2.getStatus());
+
+                       PrintWriter w = null;
+                       try {
+                               w = res.getWriter();
+                       } catch (IllegalStateException x) {
+                               w = new PrintWriter(new 
OutputStreamWriter(res.getOutputStream(), UTF8));
+                       }
+
+                       try (PrintWriter w2 = w) {
+
+                               // Throwable can be handled as an HTTP part.
+                               if (rmt != null && ps != null) {
+                                       w2.append(ps.serialize(rmt.getSchema(), 
e));
+
+                               // It's some other exception.
+                               } else {
+                                       String httpMessage = 
RestUtils.getHttpResponseText(e2.getStatus());
+                                       if (httpMessage != null)
+                                               w2.append("HTTP 
").append(String.valueOf(e2.getStatus())).append(": 
").append(httpMessage).append("\n\n");
+                                       if (context != null && 
context.isRenderResponseStackTraces())
+                                               e.printStackTrace(w2);
+                                       else
+                                               
w2.append(e2.getFullStackMessage(true));
+                               }
+                       }
+
+               } catch (Exception e1) {
+                       logger.onError(req, res, new RestException(e1, 0));
                }
 
-               try (PrintWriter w2 = w) {
-                       String httpMessage = 
RestUtils.getHttpResponseText(status);
-                       if (httpMessage != null)
-                               w2.append("HTTP 
").append(String.valueOf(status)).append(": 
").append(httpMessage).append("\n\n");
-                       if (context != null && 
context.isRenderResponseStackTraces())
-                               e.printStackTrace(w2);
-                       else
-                               w2.append(e.getFullStackMessage(true));
+               if (context.isDebug()) {
+                       String qs = req.getQueryString();
+                       String msg = '[' + Integer.toHexString(e.hashCode()) + 
'.' + e2.getStatus() + '.' + e2.getOccurrence() + "] HTTP " + req.getMethod() + 
" " + e2.getStatus() + " " + req.getRequestURI() + (qs == null ? "" : "?" + qs);
+                       System.err.println(msg);
+                       e.printStackTrace(System.err);
                }
+
+               logger.onError(req, res, e2);
        }
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
index cf007fa..41f5f18 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallHandler.java
@@ -95,20 +95,13 @@ public interface RestCallHandler {
         *
         * @param req The servlet request.
         * @param res The servlet response.
+        * @param rreq
+        *      The REST request.
+        *      <br>This may be <jk>null</jk> if an error occurred before this 
was initialized.
         * @param e The exception that occurred.
         * @throws IOException Can be thrown if a problem occurred trying to 
write to the output stream.
         */
-       public void handleError(HttpServletRequest req, HttpServletResponse 
res, RestException e) throws IOException;
-
-       /**
-        * Method for rendering response errors.
-        *
-        * @param req The servlet request.
-        * @param res The servlet response.
-        * @param e The exception that occurred.
-        * @throws IOException Can be thrown if a problem occurred trying to 
write to the output stream.
-        */
-       public void renderError(HttpServletRequest req, HttpServletResponse 
res, RestException e) throws IOException;
+       public void handleError(HttpServletRequest req, HttpServletResponse 
res, RestRequest rreq, Throwable e) throws IOException;
 
        /**
         * Returns the session objects for the specified request.
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallRouter.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallRouter.java
index 48bac28..3bf4358 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallRouter.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestCallRouter.java
@@ -75,7 +75,7 @@ public class RestCallRouter {
         * @param pathInfo The value of {@link 
HttpServletRequest#getPathInfo()} (sorta)
         * @return The HTTP response code.
         */
-       int invoke(String pathInfo, RestRequest req, RestResponse res) throws 
RestException {
+       int invoke(String pathInfo, RestRequest req, RestResponse res) throws 
Throwable {
                if (restJavaMethods.length == 1)
                        return restJavaMethods[0].invoke(pathInfo, req, res);
 
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 a7251de..a926559 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
@@ -834,7 +834,7 @@ public final class RestContext extends BeanContext {
         * <p>
         * Enables the following:
         * <ul>
-        *      <li>A message and stack trace is printed to STDERR when {@link 
BasicRestCallHandler#handleError(HttpServletRequest, HttpServletResponse, 
RestException)} is called.
+        *      <li>A message and stack trace is printed to STDERR when {@link 
BasicRestCallHandler#handleError(HttpServletRequest, HttpServletResponse, 
RestRequest, Throwable)} is called.
         * </ul>
         */
        public static final String REST_debug = PREFIX + "debug.b";
@@ -2030,7 +2030,7 @@ public final class RestContext extends BeanContext {
         *              <ul>
         *                      <li class='jm'>{@link 
RestContext#isRenderResponseStackTraces() 
RestContext.isRenderResponseStackTraces()}
         *              </ul>
-        *              That method is used by {@link 
BasicRestCallHandler#renderError(HttpServletRequest, HttpServletResponse, 
RestException)}.
+        *              That method is used by {@link 
BasicRestCallHandler#handleError(HttpServletRequest, HttpServletResponse, 
RestRequest, Throwable)}.
         * </ul>
         */
        public static final String REST_renderResponseStackTraces = PREFIX + 
"renderResponseStackTraces.b";
@@ -2666,7 +2666,7 @@ public final class RestContext extends BeanContext {
         * Affects the following methods:
         * <ul>
         *      <li class='jm'>{@link 
RestContext#getStackTraceOccurrence(Throwable) 
RestContext.getStackTraceOccurrance(Throwable)}
-        *      <li class='jm'>{@link 
RestCallHandler#handleError(HttpServletRequest, HttpServletResponse, 
RestException)}
+        *      <li class='jm'>{@link 
RestCallHandler#handleError(HttpServletRequest, HttpServletResponse, 
RestRequest, Throwable)}
         *      <li class='jm'>{@link RestException#getOccurrence()} - Returns 
the number of times this exception occurred.
         * </ul>
         *
@@ -2955,7 +2955,7 @@ public final class RestContext extends BeanContext {
                        serializers = 
SerializerGroup.create().append(getInstanceArrayProperty(REST_serializers, 
Serializer.class, new Serializer[0], true, resource, ps)).build();
                        parsers = 
ParserGroup.create().append(getInstanceArrayProperty(REST_parsers, 
Parser.class, new Parser[0], true, resource, ps)).build();
                        partSerializer = 
getInstanceProperty(REST_partSerializer, HttpPartSerializer.class, 
OpenApiPartSerializer.class, true, resource, ps);
-                       partParser = getInstanceProperty(REST_partSerializer, 
HttpPartParser.class, OpenApiPartParser.class, true, resource, ps);
+                       partParser = getInstanceProperty(REST_partParser, 
HttpPartParser.class, OpenApiPartParser.class, true, resource, ps);
                        jsonSchemaSerializer = new JsonSchemaSerializer(ps);
                        encoders = new 
EncoderGroupBuilder().append(getInstanceArrayProperty(REST_encoders, 
Encoder.class, new Encoder[0], true, resource, ps)).build();
                        beanContext = BeanContext.create().apply(ps).build();
@@ -3044,7 +3044,7 @@ public final class RestContext extends BeanContext {
                                                        sm = new 
RestJavaMethod(resource, method, this) {
 
                                                                @Override
-                                                               int 
invoke(String pathInfo, RestRequest req, RestResponse res) throws 
InternalServerError {
+                                                               int 
invoke(String pathInfo, RestRequest req, RestResponse res) throws Throwable {
 
                                                                        int rc 
= super.invoke(pathInfo, req, res);
                                                                        if (rc 
!= SC_OK)
@@ -3093,7 +3093,7 @@ public final class RestContext extends BeanContext {
                                                        
_javaRestMethods.put(method.getName(), sm);
                                                        addToRouter(routers, 
httpMethod, sm);
                                                }
-                                       } catch (RestServletException e) {
+                                       } catch (Throwable e) {
                                                throw new 
RestServletException("Problem occurred trying to serialize methods on class 
{0}, methods={1}", resourceClass.getName(), 
SimpleJsonSerializer.DEFAULT.serialize(methodsFound)).initCause(e);
                                        }
                                }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
index 4a90673..d7e32b6 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContextBuilder.java
@@ -116,7 +116,11 @@ public class RestContextBuilder extends BeanContextBuilder 
implements ServletCon
                this.parentContext = parentContext;
 
                properties = new RestContextProperties();
+
+               // Default values.
                logger(BasicRestLogger.class);
+               partSerializer(OpenApiPartSerializer.class);
+               partParser(OpenApiPartParser.class);
                staticFileResponseHeader("Cache-Control", "max-age=86400, 
public");
                encoders(IdentityEncoder.INSTANCE);
 
@@ -169,6 +173,10 @@ public class RestContextBuilder extends BeanContextBuilder 
implements ServletCon
                                        set(p, true);
                                serializers(false, 
merge(ObjectUtils.toType(psb.peek(REST_serializers), Object[].class), 
r.serializers()));
                                parsers(false, 
merge(ObjectUtils.toType(psb.peek(REST_parsers), Object[].class), r.parsers()));
+                               if (r.partSerializer() != 
HttpPartSerializer.Null.class)
+                                       partSerializer(r.partSerializer());
+                               if (r.partParser() != HttpPartParser.Null.class)
+                                       partParser(r.partParser());
                                encoders(r.encoders());
                                if (r.produces().length > 0)
                                        produces(false, resolveVars(vr, 
r.produces()));
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestException.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestException.java
index 45bc86e..a06489e 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestException.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestException.java
@@ -31,7 +31,7 @@ public class RestException extends FormattedRuntimeException {
 
        private static final long serialVersionUID = 1L;
 
-       private final int status;
+       private int status;
        private int occurrence;
 
        /**
@@ -134,8 +134,13 @@ public class RestException extends 
FormattedRuntimeException {
                return i;
        }
 
-       void setOccurrence(int occurrence) {
+       RestException setOccurrence(int occurrence) {
                this.occurrence = occurrence;
+               return this;
+       }
+
+       void setStatus(int status) {
+               this.status = status;
        }
 
        /**
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
index 41bbc77..8021822 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestJavaMethod.java
@@ -384,11 +384,11 @@ public class RestJavaMethod implements 
Comparable<RestJavaMethod>  {
 
                                methodParams = context.findParams(method, 
pathPattern, false);
 
-                               methodReturn = new 
RestMethodReturn(method.getGenericReturnType());
+                               methodReturn = new RestMethodReturn(method, 
partSerializer, ps);
 
                                methodThrowns = new 
RestMethodThrown[method.getExceptionTypes().length];
                                for (int i = 0; i < methodThrowns.length; i++)
-                                       methodThrowns[i] = new 
RestMethodThrown(method.getExceptionTypes()[i]);
+                                       methodThrowns[i] = new 
RestMethodThrown(method.getExceptionTypes()[i], partSerializer, ps);
 
                                // Need this to access methods in anonymous 
inner classes.
                                setAccessible(method, true);
@@ -439,7 +439,7 @@ public class RestJavaMethod implements 
Comparable<RestJavaMethod>  {
         * @param pathInfo The value of {@link 
HttpServletRequest#getPathInfo()} (sorta)
         * @return The HTTP response code.
         */
-       int invoke(String pathInfo, RestRequest req, RestResponse res) throws 
RestException, BadRequest, InternalServerError {
+       int invoke(String pathInfo, RestRequest req, RestResponse res) throws 
Throwable {
 
                String[] patternVals = pathPattern.match(pathInfo);
                if (patternVals == null)
@@ -522,11 +522,7 @@ public class RestJavaMethod implements 
Comparable<RestJavaMethod>  {
                                throw new BadRequest(e2);
                        if (e2 instanceof InvalidDataConversionException)
                                throw new BadRequest(e2);
-                       throw new InternalServerError(e2);
-               } catch (RestException e) {
-                       throw e;
-               } catch (Exception e) {
-                       throw new InternalServerError(e);
+                       throw e2;
                }
                return SC_OK;
        }
@@ -621,4 +617,12 @@ public class RestJavaMethod implements 
Comparable<RestJavaMethod>  {
                        out[i] = vr.resolve(in[i]);
                return out;
        }
+
+       RestMethodReturn getRestMethodReturn() {
+               return this.methodReturn;
+       }
+
+       List<RestMethodThrown> getRestMethodThrown() {
+               return 
Collections.unmodifiableList(Arrays.asList(this.methodThrowns));
+       }
 }
\ No newline at end of file
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodReturn.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodReturn.java
index ffb7fa8..c8f75ee 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodReturn.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodReturn.java
@@ -12,11 +12,14 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest;
 
+import static org.apache.juneau.internal.ReflectionUtils.*;
+
 import java.lang.reflect.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.internal.*;
 
 /**
  * Contains metadata about the return type on a REST Java method.
@@ -26,12 +29,21 @@ public class RestMethodReturn {
        private final Type type;
        private final int code;
        private final ObjectMap api;
+       private final HttpPartSchema schema;
+       private final HttpPartSerializer partSerializer;
+
+       RestMethodReturn(Method m, HttpPartSerializer partSerializer, 
PropertyStore ps) {
+               HttpPartSchema s = HttpPartSchema.DEFAULT;
+               if (hasAnnotation(Response.class, m))
+                       s = HttpPartSchema.create(Response.class, m);
 
-       RestMethodReturn(Type type) {
-               HttpPartSchema s = HttpPartSchema.create(Response.class, type);
-               this.type = type;
+               this.schema = s;
+               this.type = m.getGenericReturnType();
                this.api = HttpPartSchema.getApiCodeMap(s, 200).unmodifiable();
                this.code = s.getCode(200);
+
+               boolean usePS = (s.isUsePartSerializer() || s.getSerializer() 
!= null);
+               this.partSerializer = usePS ? 
ObjectUtils.firstNonNull(ClassUtils.newInstance(HttpPartSerializer.class, 
s.getSerializer(), true, ps), partSerializer) : null;
        }
 
        /**
@@ -60,4 +72,24 @@ public class RestMethodReturn {
        public ObjectMap getApi() {
                return api;
        }
+
+       /**
+        * Returns the schema for the method return type.
+        *
+        * @return The schema for the method return type.  Never <jk>null</jk>.
+        */
+       public HttpPartSchema getSchema() {
+               return schema;
+       }
+
+       /**
+        * Returns the part serializer for the method return type.
+        *
+        * @return
+        *      The part serializer for the method return type.
+        *      <br><jk>null</jk> if {@link Response#usePartSerializer()} is 
<jk>false</jk>.
+        */
+       public HttpPartSerializer getPartSerializer() {
+               return partSerializer;
+       }
 }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodThrown.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodThrown.java
index f37bb67..a4176f5 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodThrown.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodThrown.java
@@ -12,11 +12,12 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest;
 
-import java.lang.reflect.*;
+import static org.apache.juneau.internal.ReflectionUtils.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.httppart.*;
+import org.apache.juneau.internal.*;
 
 /**
  * Contains metadata about a throwable on a REST Java method.
@@ -26,12 +27,21 @@ public class RestMethodThrown {
        final Class<?> type;
        final int code;
        final ObjectMap api;
+       private final HttpPartSchema schema;
+       final HttpPartSerializer partSerializer;
 
-       RestMethodThrown(Class<?> type) {
-               HttpPartSchema s = HttpPartSchema.create(Response.class, type);
+       RestMethodThrown(Class<?> type, HttpPartSerializer partSerializer, 
PropertyStore ps) {
+               HttpPartSchema s = HttpPartSchema.DEFAULT;
+               if (hasAnnotation(Response.class, type))
+                       s = HttpPartSchema.create(Response.class, type);
+
+               this.schema = s;
                this.type = type;
                this.api = HttpPartSchema.getApiCodeMap(s, 500).unmodifiable();
                this.code = s.getCode(500);
+
+               boolean usePS = (s.isUsePartSerializer() || s.getSerializer() 
!= null);
+               this.partSerializer = usePS ? 
ObjectUtils.firstNonNull(ClassUtils.newInstance(HttpPartSerializer.class, 
s.getSerializer(), true, ps), partSerializer) : null;
        }
 
        /**
@@ -39,7 +49,7 @@ public class RestMethodThrown {
         *
         * @return The return type of the Java method.
         */
-       public Type getType() {
+       public Class<?> getType() {
                return type;
        }
 
@@ -60,4 +70,24 @@ public class RestMethodThrown {
        public ObjectMap getApi() {
                return api;
        }
+
+       /**
+        * Returns the schema for the method return type.
+        *
+        * @return The schema for the method return type.  Never <jk>null</jk>.
+        */
+       public HttpPartSchema getSchema() {
+               return schema;
+       }
+
+       /**
+        * Returns the part serializer for the method return type.
+        *
+        * @return
+        *      The part serializer for the method return type.
+        *      <br><jk>null</jk> if {@link Response#usePartSerializer()} is 
<jk>false</jk>.
+        */
+       public HttpPartSerializer getPartSerializer() {
+               return partSerializer;
+       }
 }
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
index 7156308..a45b31c 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
@@ -662,12 +662,14 @@ class RestParamDefaults {
 
        static final class ResponseObject extends RestMethodParam {
                final HttpPartSerializer partSerializer;
+               final boolean usePartSerializer;
                final HttpPartSchema schema;
                private String _default;
 
                protected ResponseObject(Method m, HttpPartSchema s, Type t, 
PropertyStore ps) {
                        super(RESPONSE, m, s.getName(), t, 
HttpPartSchema.getApiCodeMap(s, 200));
-                       this.partSerializer = s.isUsePartSerializer() ? 
ClassUtils.newInstance(HttpPartSerializer.class, s.getSerializer(), true, ps) : 
null;
+                       this.usePartSerializer = s.isUsePartSerializer() || 
s.getSerializer() != null;
+                       this.partSerializer = usePartSerializer ? 
ClassUtils.newInstance(HttpPartSerializer.class, s.getSerializer(), true, ps) : 
null;
                        this.schema = s;
                        this._default = s.getDefault();
 
@@ -679,14 +681,17 @@ class RestParamDefaults {
 
                @SuppressWarnings({ "unchecked", "rawtypes" })
                @Override /* RestMethodParam */
-               public Object resolve(RestRequest req, final RestResponse res) 
throws Exception {
+               public Object resolve(final RestRequest req, final RestResponse 
res) throws Exception {
                        Value<Object> v = (Value<Object>)c.newInstance();
                        v.listener(new ValueListener() {
                                @Override
                                public void onSet(Object newValue) {
                                        try {
-                                               if (partSerializer != null)
-                                                       newValue = new 
StringReader(partSerializer.serialize(HttpPartType.BODY, schema, newValue));
+                                               if (usePartSerializer) {
+                                                       HttpPartSerializer ps = 
partSerializer == null ? req.getPartSerializer() : partSerializer;
+                                                       if (ps != null)
+                                                               newValue = new 
StringReader(ps.serialize(HttpPartType.BODY, schema, newValue));
+                                               }
                                                res.setOutput(newValue);
                                        } catch (SchemaValidationException | 
SerializeException e) {
                                                throw new RuntimeException(e);
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 067ceba..5507f15 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
@@ -1609,4 +1609,27 @@ public final class RestRequest extends 
HttpServletRequestWrapper {
        void setJavaMethod(Method method) {
                this.javaMethod = method;
        }
+
+       /**
+        * Returns metadata about the method return type.
+        *
+        * @return Metadata about the method return type.
+        */
+       public RestMethodReturn getRestMethodReturn() {
+               return restJavaMethod.getRestMethodReturn();
+       }
+
+       /**
+        * Returns metadata about the specified exception.
+        *
+        * @param e
+        * @return Metadata about the specified exception.
+        */
+       public RestMethodThrown getRestMethodThrown(Throwable e) {
+               if (restJavaMethod != null)
+                       for (RestMethodThrown rmt : 
restJavaMethod.getRestMethodThrown())
+                               if 
(rmt.getType().isAssignableFrom(e.getClass()))
+                                       return rmt;
+               return null;
+       }
 }
\ 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 a7f9b0e..daf3fea 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
@@ -572,7 +572,7 @@ public @interface RestResource {
         *      <li class='jf'>{@link RestContext#REST_partParser}
         * </ul>
         */
-       Class<? extends HttpPartParser> partParser() default 
UonPartParser.class;
+       Class<? extends HttpPartParser> partParser() default 
HttpPartParser.Null.class;
 
        /**
         * HTTP part serializer.
@@ -585,7 +585,7 @@ public @interface RestResource {
         *      <li class='jf'>{@link RestContext#REST_partSerializer}
         * </ul>
         */
-       Class<? extends HttpPartSerializer> partSerializer() default 
SimpleUonPartSerializer.class;
+       Class<? extends HttpPartSerializer> partSerializer() default 
HttpPartSerializer.Null.class;
 
        /**
         * Resource path.
@@ -952,7 +952,7 @@ public @interface RestResource {
         * <p>
         * Enables the following:
         * <ul>
-        *      <li>A message and stack trace is printed to STDERR when {@link 
BasicRestCallHandler#handleError(HttpServletRequest, HttpServletResponse, 
RestException)} is called.
+        *      <li>A message and stack trace is printed to STDERR when {@link 
BasicRestCallHandler#handleError(HttpServletRequest, HttpServletResponse, 
RestRequest, Throwable)} is called.
         * </ul>
         *
         * <h5 class='section'>Notes:</h5>
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
index 26a64c4..eaae103 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletRequest.java
@@ -73,6 +73,7 @@ public class MockServletRequest implements 
HttpServletRequest, MockHttpRequest {
        private HttpSession httpSession = MockHttpSession.create();
        private RestContext restContext;
        private String uri = "";
+       private boolean debug = false;
 
        /**
         * Creates a new servlet request.
@@ -221,9 +222,31 @@ public class MockServletRequest implements 
HttpServletRequest, MockHttpRequest {
                if (res.getStatus() == 0)
                        throw new RuntimeException("Response status was 0.");
 
+               if (debug)
+                       log(this, res);
+
                return res;
        }
 
+       private void log(MockServletRequest req, MockServletResponse res) {
+               StringBuilder sb = new StringBuilder();
+               sb.append("\n=== HTTP Call 
=================================================================");
+
+               sb.append("\n=== REQUEST ===");
+               sb.append("\nTODO");
+               sb.append("\n=== RESPONSE ===");
+               sb.append("\nStatus: ").append(res.getStatus());
+               sb.append("\n---response headers---");
+               for (Map.Entry<String,String[]> h : res.getHeaders().entrySet())
+                       for (String h2 : h.getValue())
+                               sb.append("\n").append(h.getKey()).append(": 
").append(h2);
+               sb.append("\n---response content---\n");
+               sb.append(res.getBodyAsString());
+               sb.append("\n=== END 
========================================================================");
+
+               System.err.println(sb);
+       }
+
        /**
         * Fluent setter.
         *
@@ -1326,4 +1349,17 @@ public class MockServletRequest implements 
HttpServletRequest, MockHttpRequest {
        public MockServletRequest warning(Object value) {
                return header("Warning", value);
        }
+
+       /**
+        * Enabled debug mode on this request.
+        *
+        * <p>
+        * Causes information about the request execution to be sent to STDERR.
+        *
+        * @return This object (for method chaining).
+        */
+       public MockServletRequest debug() {
+               this.debug = true;
+               return this;
+       }
 }
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 22cae79..89ed2a9 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
@@ -17,6 +17,7 @@ import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.http.*;
+import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.exception.*;
@@ -50,6 +51,9 @@ public class DefaultHandler implements ResponseHandler {
                String accept = req.getHeaders().getString("Accept", "");
                SerializerMatch sm = g.getSerializerMatch(accept);
 
+               RestMethodReturn rmr = req.getRestMethodReturn();
+               res.setStatus(rmr.getCode());
+
                if (sm != null) {
                        Serializer s = sm.getSerializer();
                        MediaType mediaType = res.getMediaType();
@@ -97,22 +101,37 @@ public class DefaultHandler implements ResponseHandler {
                        } catch (SerializeException e) {
                                throw new InternalServerError(e);
                        }
+                       return true;
+
+               }
+
+               HttpPartSerializer ps = rmr.getPartSerializer();
+               if (ps != null) {
+                       try {
+                               FinishablePrintWriter w = 
res.getNegotiatedWriter();
+                               w.append(ps.serialize(rmr.getSchema(), output));
+                               w.flush();
+                               w.finish();
+                       } catch (SchemaValidationException | SerializeException 
e) {
+                               throw new InternalServerError(e);
+                       }
+                       return true;
+               }
 
                // Non-existent Accept or plain/text can just be serialized 
as-is.
-               } else if ("".equals(accept) || "plain/text".equals(accept)) {
+               if ("".equals(accept) || "plain/text".equals(accept)) {
                        FinishablePrintWriter w = res.getNegotiatedWriter();
                        ClassMeta<?> cm = 
req.getBeanSession().getClassMetaForObject(output);
                        if (cm != null)
                                w.append(cm.toString(output));
                        w.flush();
                        w.finish();
-
-               } else {
-                       throw new NotAcceptable(
-                               "Unsupported media-type in request header 
''Accept'': ''{0}''\n\tSupported media-types: {1}",
-                               req.getHeaders().getString("Accept", ""), 
g.getSupportedMediaTypes()
-                       );
+                       return true;
                }
-               return true;
+
+               throw new NotAcceptable(
+                       "Unsupported media-type in request header ''Accept'': 
''{0}''\n\tSupported media-types: {1}",
+                       req.getHeaders().getString("Accept", ""), 
g.getSupportedMediaTypes()
+               );
        }
 }
diff --git 
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java
 
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java
index 917659b..f5f2317 100644
--- 
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java
+++ 
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/ResponseAnnotationTest.java
@@ -20,10 +20,13 @@ import java.util.*;
 
 import org.apache.juneau.dto.swagger.*;
 import org.apache.juneau.http.annotation.*;
+import org.apache.juneau.httppart.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.serializer.*;
 import org.junit.*;
 import org.junit.runners.*;
+import org.apache.juneau.utils.*;
 
 /**
  * Tests the @Response annotation.
@@ -43,6 +46,461 @@ public class ResponseAnnotationTest {
                return ip.getSwagger(req);
        }
 
+
+       
//=================================================================================================================
+       // Status codes
+       
//=================================================================================================================
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // HTTP status code
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @RestResource
+       public static class A {
+
+               @Response(code=201)
+               @RestMethod(name=GET,path="/codeOnMethod")
+               public String a01() {
+                       return "foo";
+               }
+
+               @RestMethod(name=GET,path="/codeOnClass")
+               public A02 a02() {
+                       return new A02();
+               }
+
+               @RestMethod(name=GET,path="/codeOnThrown")
+               public String a03() throws A03 {
+                       throw new A03();
+               }
+
+               @Response(code=201)
+               @RestMethod(name=GET,path="/codeOnParameter")
+               public void a04(@Response(code=201) Value<String> value) {
+                       value.set("foo");
+               }
+       }
+
+       @Response(code=201)
+       public static class A02 {
+               @Override
+               public String toString() {return "foo";}
+       }
+
+       @Response(code=501)
+       public static class A03 extends Exception {
+               @Override
+               public String toString() {return "foo";}
+       }
+
+       static MockRest a = MockRest.create(A.class);
+
+       @Test
+       public void a01_codeOnMethod() throws Exception {
+               
a.get("/codeOnMethod").execute().assertStatus(201).assertBody("foo");
+       }
+
+       @Test
+       public void a02_codeOnClass() throws Exception {
+               
a.get("/codeOnClass").execute().assertStatus(201).assertBody("foo");
+       }
+
+       @Test
+       public void a03_codeOnThrown() throws Exception {
+               a.get("/codeOnThrown").execute().assertStatus(501);
+       }
+
+       @Test
+       public void a04_codeOnParameter() throws Exception {
+               
a.get("/codeOnParameter").execute().assertStatus(201).assertBody("foo");
+       }
+
+       
//=================================================================================================================
+       // PartSerializers
+       
//=================================================================================================================
+
+       public static class XPartSerializer implements HttpPartSerializer {
+               @Override
+               public HttpPartSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new HttpPartSerializerSession() {
+                               @Override
+                               public String serialize(HttpPartType partType, 
HttpPartSchema schema, Object value) throws SerializeException, 
SchemaValidationException {
+                                       return "x" + value + "x";
+                               }
+                       };
+               }
+
+               @Override
+               public String serialize(HttpPartType partType, HttpPartSchema 
schema, Object value) throws SchemaValidationException, SerializeException {
+                       return createSession(null).serialize(partType, schema, 
value);
+               }
+
+               @Override
+               public String serialize(HttpPartSchema schema, Object value) 
throws SchemaValidationException, SerializeException {
+                       return createSession(null).serialize(null, schema, 
value);
+               }
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // @Response(usePartSerializer)
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @RestResource(partSerializer=XPartSerializer.class)
+       public static class B {
+
+               @Response(usePartSerializer=true)
+               @RestMethod(name=GET,path="/useOnMethod")
+               public String b01() {
+                       return "foo";
+               }
+
+               @Response(usePartSerializer=false)
+               @RestMethod(name=GET,path="/dontUseOnMethod")
+               public String b02() {
+                       return "foo";
+               }
+
+               @RestMethod(name=GET,path="/useOnClass")
+               public B03 b03() {
+                       return new B03();
+               }
+
+               @RestMethod(name=GET,path="/dontUseOnClass")
+               public B04 b04() {
+                       return new B04();
+               }
+
+               @RestMethod(name=GET,path="/useOnThrown")
+               public String b05() throws B05 {
+                       throw new B05();
+               }
+
+               @RestMethod(name=GET,path="/dontUseOnThrown")
+               public String b06() throws B06 {
+                       throw new B06();
+               }
+
+               @RestMethod(name=GET,path="/useOnParameter")
+               public void b07(@Response(usePartSerializer=true) Value<String> 
value) {
+                       value.set("foo");
+               }
+
+               @RestMethod(name=GET,path="/dontUseOnParameter")
+               public void b08(@Response(usePartSerializer=false) 
Value<String> value) {
+                       value.set("foo");
+               }
+
+       }
+
+       @Response(usePartSerializer=true)
+       public static class B03 {
+               @Override
+               public String toString() {return "foo";}
+       }
+
+       @Response(usePartSerializer=false)
+       public static class B04 {
+               @Override
+               public String toString() {return "foo";}
+       }
+
+       @Response(usePartSerializer=true)
+       public static class B05 extends Exception {
+               @Override
+               public String toString() {return "foo";}
+       }
+
+       @Response(usePartSerializer=false)
+       public static class B06 extends Exception {
+               @Override
+               public String toString() {return "foo";}
+       }
+
+       static MockRest b = MockRest.create(B.class);
+
+
+       @Test
+       public void b01_useOnMethod() throws Exception {
+               
b.get("/useOnMethod").execute().assertStatus(200).assertBody("xfoox");
+       }
+
+       @Test
+       public void b02_dontUseOnMethod() throws Exception {
+               
b.get("/dontUseOnMethod").execute().assertStatus(200).assertBody("foo");
+       }
+
+       @Test
+       public void b03_useOnClass() throws Exception {
+               
b.get("/useOnClass").execute().assertStatus(200).assertBody("xfoox");
+       }
+
+       @Test
+       public void b04_dontUseOnClass() throws Exception {
+               
b.get("/dontUseOnClass").execute().assertStatus(200).assertBody("foo");
+       }
+
+       @Test
+       public void b05_useOnThrown() throws Exception {
+               
b.get("/useOnThrown").execute().assertStatus(500).assertBody("xfoox");
+       }
+
+       @Test
+       public void b06_dontUseOnThrown() throws Exception {
+               
b.get("/dontUseOnThrown").execute().assertStatus(500).assertBodyContains("HTTP 
500: Internal Server Error");
+       }
+
+       @Test
+       public void b07_useOnParameter() throws Exception {
+               
b.get("/useOnParameter").execute().assertStatus(200).assertBody("xfoox");
+       }
+
+       @Test
+       public void b08_dontUseOnParameter() throws Exception {
+               
b.get("/dontUseOnParameter").execute().assertStatus(200).assertBody("foo");
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // @Response(partSerializer)
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @RestResource
+       public static class C {
+
+               @Response(partSerializer=XPartSerializer.class)
+               @RestMethod(name=GET,path="/useOnMethod")
+               public String c01() {
+                       return "foo";
+               }
+
+               @Response
+               @RestMethod(name=GET,path="/dontUseOnMethod")
+               public String c02() {
+                       return "foo";
+               }
+
+               @RestMethod(name=GET,path="/useOnClass")
+               public C03 c03() {
+                       return new C03();
+               }
+
+               @RestMethod(name=GET,path="/dontUseOnClass")
+               public C04 c04() {
+                       return new C04();
+               }
+
+               @RestMethod(name=GET,path="/useOnThrown")
+               public String c05() throws C05 {
+                       throw new C05();
+               }
+
+               @RestMethod(name=GET,path="/dontUseOnThrown")
+               public String c06() throws C06 {
+                       throw new C06();
+               }
+
+               @RestMethod(name=GET,path="/useOnParameter")
+               public void c07(@Response(partSerializer=XPartSerializer.class) 
Value<String> value) {
+                       value.set("foo");
+               }
+
+               @RestMethod(name=GET,path="/dontUseOnParameter")
+               public void c08(@Response Value<String> value) {
+                       value.set("foo");
+               }
+
+       }
+
+       @Response(partSerializer=XPartSerializer.class)
+       public static class C03 {
+               @Override
+               public String toString() {return "foo";}
+       }
+
+       @Response
+       public static class C04 {
+               @Override
+               public String toString() {return "foo";}
+       }
+
+       @Response(partSerializer=XPartSerializer.class)
+       public static class C05 extends Exception {
+               @Override
+               public String toString() {return "foo";}
+       }
+
+       @Response
+       public static class C06 extends Exception {
+               @Override
+               public String toString() {return "foo";}
+       }
+
+       static MockRest c = MockRest.create(C.class);
+
+
+       @Test
+       public void c01_useOnMethod() throws Exception {
+               
c.get("/useOnMethod").execute().assertStatus(200).assertBody("xfoox");
+       }
+
+       @Test
+       public void c02_dontUseOnMethod() throws Exception {
+               
c.get("/dontUseOnMethod").execute().assertStatus(200).assertBody("foo");
+       }
+
+       @Test
+       public void c03_useOnClass() throws Exception {
+               
c.get("/useOnClass").execute().assertStatus(200).assertBody("xfoox");
+       }
+
+       @Test
+       public void c04_dontUseOnClass() throws Exception {
+               
c.get("/dontUseOnClass").execute().assertStatus(200).assertBody("foo");
+       }
+
+       @Test
+       public void c05_useOnThrown() throws Exception {
+               
c.get("/useOnThrown").execute().assertStatus(500).assertBody("xfoox");
+       }
+
+       @Test
+       public void c06_dontUseOnThrown() throws Exception {
+               
c.get("/dontUseOnThrown").execute().assertStatus(500).assertBodyContains("HTTP 
500: Internal Server Error");
+       }
+
+       @Test
+       public void c07_useOnParameter() throws Exception {
+               
c.get("/useOnParameter").execute().assertStatus(200).assertBody("xfoox");
+       }
+
+       @Test
+       public void c08_dontUseOnParameter() throws Exception {
+               
c.get("/dontUseOnParameter").execute().assertStatus(200).assertBody("foo");
+       }
+
+       
//-----------------------------------------------------------------------------------------------------------------
+       // @Response(partSerializer) with schemas
+       
//-----------------------------------------------------------------------------------------------------------------
+
+       @RestResource
+       public static class D {
+
+               
@Response(schema=@Schema(collectionFormat="pipes"),usePartSerializer=true)
+               @RestMethod(name=GET,path="/useOnMethod")
+               public String[] d01() {
+                       return new String[]{"foo","bar"};
+               }
+
+               @RestMethod(name=GET,path="/useOnClass")
+               public D02 d02() {
+                       return new D02();
+               }
+
+               @RestMethod(name=GET,path="/useOnThrown")
+               public String d03() throws D03 {
+                       throw new D03();
+               }
+
+               @RestMethod(name=GET,path="/useOnParameter")
+               public void 
d04(@Response(schema=@Schema(collectionFormat="pipes"),usePartSerializer=true) 
Value<String[]> value) {
+                       value.set(new String[]{"foo","bar"});
+               }
+
+               
@Response(schema=@Schema(type="string",format="byte"),usePartSerializer=true)
+               @RestMethod(name=GET,path="/useOnMethodBytes")
+               public byte[] d05() {
+                       return "foo".getBytes();
+               }
+
+               @RestMethod(name=GET,path="/useOnClassBytes")
+               public D06 d06() {
+                       return new D06();
+               }
+
+               @RestMethod(name=GET,path="/useOnThrownBytes")
+               public String d07() throws D07 {
+                       throw new D07();
+               }
+
+
+               @RestMethod(name=GET,path="/useOnParameterBytes")
+               public void 
d08(@Response(schema=@Schema(type="string",format="byte"),usePartSerializer=true)
 Value<byte[]> value) {
+                       value.set("foo".getBytes());
+               }
+
+       }
+
+       
@Response(schema=@Schema(type="array",collectionFormat="pipes"),usePartSerializer=true)
+       public static class D02 {
+               public String[] toStringArray() {
+                       return new String[]{"foo","bar"};
+               }
+       }
+
+       
@Response(schema=@Schema(type="array",collectionFormat="pipes"),usePartSerializer=true)
+       public static class D03 extends Exception {
+               public String[] toStringArray() {
+                       return new String[]{"foo","bar"};
+               }
+       }
+
+       @Response(schema=@Schema(format="byte"),usePartSerializer=true)
+       public static class D06 {
+               public byte[] toBytes() {
+                       return "foo".getBytes();
+               }
+       }
+
+       @Response(schema=@Schema(format="byte"),usePartSerializer=true)
+       public static class D07 extends Exception {
+               public byte[] toBytes() {
+                       return "foo".getBytes();
+               }
+       }
+
+       static MockRest d = MockRest.create(D.class);
+
+
+       @Test
+       public void d01_useOnMethod() throws Exception {
+               
d.get("/useOnMethod").execute().assertStatus(200).assertBody("foo|bar");
+       }
+
+       @Test
+       public void d02_useOnClass() throws Exception {
+               
d.get("/useOnClass").execute().assertStatus(200).assertBody("foo|bar");
+       }
+
+       @Test
+       public void d03_useOnThrown() throws Exception {
+               
d.get("/useOnThrown").execute().assertStatus(500).assertBody("foo|bar");
+       }
+
+       @Test
+       public void d04_useOnParameter() throws Exception {
+               
d.get("/useOnParameter").execute().assertStatus(200).assertBody("foo|bar");
+       }
+
+       @Test
+       public void d05_useOnMethodBytes() throws Exception {
+               
d.get("/useOnMethodBytes").execute().assertStatus(200).assertBody("Zm9v");
+       }
+
+       @Test
+       public void d06_useOnClassBytes() throws Exception {
+               
d.get("/useOnClassBytes").execute().assertStatus(200).assertBody("Zm9v");
+       }
+
+       @Test
+       public void d07_useOnThrownBytes() throws Exception {
+               
d.get("/useOnThrownBytes").execute().assertStatus(500).assertBody("Zm9v");
+       }
+
+       @Test
+       public void d08_useOnParameterBytes() throws Exception {
+               
d.get("/useOnParameterBytes").execute().assertStatus(200).assertBody("Zm9v");
+       }
+
+
        
//=================================================================================================================
        // @Response on POJO
        
//=================================================================================================================

Reply via email to