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 a447cb4  Tests
a447cb4 is described below

commit a447cb4a8d62b8b7a23b19714887b2f4adc36e2d
Author: JamesBognar <jamesbog...@apache.org>
AuthorDate: Sat May 12 12:08:45 2018 -0400

    Tests
---
 .../org/apache/juneau/testutils/TestUtils.java     |   6 +
 .../src/main/java/org/apache/juneau/ClassMeta.java |  74 +++
 juneau-doc/src/main/javadoc/overview.html          | 176 +++++-
 .../rest/test/DefaultContentTypesResource.java     | 140 -----
 .../apache/juneau/rest/test/ParamsResource.java    |   2 +-
 .../java/org/apache/juneau/rest/test/Root.java     |   1 -
 .../juneau/rest/test/DefaultContentTypesTest.java  | 427 -------------
 .../org/apache/juneau/rest/test/ParamsTest.java    |   2 +-
 .../org/apache/juneau/rest/test/_TestSuite.java    |   1 -
 .../apache/juneau/rest/BasicRestCallHandler.java   |   3 +
 .../java/org/apache/juneau/rest/RequestBody.java   |  29 +-
 .../java/org/apache/juneau/rest/RestContext.java   |  12 +-
 .../org/apache/juneau/rest/RestParamDefaults.java  |   9 -
 .../org/apache/juneau/rest/annotation/Body.java    |  77 ++-
 .../juneau/rest/mock/MockServletRequest.java       |  78 ++-
 .../juneau/rest/mock/MockServletResponse.java      |  44 ++
 .../juneau/rest/annotation/BodyAnnotationTest.java | 680 +++++++++++++++++++++
 .../apache/juneau/rest/annotation/BodyTest.java    | 533 ----------------
 .../rest/annotation/DefaultContentTypesTest.java   | 384 ++++++++++++
 .../juneau/rest/annotation/StatusCodesTest.java    |  48 ++
 20 files changed, 1565 insertions(+), 1161 deletions(-)

diff --git 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java
 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java
index cb662e7..abdfced 100644
--- 
a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java
+++ 
b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/testutils/TestUtils.java
@@ -474,6 +474,12 @@ public class TestUtils {
                if (! isEquals(expected, actual))
                        throw new ComparisonFailure(format(msg, args), 
toString(expected), toString(actual));
        }
+       
+       public static final void assertContains(Object value, 
String...substrings) {
+               for (String substring : substrings) 
+                       if (! contains(toString(value), substring))
+                               throw new ComparisonFailure("Text did not 
contain expected substring.", toString(substring), toString(value));
+       }
 
        /**
         * Creates a ClassMeta for the given types.
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index a3e6ddc..1913e26 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -119,6 +119,9 @@ public final class ClassMeta<T> implements Type {
        private final BeanRegistry beanRegistry;                // The bean 
registry of this class meta (if it has one).
        private final ClassMeta<?>[] args;                      // Arg types if 
this is an array of args.
        private final Object example;                          // Example 
object.
+       private final Transform<Reader,T> readerTransform;
+       private final Transform<InputStream,T> inputStreamTransform;
+       private final Transform<String,T> stringTransform;
        
        private ReadWriteLock lock = new ReentrantReadWriteLock(false);
        private Lock rLock = lock.readLock(), wLock = lock.writeLock();
@@ -198,6 +201,9 @@ public final class ClassMeta<T> implements Type {
                        this.exampleField = builder.exampleField;
                        this.example = builder.example;
                        this.args = null;
+                       this.readerTransform = builder.readerTransform;
+                       this.inputStreamTransform = 
builder.inputStreamTransform;
+                       this.stringTransform = builder.stringTransform;
                } finally {
                        wLock.unlock();
                }
@@ -260,6 +266,9 @@ public final class ClassMeta<T> implements Type {
                this.exampleField = mainType.exampleField;
                this.example = mainType.example;
                this.args = null;
+               this.readerTransform = mainType.readerTransform;
+               this.inputStreamTransform = mainType.inputStreamTransform;
+               this.stringTransform = mainType.stringTransform;
        }
 
        /**
@@ -309,6 +318,9 @@ public final class ClassMeta<T> implements Type {
                this.exampleMethod = null;
                this.exampleField = null;
                this.example = null;
+               this.readerTransform = null;
+               this.inputStreamTransform = null;
+               this.stringTransform = null;
        }
 
        @SuppressWarnings({"unchecked","rawtypes","hiding"})
@@ -361,6 +373,9 @@ public final class ClassMeta<T> implements Type {
                Method exampleMethod;
                Field exampleField;
                Object example;
+               Transform<Reader,T> readerTransform;
+               Transform<InputStream,T> inputStreamTransform;
+               Transform<String,T> stringTransform;
 
                ClassMetaBuilder(Class<T> innerClass, BeanContext beanContext, 
Class<? extends T> implClass, BeanFilter beanFilter, PojoSwap<T,?>[] pojoSwaps, 
PojoSwap<?,?>[] childPojoSwaps, Object example) {
                        this.innerClass = innerClass;
@@ -451,6 +466,7 @@ public final class ClassMeta<T> implements Type {
                                        }
                                }
                        }
+                       // TODO - should use transforms for above code.
 
                        // Special cases
                        try {
@@ -748,6 +764,10 @@ public final class ClassMeta<T> implements Type {
                        }
                        
                        this.example = example;
+                       
+                       this.readerTransform = TransformCache.get(Reader.class, 
c);
+                       this.inputStreamTransform = 
TransformCache.get(InputStream.class, c);
+                       this.stringTransform = TransformCache.get(String.class, 
c);
                }
 
                private BeanFilter findBeanFilter() {
@@ -2026,4 +2046,58 @@ public final class ClassMeta<T> implements Type {
        public int hashCode() {
                return super.hashCode();
        }
+
+       /**
+        * Returns <jk>true</jk> if this class has a transform associated with 
it that allows it to be created from a Reader.
+        * 
+        * @return <jk>true</jk> if this class has a transform associated with 
it that allows it to be created from a Reader.
+        */
+       public boolean hasReaderTransform() {
+               return readerTransform != null;
+       }
+       
+       /**
+        * Returns the transform for this class for creating instances from a 
Reader.
+        * 
+        * @return The transform, or <jk>null</jk> if no such transform exists.
+        */
+       public Transform<Reader,T> getReaderTransform() {
+               return readerTransform;
+       }
+
+       /**
+        * Returns <jk>true</jk> if this class has a transform associated with 
it that allows it to be created from an InputStream.
+        * 
+        * @return <jk>true</jk> if this class has a transform associated with 
it that allows it to be created from an InputStream.
+        */
+       public boolean hasInputStreamTransform() {
+               return inputStreamTransform != null;
+       }
+
+       /**
+        * Returns the transform for this class for creating instances from an 
InputStream.
+        * 
+        * @return The transform, or <jk>null</jk> if no such transform exists.
+        */
+       public Transform<InputStream,T> getInputStreamTransform() {
+               return inputStreamTransform;
+       }
+
+       /**
+        * Returns <jk>true</jk> if this class has a transform associated with 
it that allows it to be created from a String.
+        * 
+        * @return <jk>true</jk> if this class has a transform associated with 
it that allows it to be created from a String.
+        */
+       public boolean hasStringTransform() {
+               return stringTransform != null;
+       }
+
+       /**
+        * Returns the transform for this class for creating instances from a 
String.
+        * 
+        * @return The transform, or <jk>null</jk> if no such transform exists.
+        */
+       public Transform<String,T> getStringTransform() {
+               return stringTransform;
+       }
 }
diff --git a/juneau-doc/src/main/javadoc/overview.html 
b/juneau-doc/src/main/javadoc/overview.html
index 4d88d55..29d01ca 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -12279,40 +12279,172 @@
        <h3 class='topic' onclick='toggle(this)'>7.7 - @Body</h3>
        <div class='topic'>
                <p>
-                       The {@link org.apache.juneau.rest.annotation.Body 
@Body} annotation provides easy access to the HTTP body content as any <a 
class='doclink' href='#juneau-marshall.PojoCategories'>parsable</a> POJO type
-                       <br>In the example below, we're POSTing beans.
+                       The {@link org.apache.juneau.rest.annotation.Body 
@Body} annotation is used to identify POJOs to be used as the body of an HTTP 
request.
                </p>
+               <h5 class='figure'>Example:</h5>
                <p class='bcode w800'>
-       <jc>// Example POST of a bean</jc>
-       <ja>@RestMethod</ja>(name=<jsf>POST</jsf>, path=<js>"/"</js>)
-       <jk>public void</jk> doPost(<ja>@Body</ja> Person person) 
<jk>throws</jk> Exception {
-               <jc>// Do something with person.</jc>
+       <ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
+       <jk>public void</jk> addPerson(<ja>@Body</ja> Person person) { 
+               ... 
        }
                </p>
                <p>
-                       The HTTP body of a request can be retrieved as a parsed 
POJO using either the 
-                       {@link org.apache.juneau.rest.RestRequest#getBody()} 
method, or a parameter annotated with 
-                       {@link org.apache.juneau.rest.annotation.Body @Body}.
+                       This is functionally equivalent to the following code...
                </p>
                <p class='bcode w800'>
-       <jc>// Equivalent method 1</jc>
-       <ja>@RestMethod</ja>(name=<jsf>POST</jsf>, path=<js>"/example1"</js>)
-       <jk>public void</jk> doPost1(<ja>@Body</ja> Person p) {
-               <jc>// Do something with p.</jc>
+       <ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
+       <jk>public void</jk> addPerson(RestRequest req) {
+               Person person = req.getBody().asType(Person.<jk>class</jk>);
+               ...
        }
-
-       <jc>// Equivalent method 2</jc>
-       <ja>@RestMethod</ja>(name=<jsf>POST</jsf>, path=<js>"/example2"</js>)
-       <jk>public void</jk> doPost2(RestRequest req) {
-               Person p = req.getBody).asType(Person.<jk>class</jk>);
-               <jc>// Do something with p.</jc>
+               </p>
+               <p>
+                       This annotation can be applied at the following 
locations:
+               </p>
+               <ul class='spaced-list'>
+                       <li>
+                               Parameters on a  {@link RestMethod @RestMethod}.
+                       <li>
+                               POJO classes.
+               </ul>
+               
+               <p>
+                       Any of the following types can be used for the 
parameter or POJO class:
+               </p>
+               <ol class='spaced-list'>
+                       <li>
+                               {@link Reader}
+                               <br><ja>@Body</ja> annotation is optional.
+                               <br><code>Content-Type</code> is ignored.
+                       <li>
+                               {@link InputStream} 
+                               <br><ja>@Body</ja> annotation is optional.
+                               <br><code>Content-Type</code> is ignored.
+                       <li>
+                               Any <a class='doclink' 
href='../../../../../overview-summary.html#juneau-marshall.PojoCategories'>parsable</a>
 POJO type.
+                               <br><code>Content-Type</code> is required to 
identify correct parser.
+                       <li>
+                               Objects convertible from {@link 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>
+                               <br><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 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>
+                               <br><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 String} 
(including <code>String</code> itself) by having one of the following 
non-deprecated methods:
+                               <ul>
+                                       <li><code><jk>public</jk> T(String in) 
{...}</code> (e.g. {@link Integer}, {@link Boolean})
+                                       <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>fromValue</jsm>(String in) {...}</code>
+                                       <li><code><jk>public static</jk> T 
<jsm>valueOf</jsm>(String in) {...}</code> (e.g. enums)
+                                       <li><code><jk>public static</jk> T 
<jsm>parse</jsm>(String in) {...}</code> (e.g. {@link Level})
+                                       <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> (e.g. {@link Class}, {@link Charset})
+                                       <li><code><jk>public static</jk> T 
<jsm>forString</jsm>(String in) {...}</code>
+                               </ul>
+                               <br><code>Content-Type</code> must not be 
present or match an existing parser so that it's not parsed as a POJO.
+               </ol>
+               <p>
+                       Special note should be taken on using {@link String} as 
the body object:
+               </p>
+               <p class='bcode w800'>
+       <ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
+       <jk>public void</jk> add(<ja>@Body</ja> String body) { 
+               ... 
        }
                </p>
                <p>
-                       The Juneau framework will automatically determine the 
appropriate <l>Parser</l> to use based on the 
-                       <l>Content-Type</l> HTTP header.  
-                       <br>So the body content could be JSON or XML or any 
other supported parsing types.
+                       In the case above, when the <code>Content-Type</code> 
header is present and matches a parser, the body will be parsed into a 
<code>String</code> using the matched parser
+                       using rule #3 above.
+                       <br>For example, passing in a body of <js>"'foo'"</js> 
with the header <code>Content-Type: application/json</code> will result in the 
body being populated with
+                       <js>"foo"</js>.
+               </p>
+               <p>
+                       When the <code>Content-Type</code> header is not 
present or match a parser, the body is pass as-is using rule #6 above.
+                       <br>For example, passing in a body of <js>"'foo'"</js> 
with no <code>Content-Type</code> header will result in the body being 
populated with
+                       <js>"'foo'"</js>.
                </p>
+               <p>
+                       The <ja>@Body</ja> annotation can also be used on POJO 
classes used as parameters on a REST method.
+                       <br>This can be useful if you're reusing the same POJOs 
often in your REST interface and don't want to redefine your Swagger on each 
method.
+               </p>
+               
+               <h5 class='figure'>Examples:</h5>
+               <p class='bcode w800'>
+       <ja>@Body</ja>(description=<js>"POJO convertible from String"</js>)</ja>
+       <jk>public static class</jk> A {
+               <jk>private</jk> String <jf>val</jf>;
+               <jk>public</jk> A(String val) {
+                       <jk>this</jk>.<jf>val</jf> = val;
+               }
+               <jk>public</jk> String toString() {
+                       <jk>return</jk> <jf>val</jf>;
+               }
+       }
+
+       <ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, 
path=<js>"/testPojoFromString"</js>)
+       <jk>public</jk> A testPojoFromString(A a) {
+               <jk>return</jk> a;
+       }
+               </p>
+               <p class='bcode w800'>
+       <ja>@Body</ja>(description=<js>"Bean POJO"</js>)</ja>
+       <jk>public static class</jk> B {
+               <jk>public</jk> String <jf>f1</jf>;
+       }
+
+       <ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/testBean"</js>)
+       <jk>public</jk> B testBean(B b) {
+               <jk>return</jk> b;
+       }
+               </p>
+               <p class='bcode w800'>
+       <ja>@Body</ja>(description=<js>"Bean list"</js>)</ja>
+       <jk>public static class</jk> C extends LinkedList&lt;B&gt; {}
+       
+       <ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, path=<js>"/testBeanList"</js>)
+       <jk>public</jk> C testString(C c) {
+               <jk>return</jk> c;
+       }
+               </p>
+               <p class='bcode w800'>
+       <ja>@Body</ja>(description=<js>"POJO convertible from input 
stream"</js>)</ja>
+       <jk>public static class</jk> D {
+               <jk>private</jk> String <jf>val</jf>;
+               <jk>public</jk> D(InputStream is) {
+                       <jk>this</jk>.<jf>val</jf> = 
IOUtils.<jsm>read</jsm>(is);
+               }
+               <jk>public</jk> String toString() {
+                       <jk>return</jk> <jf>val</jf>;
+               }
+       }
+
+       <ja>@RestMethod</ja>(name=<jsf>PUT</jsf>, 
path=<js>"/testPojoFromInputStream"</js>)
+       <jk>public</jk> D testPojoFromInputStream(D d) {
+               <jk>return</jk> d;
+       }
+               </p>
+               
+               <h5 class='section'>Notes:</h5>
+               <ul class='spaced-list'>
+                       <li>
+                               Annotation parameter values will be aggregated 
when used on POJO parent and child classes. 
+                               <br>Values on child classes override values on 
parent classes.
+                       <li>
+                               Annotation parameter values will be aggregated 
when used on both POJOs and REST methods. 
+                               <br>Values on methods override values on POJO 
classes.
+               </ul>
+               
                <h5 class='section'>See Also:</h5>
                <ul>
                        <li class='ja'>{@link 
org.apache.juneau.rest.annotation.Body}
diff --git 
a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java
 
b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java
deleted file mode 100644
index c15a0d7..0000000
--- 
a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java
+++ /dev/null
@@ -1,140 +0,0 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.rest.test;
-
-import static org.apache.juneau.http.HttpMethodName.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.parser.*;
-import org.apache.juneau.rest.*;
-import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.serializer.*;
-
-/**
- * JUnit automated testcase resource.
- */
-@RestResource(
-       path="/testDefaultContentTypes",
-       defaultRequestHeaders={" Accept : text/s2 "," Content-Type : text/p2 "},
-       
parsers={DefaultContentTypesResource.P1.class,DefaultContentTypesResource.P2.class},
 
serializers={DefaultContentTypesResource.S1.class,DefaultContentTypesResource.S2.class}
-)
-public class DefaultContentTypesResource extends RestServlet {
-       private static final long serialVersionUID = 1L;
-
-       public static class P1 extends DummyParser { public P1(PropertyStore 
ps) {super(ps, "p1", "text/p1");}}
-
-       public static class P2 extends DummyParser { public P2(PropertyStore 
ps) {super(ps, "p2", "text/p2");}}
-
-       public static class P3 extends DummyParser { public P3(PropertyStore 
ps) {super(ps, "p3", "text/p3");}}
-
-       public static class S1 extends DummySerializer { public 
S1(PropertyStore ps) {super(ps, "s1", "text/s1");}}
-
-       public static class S2 extends DummySerializer { public 
S2(PropertyStore ps) {super(ps, "s2", "text/s2");}}
-
-       public static class S3 extends DummySerializer { public 
S3(PropertyStore ps) {super(ps, "s3", "text/s3");}}
-
-       /**
-        * Test that default Accept and Content-Type headers on servlet 
annotation are picked up.
-        */
-       @RestMethod(name=PUT, path="/testDefaultHeadersOnServletAnnotation")
-       public String testDefaultHeadersOnServletAnnotation(@Body String in) {
-               return in;
-       }
-
-       
//====================================================================================================
-       // Test that default Accept and Content-Type headers on servlet 
annotation are picked up
-       // when @RestMethod.parsers/serializers annotations are used.
-       
//====================================================================================================
-       @RestMethod(name=PUT, path="/testRestMethodParsersSerializers", 
parsers=P3.class, serializers=S3.class)
-       public String testRestMethodParsersSerializers(@Body String in) {
-               return in;
-       }
-
-       
//====================================================================================================
-       // Test that default Accept and Content-Type headers on servlet 
annotation are picked up
-       // when @RestMethod.addParsers/addSerializers annotations are used.
-       
//====================================================================================================
-       @RestMethod(name=PUT, path="/testRestMethodAddParsersSerializers", 
parsers=P3.class, serializers=S3.class, inherit="SERIALIZERS,PARSERS")
-       public String testRestMethodAddParsersSerializers(@Body String in) {
-               return in;
-       }
-
-       
//====================================================================================================
-       // Various Accept incantations.
-       
//====================================================================================================
-       @RestMethod(name=PUT, path="/testAccept")
-       public String testAccept(@Body String in) {
-               return in;
-       }
-
-       
//====================================================================================================
-       // Test that default Accept and Content-Type headers on method 
annotation are picked up
-       // when @RestMethod.parsers/serializers annotations are used.
-       
//====================================================================================================
-       @RestMethod(name=PUT, 
path="/testRestMethodParserSerializerAnnotations", 
defaultRequestHeaders={"Accept: text/s3","Content-Type: text/p3"}, 
parsers=P3.class, serializers=S3.class)
-       public String testRestMethodParserSerializerAnnotations(@Body String 
in) {
-               return in;
-       }
-
-       
//====================================================================================================
-       // Test that default Accept and Content-Type headers on method 
annotation are picked up
-       //      when @RestMethod.addParsers/addSerializers annotations are used.
-       
//====================================================================================================
-       @RestMethod(name=PUT, 
path="/testRestMethodAddParsersSerializersAnnotations", 
defaultRequestHeaders={"Accept: text/s3","Content-Type: text/p3"}, 
parsers=P3.class, serializers=S3.class, inherit="SERIALIZERS,PARSERS")
-       public String testRestMethodAddParsersSerializersAnnotations(@Body 
String in) {
-               return in;
-       }
-
-       public static class DummyParser extends ReaderParser {
-
-               private String name;
-
-               private DummyParser(PropertyStore ps, String name, 
String...consumes) {
-                       super(ps, consumes);
-                       this.name = name;
-               }
-
-               @Override /* Parser */
-               public ReaderParserSession createSession(ParserSessionArgs 
args) {
-                       return new ReaderParserSession(args) {
-
-                               @Override /* ParserSession */
-                               @SuppressWarnings("unchecked")
-                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
-                                       return (T)name;
-                               }
-                       };
-               }
-       }
-
-       public static class DummySerializer extends WriterSerializer {
-
-               private String name;
-
-               private DummySerializer(PropertyStore ps, String name, String 
produces) {
-                       super(ps, produces, null);
-                       this.name = name;
-               }
-
-               @Override /* Serializer */
-               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
-                       return new WriterSerializerSession(args) {
-
-                               @Override /* SerializerSession */
-                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
-                                       out.getWriter().write(name + "/" + o);
-                               }
-                       };
-               }
-       }
-}
diff --git 
a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/ParamsResource.java
 
b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/ParamsResource.java
index 69fe0e0..e15ca28 100644
--- 
a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/ParamsResource.java
+++ 
b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/ParamsResource.java
@@ -401,7 +401,7 @@ public class ParamsResource extends BasicRestServlet {
                return t != null;
        }
 
-       @RestMethod(name=GET, path="/otherObjects/Parser")
+       @RestMethod(name=GET, 
path="/otherObjects/Parser",parsers={JsonParser.class})
        public String testOtherParser(Parser t) {
                return t.getClass().getName();
        }
diff --git 
a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/Root.java
 
b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/Root.java
index 3b4973e..119996e 100644
--- 
a/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/Root.java
+++ 
b/juneau-microservice/juneau-microservice-test/src/main/java/org/apache/juneau/rest/test/Root.java
@@ -32,7 +32,6 @@ import org.apache.juneau.rest.helper.*;
                ClientFuturesResource.class,
                ClientVersionResource.class,
                ConfigResource.class,
-               DefaultContentTypesResource.class,
                ErrorConditionsResource.class,
                TransformsResource.class,
                FormDataResource.class,
diff --git 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/DefaultContentTypesTest.java
 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/DefaultContentTypesTest.java
deleted file mode 100644
index 9ce9e19..0000000
--- 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/DefaultContentTypesTest.java
+++ /dev/null
@@ -1,427 +0,0 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.rest.test;
-
-import static javax.servlet.http.HttpServletResponse.*;
-import static org.apache.juneau.microservice.testutils.TestUtils.*;
-import static org.junit.Assert.*;
-
-import org.apache.juneau.rest.client.*;
-import org.junit.*;
-
-
-public class DefaultContentTypesTest extends RestTestcase {
-
-       private static String URL = "/testDefaultContentTypes";
-       private static boolean debug = false;
-
-       
//====================================================================================================
-       // Test that default Accept and Content-Type headers on servlet 
annotation are picked up.
-       
//====================================================================================================
-       @Test
-       public void testDefaultHeadersOnServletAnnotation() throws Exception {
-               RestClient client = TestMicroservice.DEFAULT_CLIENT;
-               String r;
-
-               String url = URL + "/testDefaultHeadersOnServletAnnotation";
-
-               r = client.doPut(url, 
"").accept("").contentType("").getResponseAsString();
-               assertEquals("s2/p2", r);
-
-               r = client.doPut(url, 
"").accept("text/s1").contentType("").getResponseAsString();
-               assertEquals("s1/p2", r);
-
-               r = client.doPut(url, 
"").accept("").contentType("text/p1").getResponseAsString();
-               assertEquals("s2/p1", r);
-
-               r = client.doPut(url, 
"").accept("text/s1").contentType("text/p1").getResponseAsString();
-               assertEquals("s1/p1", r);
-
-               r = client.doPut(url, 
"").accept("text/s2").contentType("").getResponseAsString();
-               assertEquals("s2/p2", r);
-
-               r = client.doPut(url, 
"").accept("").contentType("text/p2").getResponseAsString();
-               assertEquals("s2/p2", r);
-
-               r = client.doPut(url, 
"").accept("text/s2").contentType("text/p2").getResponseAsString();
-               assertEquals("s2/p2", r);
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s3").contentType("").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
-                               "Unsupported media-type in request header 
'Accept': 'text/s3'",
-                               "Supported media-types: ['text/s1','text/s2']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("").contentType("text/p3").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p3'",
-                               "Supported media-types: ['text/p1','text/p2']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s3").contentType("text/p3").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p3'",
-                               "Supported media-types: ['text/p1','text/p2']"
-                       );
-               }
-       }
-
-       
//====================================================================================================
-       // Test that default Accept and Content-Type headers on servlet 
annotation are picked up
-       // when @RestMethod.parsers/serializers annotations are used.
-       
//====================================================================================================
-       @Test
-       public void testRestMethodParsersSerializers() throws Exception {
-               RestClient client = TestMicroservice.DEFAULT_CLIENT;
-               String r;
-
-               String url = URL + "/testRestMethodParsersSerializers";
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("").contentType("").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s1").contentType("").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("").contentType("text/p1").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p1'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s1").contentType("text/p1").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p1'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s2").contentType("").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("").contentType("text/p2").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s2").contentType("text/p2").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s3").contentType("").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("").contentType("text/p3").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
-                               "Unsupported media-type in request header 
'Accept': 'text/s2'",
-                               "Supported media-types: ['text/s3']"
-                       );
-               }
-
-               r = client.doPut(url, 
"").accept("text/s3").contentType("text/p3").getResponseAsString();
-               assertEquals("s3/p3", r);
-       }
-
-       
//====================================================================================================
-       // Test that default Accept and Content-Type headers on servlet 
annotation are picked up
-       // when @RestMethod.addParsers/addSerializers annotations are used.
-       
//====================================================================================================
-       @Test
-       public void testRestMethodAddParsersSerializers() throws Exception {
-               RestClient client = TestMicroservice.DEFAULT_CLIENT;
-               String r;
-
-               String url = URL + "/testRestMethodAddParsersSerializers";
-
-               r = client.doPut(url, 
"").accept("").contentType("").getResponseAsString();
-               assertEquals("s2/p2", r);
-
-               r = client.doPut(url, 
"").accept("text/s1").contentType("").getResponseAsString();
-               assertEquals("s1/p2", r);
-
-               r = client.doPut(url, 
"").accept("").contentType("text/p1").getResponseAsString();
-               assertEquals("s2/p1", r);
-
-               r = client.doPut(url, 
"").accept("text/s1").contentType("text/p1").getResponseAsString();
-               assertEquals("s1/p1", r);
-
-               r = client.doPut(url, 
"").accept("text/s2").contentType("").getResponseAsString();
-               assertEquals("s2/p2", r);
-
-               r = client.doPut(url, 
"").accept("").contentType("text/p2").getResponseAsString();
-               assertEquals("s2/p2", r);
-
-               r = client.doPut(url, 
"").accept("text/s2").contentType("text/p2").getResponseAsString();
-               assertEquals("s2/p2", r);
-
-               r = client.doPut(url, 
"").accept("text/s3").contentType("").getResponseAsString();
-               assertEquals("s3/p2", r);
-
-               r = client.doPut(url, 
"").accept("").contentType("text/p3").getResponseAsString();
-               assertEquals("s2/p3", r);
-
-               r = client.doPut(url, 
"").accept("text/s3").contentType("text/p3").getResponseAsString();
-               assertEquals("s3/p3", r);
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("").contentType("text/p4").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       // Note that parsers defined on method are listed 
before parsers defined on class.
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p4'",
-                               "Supported media-types: 
['text/p3','text/p1','text/p2']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s4").contentType("").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       // Note that serializers defined on method are listed 
before serializers defined on class.
-                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
-                               "Unsupported media-type in request header 
'Accept': 'text/s4'",
-                               "Supported media-types: 
['text/s3','text/s1','text/s2']"
-                       );
-               }
-       }
-
-       
//====================================================================================================
-       // Various Accept incantations.
-       
//====================================================================================================
-       @Test
-       public void testAccept() throws Exception {
-               RestClient client = 
TestMicroservice.client().contentType("text/p1").build();
-               String r;
-
-               String url = URL + "/testAccept";
-
-               // "*/*" should match the first serializer, not the default 
serializer.
-               r = client.doPut(url, "").accept("*/*").getResponseAsString();
-               assertEquals("s1/p1", r);
-
-               // "text/*" should match the first serializer, not the default 
serializer.
-               r = client.doPut(url, 
"").accept("text/*").getResponseAsString();
-               assertEquals("s1/p1", r);
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("bad/*").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
-                               "Unsupported media-type in request header 
'Accept': 'bad/*'",
-                               "Supported media-types: ['text/s1','text/s2']"
-                       );
-               }
-
-               r = client.doPut(url, 
"").accept("bad/*,text/*").getResponseAsString();
-               assertEquals("s1/p1", r);
-
-               r = client.doPut(url, 
"").accept("text/*,bad/*").getResponseAsString();
-               assertEquals("s1/p1", r);
-
-               r = client.doPut(url, 
"").accept("text/s1;q=0.5,text/s2").getResponseAsString();
-               assertEquals("s2/p1", r);
-
-               r = client.doPut(url, 
"").accept("text/s1,text/s2;q=0.5").getResponseAsString();
-               assertEquals("s1/p1", r);
-
-               client.closeQuietly();
-       }
-
-       
//====================================================================================================
-       // Test that default Accept and Content-Type headers on method 
annotation are picked up
-       // when @RestMethod.parsers/serializers annotations are used.
-       
//====================================================================================================
-       @Test
-       public void testRestMethodParserSerializerAnnotations() throws 
Exception {
-               RestClient client = TestMicroservice.DEFAULT_CLIENT;
-               String r;
-
-               String url = URL + "/testRestMethodParserSerializerAnnotations";
-
-               r = client.doPut(url, 
"").accept("").contentType("").getResponseAsString();
-               assertEquals("s3/p3", r);
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s1").contentType("").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
-                               "Unsupported media-type in request header 
'Accept': 'text/s1'",
-                               "Supported media-types: ['text/s3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("").contentType("text/p1").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p1'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s1").contentType("text/p1").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p1'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s2").contentType("").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
-                               "Unsupported media-type in request header 
'Accept': 'text/s2'",
-                               "Supported media-types: ['text/s3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("").contentType("text/p2").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               try {
-                       r = client.doPut(url+"?noTrace=true", 
"").accept("text/s2").contentType("text/p2").getResponseAsString();
-                       fail("Exception expected");
-               } catch (RestCallException e) {
-                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
-                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
-                               "Supported media-types: ['text/p3']"
-                       );
-               }
-
-               r = client.doPut(url, 
"").accept("text/s3").contentType("").getResponseAsString();
-               assertEquals("s3/p3", r);
-
-               r = client.doPut(url, 
"").accept("").contentType("text/p3").getResponseAsString();
-               assertEquals("s3/p3", r);
-
-               r = client.doPut(url, 
"").accept("text/s3").contentType("text/p3").getResponseAsString();
-               assertEquals("s3/p3", r);
-       }
-
-       
//====================================================================================================
-       // Test that default Accept and Content-Type headers on method 
annotation are picked up
-       //      when @RestMethod.addParsers/addSerializers annotations are used.
-       
//====================================================================================================
-       @Test
-       public void testRestMethodAddParsersSerializersAnnotations() throws 
Exception {
-               RestClient client = TestMicroservice.DEFAULT_CLIENT;
-               String r;
-
-               String url = URL + 
"/testRestMethodAddParsersSerializersAnnotations";
-
-               r = client.doPut(url, 
"").accept("").contentType("").getResponseAsString();
-               assertEquals("s3/p3", r);
-
-               r = client.doPut(url, 
"").accept("text/s1").contentType("").getResponseAsString();
-               assertEquals("s1/p3", r);
-
-               r = client.doPut(url, 
"").accept("").contentType("text/p1").getResponseAsString();
-               assertEquals("s3/p1", r);
-
-               r = client.doPut(url, 
"").accept("text/s1").contentType("text/p1").getResponseAsString();
-               assertEquals("s1/p1", r);
-
-               r = client.doPut(url, 
"").accept("text/s2").contentType("").getResponseAsString();
-               assertEquals("s2/p3", r);
-
-               r = client.doPut(url, 
"").accept("").contentType("text/p2").getResponseAsString();
-               assertEquals("s3/p2", r);
-
-               r = client.doPut(url, 
"").accept("text/s2").contentType("text/p2").getResponseAsString();
-               assertEquals("s2/p2", r);
-
-               r = client.doPut(url, 
"").accept("text/s3").contentType("").getResponseAsString();
-               assertEquals("s3/p3", r);
-
-               r = client.doPut(url, 
"").accept("").contentType("text/p3").getResponseAsString();
-               assertEquals("s3/p3", r);
-
-               r = client.doPut(url, 
"").accept("text/s3").contentType("text/p3").getResponseAsString();
-               assertEquals("s3/p3", r);
-       }
-}
diff --git 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ParamsTest.java
 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ParamsTest.java
index bd7bf6f..72cd276 100644
--- 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ParamsTest.java
+++ 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ParamsTest.java
@@ -811,7 +811,7 @@ public class ParamsTest extends RestTestcase {
 
        @Test
        public void testOtherParser() throws Exception {
-               String r = CLIENT.doGet(URL + 
"/otherObjects/Parser").getResponseAsString();
+               String r = CLIENT.doGet(URL + 
"/otherObjects/Parser").contentType("application/json").getResponseAsString();
                assertEquals("\"org.apache.juneau.json.JsonParser\"", r);
        }
 
diff --git 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
index 6841615..724cf8d 100644
--- 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
+++ 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
@@ -31,7 +31,6 @@ import org.junit.runners.Suite.*;
        ClientFuturesTest.class,
        ClientVersionTest.class,
        ConfigTest.class,
-       DefaultContentTypesTest.class,
        ErrorConditionsTest.class,
        FormDataTest.class,
        GroupsTest.class,
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 b0d007b..6ff40d7 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
@@ -167,6 +167,9 @@ public class BasicRestCallHandler implements 
RestCallHandler {
                                // If not invoked above, see if it's an OPTIONs 
request
                                if (rc != SC_OK)
                                        handleNotFound(rc, req, res);
+                               
+                               if (res.getStatus() == 0)
+                                       res.setStatus(rc);
                        }
 
                        if (res.hasOutput()) {
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
index b5e7c4a..0df1e58 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
@@ -343,16 +343,19 @@ public class RequestBody {
        public ParserMatch getParserMatch() {
                if (mediaType != null && parser != null)
                        return new ParserMatch(mediaType, parser);
+               MediaType mt = getMediaType();
+               return mt == null ? null : parsers.getParserMatch(mt);
+       }
+       
+       private MediaType getMediaType() {
+               if (mediaType != null)
+                       return mediaType;
                MediaType mediaType = headers.getContentType();
-               if (isEmpty(mediaType)) {
-                       if (body != null)
-                               mediaType = MediaType.UON;
-                       else
-                               mediaType = MediaType.JSON;
-               }
-               return parsers.getParserMatch(mediaType);
+               if (mediaType == null && body != null) 
+                       return MediaType.UON;
+               return mediaType;
        }
-
+       
        /**
         * Returns the parser matching the request <code>Content-Type</code> 
header.
         * 
@@ -423,7 +426,17 @@ public class RequestBody {
                                        );
                                }
                        }
+                       
+                       if (cm.hasReaderTransform())
+                               return 
cm.getReaderTransform().transform(getReader());
 
+                       if (cm.hasInputStreamTransform())
+                               return 
cm.getInputStreamTransform().transform(getInputStream());
+                       
+                       MediaType mt = getMediaType();
+                       if ((isEmpty(mt) || mt.toString().equals("text/plain")) 
&& cm.hasStringTransform())
+                               return 
cm.getStringTransform().transform(asString());
+                       
                        throw new UnsupportedMediaType(
                                "Unsupported media-type in request header 
''Content-Type'': ''{0}''\n\tSupported media-types: {1}",
                                headers.getContentType(), 
req.getParsers().getSupportedMediaTypes()
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 097138a..abc0529 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
@@ -3029,10 +3029,16 @@ public final class RestContext extends BeanContext {
                                                                                
        try {
                                                                                
                // Parse the args and invoke the method.
                                                                                
                Parser p = req.getBody().getParser();
-                                                                               
                try (Closeable in = p.isReaderParser() ? req.getReader() : 
req.getInputStream()) {
-                                                                               
                        Object output = m.invoke(o, p.parseArgs(in, 
m.getGenericParameterTypes()));
-                                                                               
                        res.setOutput(output);
+                                                                               
                Object[] args = null;
+                                                                               
                if (m.getGenericParameterTypes().length == 0)
+                                                                               
                        args = new Object[0];
+                                                                               
                else {
+                                                                               
                        try (Closeable in = p.isReaderParser() ? 
req.getReader() : req.getInputStream()) {
+                                                                               
                                args = p.parseArgs(in, 
m.getGenericParameterTypes());
+                                                                               
                        }
                                                                                
                }
+                                                                               
                Object output = m.invoke(o, args);
+                                                                               
                res.setOutput(output);
                                                                                
                return SC_OK;
                                                                                
        } catch (Exception e) {
                                                                                
                throw new InternalServerError(e);
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 a0a33c0..e55623a 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
@@ -589,21 +589,12 @@ class RestParamDefaults {
 
        static final class BodyObject extends RestMethodParam {
                
-               private final Transform<Reader,?> readerTransform;
-               private final Transform<InputStream,?> inputStreamTransform;
-
                protected BodyObject(Method method, Body a, Type type, 
RestMethodParam existing) {
                        super(BODY, method, null, type, getMetaData(a, 
castOrNull(existing, BodyObject.class)));
-                       readerTransform = TransformCache.get(Reader.class, 
getTypeClass());
-                       inputStreamTransform = 
TransformCache.get(InputStream.class, getTypeClass());
                }
 
                @Override /* RestMethodParam */
                public Object resolve(RestRequest req, RestResponse res) throws 
Exception {
-                       if (readerTransform != null)
-                               return 
readerTransform.transform(req.getReader());  // Also passes Reader through.
-                       if (inputStreamTransform != null)
-                               return 
inputStreamTransform.transform(req.getInputStream());  // Also passes 
InputStream through.
                        return req.getBody().asType(type);
                }
                
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java
index 085fe31..3d6beb3 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/Body.java
@@ -17,15 +17,19 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.io.*;
 import java.lang.annotation.*;
+import java.nio.charset.*;
+import java.util.logging.*;
 
 import org.apache.juneau.rest.*;
 
 /**
- * Annotation that can be applied to a parameter of a {@link RestMethod 
@RestMethod} annotated method or POJO class to identify it as the HTTP
- * request body converted to a POJO.
+ * REST request body annotation.
+ * 
+ * <p>
+ * Identifies a POJO to be used as the body of an HTTP request.
  * 
  * <h5 class='section'>Example:</h5>
- * <p class='bcode'>
+ * <p class='bcode w800'>
  *     <ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
  *     <jk>public void</jk> addPerson(<ja>@Body</ja> Person person) {
  *             ...
@@ -34,36 +38,81 @@ import org.apache.juneau.rest.*;
  * 
  * <p>
  * This is functionally equivalent to the following code...
- * <p class='bcode'>
+ * <p class='bcode w800'>
  *     <ja>@RestMethod</ja>(name=<jsf>POST</jsf>)
- *     <jk>public void</jk> addPerson(RestRequest req, RestResponse res) {
+ *     <jk>public void</jk> addPerson(RestRequest req) {
  *             Person person = req.getBody().asType(Person.<jk>class</jk>);
  *             ...
  *     }
  * </p>
  * 
+ * <p>
+ * This annotation can be applied to the following:
+ * <ul class='spaced-list'>
+ *     <li>
+ *             Parameters on a  {@link RestMethod @RestMethod}.
+ *     <li>
+ *             POJO classes.
+ * </ul>
+ * 
+ * <p>
  * Any of the following types can be used for the parameter:
- * <ul>
- *     <li>{@link Reader}
- *     <li>{@link InputStream}
- *     <li>Primitives (e.g. <code>String</code>, <jk>int</jk>, 
<jk>boolean</jk>, etc...)
- *     <li>Beans
- *     <li>Maps, collections, or arrays of beans or primitives.
- *     <li>Any object convertible from a {@link Reader} by having one of the 
following methods:
+ * <ul class='spaced-list'>
+ *     <li>
+ *             {@link Reader}
+ *             <br><ja>@Body</ja> annotation is optional.
+ *             <br><code>Content-Type</code> is always ignored.
+ *     <li>
+ *             {@link InputStream} 
+ *             <br><ja>@Body</ja> annotation is optional.
+ *             <br><code>Content-Type</code> is always ignored.
+ *     <li>
+ *             Any <a class='doclink' 
href='../../../../../overview-summary.html#juneau-marshall.PojoCategories'>parsable</a>
 POJO type.
+ *             <br><code>Content-Type</code> is required to identify correct 
parser.
+ *     <li>
+ *             Objects convertible from {@link 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>
- *     </ul>
- *     <li>Any object convertible from an {@link InputStream} by having one of 
the following methods:
+ *             <br><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 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>
+ *             <br><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 String} (including 
<code>String</code> itself) by having one of the following non-deprecated 
methods:
+ *             <ul>
+ *                     <li><code><jk>public</jk> T(String in) {...}</code> 
(e.g. {@link Integer}, {@link Boolean})
+ *                     <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>fromValue</jsm>(String in) {...}</code>
+ *                     <li><code><jk>public static</jk> T 
<jsm>valueOf</jsm>(String in) {...}</code> (e.g. enums)
+ *                     <li><code><jk>public static</jk> T 
<jsm>parse</jsm>(String in) {...}</code> (e.g. {@link Level})
+ *                     <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> (e.g. {@link Class}, {@link Charset})
+ *                     <li><code><jk>public static</jk> T 
<jsm>forString</jsm>(String in) {...}</code>
+ *             </ul>
+ *             <br><code>Content-Type</code> must not be present or match an 
existing parser so that it's not parsed as a POJO.
+ * </ul>
+ * 
+ * 
+ * <h5 class='section'>Notes:</h5>
+ * <ul class='spaced-list'>
+ *     <li>
+ *             Annotation parameter values will be aggregated when used on 
POJO parent and child classes. 
+ *             <br>Values on child classes override values on parent classes.
+ *     <li>
+ *             Annotation parameter values will be aggregated when used on 
both POJOs and REST methods. 
+ *             <br>Values on methods override values on POJO classes.
  * </ul>
  * 
+ * 
  * <h5 class='section'>See Also:</h5>
  * <ul>
  *     <li class='link'><a class="doclink" 
href="../../../../../overview-summary.html#juneau-rest-server.Body">Overview 
&gt; juneau-rest-server &gt; @Body</a>
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 142b3a2..5369758 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
@@ -84,7 +84,6 @@ public class MockServletRequest implements HttpServletRequest 
{
         */
        public static MockServletRequest create() {
                MockServletRequest r = new MockServletRequest();
-               r.header("Accept", "text/json+simple").header("Content-Type", 
"text/json");
                return r;
        }
        
@@ -110,6 +109,78 @@ public class MockServletRequest implements 
HttpServletRequest {
        }
        
        /**
+        * Convenience method for setting <code>Accept</code> and 
<code>Content-Type</code> headers to <js>"application/json"</js>.
+        * 
+        * @return This object (for method chaining).
+        */
+       public MockServletRequest json() {
+               return header("Accept", 
"application/json").header("Content-Type", "application/json");
+       }
+
+       /**
+        * Convenience method for setting <code>Accept</code> and 
<code>Content-Type</code> headers to <js>"text/xml"</js>.
+        * 
+        * @return This object (for method chaining).
+        */
+       public MockServletRequest xml() {
+               return header("Accept", "text/xml").header("Content-Type", 
"text/xml");
+       }
+       
+       /**
+        * Convenience method for setting <code>Accept</code> and 
<code>Content-Type</code> headers to <js>"text/html"</js>.
+        * 
+        * @return This object (for method chaining).
+        */
+       public MockServletRequest html() {
+               return header("Accept", "text/html").header("Content-Type", 
"text/html");
+       }
+       
+       /**
+        * Convenience method for setting <code>Accept</code> and 
<code>Content-Type</code> headers to <js>"text/plain"</js>.
+        * 
+        * @return This object (for method chaining).
+        */
+       public MockServletRequest plainText() {
+               return header("Accept", "text/plain").header("Content-Type", 
"text/plain");
+       }
+       
+       /**
+        * Convenience method for setting <code>Accept</code> and 
<code>Content-Type</code> headers to <js>"octal/msgpack"</js>.
+        * 
+        * @return This object (for method chaining).
+        */
+       public MockServletRequest msgpack() {
+               return header("Accept", "octal/msgpack").header("Content-Type", 
"octal/msgpack");
+       }
+       
+       /**
+        * Convenience method for setting <code>Accept</code> and 
<code>Content-Type</code> headers to <js>"text/uon"</js>.
+        * 
+        * @return This object (for method chaining).
+        */
+       public MockServletRequest uon() {
+               return header("Accept", "text/uon").header("Content-Type", 
"text/uon");
+       }
+       
+       /**
+        * Convenience method for setting <code>Accept</code> and 
<code>Content-Type</code> headers to 
<js>"application/x-www-form-urlencoded"</js>.
+        * 
+        * @return This object (for method chaining).
+        */
+       public MockServletRequest urlEnc() {
+               return header("Accept", 
"application/x-www-form-urlencoded").header("Content-Type", 
"application/x-www-form-urlencoded");
+       }
+       
+       /**
+        * Convenience method for setting <code>Accept</code> and 
<code>Content-Type</code> headers to <js>"text/yaml"</js>.
+        * 
+        * @return This object (for method chaining).
+        */
+       public MockServletRequest yaml() {
+               return header("Accept", "text/yaml").header("Content-Type", 
"text/yaml");
+       }
+
+       /**
         * Fluent setter.
         * 
         * @param uri The URI of the request.
@@ -140,6 +211,11 @@ public class MockServletRequest implements 
HttpServletRequest {
        public MockServletResponse execute() throws Exception {
                MockServletResponse res = MockServletResponse.create();
                restContext.getCallHandler().service(this, res);
+               
+               // If the status isn't set, something's broken.
+               if (res.getStatus() == 0)
+                       throw new RuntimeException("Response status was 0.");
+               
                return res;
        }
 
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
index 0e5efb2..f9845c6 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/mock/MockServletResponse.java
@@ -12,7 +12,10 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.rest.mock;
 
+import static org.apache.juneau.internal.StringUtils.*;
+
 import java.io.*;
+import java.text.*;
 import java.util.*;
 
 import javax.servlet.*;
@@ -266,4 +269,45 @@ public class MockServletResponse implements 
HttpServletResponse {
                        throw new RuntimeException(e);
                }
        }
+       
+       /**
+        * Throws an {@link AssertionError} if the response status does not 
match the expected status.
+        * 
+        * @param status The expected status.
+        * @return This object (for method chaining).
+        * @throws AssertionError Thrown if status does not match.
+        */
+       public MockServletResponse assertStatus(int status) throws 
AssertionError {
+               if (getStatus() != status)
+                       throw new AssertionError(MessageFormat.format("Response 
did not have the expected status. expected=[{0}], actual=[{1}]", status, 
getStatus()));
+               return this;
+       }
+       
+       /**
+        * Throws an {@link AssertionError} if the response body does not 
contain all of the expected substrings.
+        * 
+        * @param substrings The expected substrings.
+        * @return This object (for method chaining).
+        * @throws AssertionError Thrown if the body does not contain one or 
more of the expected substrings.
+        */
+       public MockServletResponse assertBodyContains(String...substrings) 
throws AssertionError {
+               String text = getBodyAsString(); 
+               for (String substring : substrings) 
+                       if (! contains(text, substring))
+                               throw new 
AssertionError(MessageFormat.format("Response did not have the expected 
substring. expected=[{0}], body=[{1}]", substring, text));
+               return this;
+       }
+
+       /**
+        * Throws an {@link AssertionError} if the response body does not 
contain the expected text.
+        * 
+        * @param text The expected text of the body.
+        * @return This object (for method chaining).
+        * @throws AssertionError Thrown if the body does not contain the 
expected text.
+        */
+       public MockServletResponse assertBody(String text) throws 
AssertionError {
+               if (! StringUtils.isEquals(text, getBodyAsString()))
+                       throw new AssertionError(MessageFormat.format("Response 
did not have the expected text. expected=[{0}], actual=[{1}]", text, 
getBodyAsString()));
+               return this;
+       }
 }
diff --git 
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyAnnotationTest.java
 
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyAnnotationTest.java
new file mode 100644
index 0000000..8836379
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyAnnotationTest.java
@@ -0,0 +1,680 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              * 
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.rest.annotation;
+
+import static org.apache.juneau.http.HttpMethodName.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.internal.*;
+import org.apache.juneau.json.*;
+import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.rest.testutils.*;
+import org.apache.juneau.uon.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+/**
+ * Tests the {@link Body} annotation.
+ */
+@SuppressWarnings({"javadoc","serial"})
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class BodyAnnotationTest {
+       
+       
//=================================================================================================================
+       // @Body on parameter
+       
//=================================================================================================================
+       
+       @RestResource(serializers=JsonSerializer.Simple.class, 
parsers=JsonParser.class)
+       public static class A {
+               
+               @RestMethod(name=PUT, path="/String")
+               public String a01(@Body String b) {
+                       return b;
+               }
+
+               @RestMethod(name=PUT, path="/Integer")
+               public Integer a02(@Body Integer b) {
+                       return b;
+               }
+
+               @RestMethod(name=PUT, path="/int")
+               public Integer a03(@Body int b) {
+                       return b;
+               }
+
+               @RestMethod(name=PUT, path="/Boolean")
+               public Boolean a04(@Body Boolean b) {
+                       return b;
+               }
+
+               @RestMethod(name=PUT, path="/boolean")
+               public Boolean a05(@Body boolean b) {
+                       return b;
+               }
+
+               @RestMethod(name=PUT, path="/float")
+               public float a06(@Body float f) {
+                       return f;
+               }
+
+               @RestMethod(name=PUT, path="/Float")
+               public Float a07(@Body Float f) {
+                       return f;
+               }
+               
+               @RestMethod(name=PUT, path="/Map")
+               public TreeMap<String,Integer> a08(@Body 
TreeMap<String,Integer> m) {
+                       return m;
+               }
+
+               @RestMethod(name=PUT, path="/enum")
+               public TestEnum a09(@Body TestEnum e) {
+                       return e;
+               }
+
+               public static class A11 {
+                       public String f1;
+               }
+               
+               @RestMethod(name=PUT, path="/Bean")
+               public A11 a11(@Body A11 b) {
+                       return b;
+               }
+
+               @RestMethod(name=PUT, path="/InputStream")
+               public String a12(@Body InputStream b) throws Exception {
+                       return IOUtils.read(b);
+               }
+
+               @RestMethod(name=PUT, path="/Reader")
+               public String a13(@Body Reader b) throws Exception {
+                       return IOUtils.read(b);
+               }
+
+               @RestMethod(name=PUT, path="/InputStreamTransform")
+               public A14 a14(@Body A14 b) throws Exception {
+                       return b;
+               }
+               public static class A14 {
+                       String s;
+                       public A14(InputStream in) throws Exception { this.s = 
IOUtils.read(in); }
+                       @Override public String toString() { return s; }
+               }
+               
+               @RestMethod(name=PUT, path="/ReaderTransform")
+               public A15 a15(@Body A15 b) throws Exception {
+                       return b;
+               }
+               public static class A15 {
+                       private String s;
+                       public A15(Reader in) throws Exception { this.s = 
IOUtils.read(in); }
+                       @Override public String toString() { return s; }
+               }
+               
+               @RestMethod(name=PUT, path="/StringTransform")
+               public A16 a16(@Body A16 b) throws Exception { return b; }
+               public static class A16 {
+                       private String s;
+                       public A16(String s) throws Exception { this.s = s; }
+                       @Override public String toString() { return s; }
+               }
+               
+       }
+       
+       private static MockRest a = MockRest.create(A.class);
+       
+       @Test
+       public void a01a_onParameter_String() throws Exception {
+               a.request("PUT", 
"/String").body("'foo'").json().execute().assertBody("'foo'");
+       }
+       @Test
+       public void a01b_onParameter_String_noContentType() throws Exception {
+               // If no Content-Type specified, should be treated as 
plain-text.
+               a.request("PUT", 
"/String").body("'foo'").execute().assertBody("'\\'foo\\''");
+       }
+       @Test
+       public void a01c_onParameter_String_noContentType_other() throws 
Exception {
+               // If Content-Type not matched, should be treated as plain-text.
+               a.request("PUT", 
"/String").body("'foo'").contentType("").execute().assertBody("'\\'foo\\''");
+               a.request("PUT", 
"/String").body("'foo'").contentType("text/plain").execute().assertBody("'\\'foo\\''");
+       }
+       @Test
+       public void a02a_onParameter_Integer() throws Exception {
+               a.request("PUT", 
"/Integer").body("123").json().execute().assertBody("123");
+       }
+       @Test
+       public void a02b_onParameter_Integer_noContentType() throws Exception {
+               // Integer takes in a String arg, so it can be parsed without 
Content-Type.
+               a.request("PUT", 
"/Integer").body("123").execute().assertBody("123");
+       }
+       @Test
+       public void a03a_onParameter_int() throws Exception {
+               a.request("PUT", 
"/int").body("123").json().execute().assertBody("123");
+       }
+       @Test
+       public void a03b_onParameter_int_noContentType() throws Exception {
+               a.request("PUT", 
"/int?noTrace=true").body("123").execute().assertBodyContains("Unsupported 
Media Type");
+       }
+       @Test
+       public void a04a_onParameter_Boolean() throws Exception {
+               a.request("PUT", 
"/Boolean").body("true").json().execute().assertBody("true");
+       }
+       @Test
+       public void a04b_onParameter_Boolean_noContentType() throws Exception {
+               // Boolean takes in a String arg, so it can be parsed without 
Content-Type.
+               a.request("PUT", 
"/Boolean").body("true").execute().assertBody("true");
+       }
+       @Test
+       public void a05a_onParameter_boolean() throws Exception {
+               a.request("PUT", 
"/boolean").body("true").json().execute().assertBody("true");
+       }
+       @Test
+       public void a05b_onParameter_boolean_noContentType() throws Exception {
+               a.request("PUT", 
"/boolean?noTrace=true").body("true").execute().assertBodyContains("Unsupported 
Media Type");
+       }
+       @Test
+       public void a06a_onParameter_float() throws Exception {
+               a.request("PUT", 
"/float").body("1.23").json().execute().assertBody("1.23");
+       }
+       @Test
+       public void a06b_onParameter_float_noContentType() throws Exception {
+               a.request("PUT", 
"/float?noTrace=true").body("1.23").execute().assertBodyContains("Unsupported 
Media Type");
+       }
+       @Test
+       public void a07a_onParameter_Float() throws Exception {
+               a.request("PUT", 
"/Float").body("1.23").json().execute().assertBody("1.23");
+       }
+       @Test
+       public void a07b_onParameter_Float_noContentType() throws Exception {
+               // Float takes in a String arg, so it can be parsed without 
Content-Type.
+               a.request("PUT", 
"/Float").body("1.23").execute().assertBody("1.23");
+       }
+       @Test
+       public void a08a_onParameter_Map() throws Exception {
+               a.request("PUT", 
"/Map").body("{foo:123}").json().execute().assertBody("{foo:123}");
+       }
+       @Test
+       public void a08b_onParameter_Map_noContentType() throws Exception {
+               a.request("PUT", 
"/Map?noTrace=true").body("{foo:123}").execute().assertBodyContains("Unsupported
 Media Type");
+       }
+       @Test
+       public void a09a_onParameter_enum() throws Exception {
+               a.request("PUT", 
"/enum").body("'ONE'").json().execute().assertBody("'ONE'");
+       }
+       @Test
+       public void a09b_onParameter_enum_noContentType() throws Exception {
+               a.request("PUT", 
"/enum").body("ONE").execute().assertBody("'ONE'");
+       }
+       @Test
+       public void a11a_onParameter_Bean() throws Exception {
+               a.request("PUT", 
"/Bean").body("{f1:'a'}").json().execute().assertBody("{f1:'a'}");
+       }
+       @Test
+       public void a11b_onParameter_Bean_noContentType() throws Exception {
+               a.request("PUT", 
"/Bean?noTrace=true").body("{f1:'a'}").execute().assertBodyContains("Unsupported
 Media Type");
+       }
+       @Test
+       public void a12a_onParameter_InputStream() throws Exception {
+               // Content-Type should always be ignored.
+               a.request("PUT", 
"/InputStream").body("'a'").json().execute().assertBody("'\\'a\\''");
+       }
+       @Test
+       public void a12b_onParameter_InputStream_noContentType() throws 
Exception {
+               a.request("PUT", 
"/InputStream").body("'a'").execute().assertBody("'\\'a\\''");
+       }
+       @Test
+       public void a13a_onParameter_Reader() throws Exception {
+               // Content-Type should always be ignored.
+               a.request("PUT", 
"/Reader").body("'a'").json().execute().assertBody("'\\'a\\''");
+       }
+       @Test
+       public void a13b_onParameter_Reader_noContentType() throws Exception {
+               a.request("PUT", 
"/Reader").body("'a'").execute().assertBody("'\\'a\\''");
+       }
+       @Test
+       public void a14a_onParameter_InputStreamTransform() throws Exception {
+               // Input stream transform requests must not specify 
Content-Type or else gets resolved as POJO.
+               a.request("PUT", 
"/InputStreamTransform?noTrace=true").body("'a'").json().execute().assertBodyContains("Bad
 Request");
+       }
+       @Test
+       public void a14b_onParameter_InputStreamTransform_noContentType() 
throws Exception {
+               a.request("PUT", 
"/InputStreamTransform").body("'a'").execute().assertBody("'\\'a\\''");
+       }
+       @Test
+       public void a15a_onParameter_ReaderTransform() throws Exception {
+               // Reader transform requests must not specify Content-Type or 
else gets resolved as POJO.
+               a.request("PUT", 
"/ReaderTransform?noTrace=true").body("'a'").json().execute().assertBodyContains("Bad
 Request");
+       }
+       @Test
+       public void a15b_onParameter_ReaderTransform_noContentType() throws 
Exception {
+               a.request("PUT", 
"/ReaderTransform").body("'a'").execute().assertBody("'\\'a\\''");
+       }
+       @Test
+       public void a16a_onParameter_StringTransform() throws Exception {
+               // When Content-Type specified and matched, treated as a parsed 
POJO.
+               a.request("PUT", 
"/StringTransform").body("'a'").json().execute().assertBody("'a'");
+       }
+       @Test
+       public void a16b_onParameter_StringTransform_noContentType() throws 
Exception {
+               // When Content-Type not matched, treated as plain text.
+               a.request("PUT", 
"/StringTransform").body("'a'").execute().assertBody("'\\'a\\''");
+       }
+       
+       
+       
//=================================================================================================================
+       // @Body on POJO
+       
//=================================================================================================================
+       
+       @RestResource(serializers=JsonSerializer.Simple.class, 
parsers=JsonParser.class)
+       public static class B {
+               
+               @RestMethod(name=PUT, path="/StringTransform")
+               public B01 b01(B01 b) {
+                       return b;
+               }
+               @Body 
+               public static class B01 {
+                       private String val;
+                       public B01(String val) { this.val = val; }
+                       @Override public String toString() { return val; }
+               }
+               
+               @RestMethod(name=PUT, path="/Bean")
+               public B02 b02(B02 b) {
+                       return b;
+               }
+               @Body
+               public static class B02 {
+                       public String f1;
+               }
+               
+               @RestMethod(name=PUT, path="/BeanList")
+               public B03 b03(B03 b) {
+                       return b;
+               }
+               @Body
+               public static class B03 extends LinkedList<B02> {}
+               
+               @RestMethod(name=PUT, path="/InputStreamTransform")
+               public B04 b04(B04 b) throws Exception {
+                       return b;
+               }
+               @Body 
+               public static class B04 {
+                       String s;
+                       public B04(InputStream in) throws Exception { this.s = 
IOUtils.read(in); }
+                       @Override public String toString() { return s; }
+               }
+               
+               @RestMethod(name=PUT, path="/ReaderTransform")
+               public B05 b05(B05 b) throws Exception {
+                       return b;
+               }
+               @Body 
+               public static class B05 {
+                       private String s;
+                       public B05(Reader in) throws Exception { this.s = 
IOUtils.read(in); }
+                       @Override public String toString() { return s; }
+               }
+               
+       }
+       
+       private static MockRest b = MockRest.create(B.class);
+
+       @Test
+       public void b01a_onPojo_StringTransform() throws Exception {
+               b.request("PUT", 
"/StringTransform").body("'foo'").json().execute().assertBody("'foo'");
+       }
+       @Test
+       public void b01b_onPojo_StringTransform_noContentType() throws 
Exception {
+               // When Content-Type not matched, treated as plain text.
+               b.request("PUT", 
"/StringTransform").body("'foo'").execute().assertBody("'\\'foo\\''");
+       }
+       @Test
+       public void b02a_onPojo_Bean() throws Exception {
+               b.request("PUT", 
"/Bean").body("{f1:'a'}").json().execute().assertBody("{f1:'a'}");
+       }
+       @Test
+       public void b02b_onPojo_Bean_noContentType() throws Exception {
+               b.request("PUT", 
"/Bean?noTrace=true").body("{f1:'a'}").execute().assertBodyContains("Unsupported
 Media Type");
+       }
+       @Test
+       public void b03a_onPojo_BeanList() throws Exception {
+               b.request("PUT", 
"/BeanList").body("[{f1:'a'}]").json().execute().assertBody("[{f1:'a'}]");
+       }
+       @Test
+       public void b03b_onPojo_BeanList_noContentType() throws Exception {
+               b.request("PUT", 
"/BeanList?noTrace=true").body("[{f1:'a'}]").execute().assertBodyContains("Unsupported
 Media Type");
+       }
+       @Test
+       public void b04a_onPojo_InputStreamTransform() throws Exception {
+               b.request("PUT", 
"/InputStreamTransform").body("a").execute().assertBody("'a'");
+       }
+       @Test
+       public void b04b_onPojo_InputStreamTransform_withContentType() throws 
Exception {
+               // When Content-Type matched, treated as parsed POJO.
+               b.request("PUT", 
"/InputStreamTransform?noTrace=true").body("a").json().execute().assertBodyContains("Bad
 Request");
+       }
+       @Test
+       public void b05a_onPojo_ReaderTransform() throws Exception {
+               b.request("PUT", 
"/ReaderTransform").body("a").execute().assertBody("'a'");
+       }
+       @Test
+       public void b05b_onPojo_ReaderTransform_withContentType() throws 
Exception {
+               // When Content-Type matched, treated as parsed POJO.
+               b.request("PUT", 
"/ReaderTransform?noTrace=true").body("a").json().execute().assertBodyContains("Bad
 Request");
+       }
+
+       
+       
//=================================================================================================================
+       // Basic tests using @Body parameter
+       
//=================================================================================================================
+
+       public void c01_bodyParam_String() throws Exception {
+               a.request("PUT", 
"/String?body=foo").execute().assertBody("'foo'");
+               a.request("PUT", 
"/String?body=null").execute().assertBody("null");
+               a.request("PUT", "/String?body=").execute().assertBody("''");
+       }
+       @Test
+       public void c02_bodyParam_Integer() throws Exception {
+               a.request("PUT", 
"/Integer?body=123").execute().assertBody("123");
+               a.request("PUT", 
"/Integer?body=-123").execute().assertBody("-123");
+               a.request("PUT", 
"/Integer?body=null").execute().assertBody("null");
+               a.request("PUT", "/Integer?body=").execute().assertBody("null");
+               a.request("PUT", 
"/Integer?body=bad&noTrace=true").execute().assertStatus(400);
+       }
+       @Test
+       public void c03_bodyParam_int() throws Exception {
+               a.request("PUT", "/int?body=123").execute().assertBody("123");
+               a.request("PUT", "/int?body=-123").execute().assertBody("-123");
+               a.request("PUT", "/int?body=null").execute().assertBody("0");
+               a.request("PUT", "/int?body=").execute().assertBody("0");
+               a.request("PUT", 
"/int?body=bad&noTrace=true").execute().assertStatus(400);
+       }
+       @Test
+       public void c04_bodyParam_Boolean() throws Exception {
+               a.request("PUT", 
"/Boolean?body=true").execute().assertBody("true");
+               a.request("PUT", 
"/Boolean?body=false").execute().assertBody("false");
+               a.request("PUT", 
"/Boolean?body=null").execute().assertBody("null");
+               a.request("PUT", "/Boolean?body=").execute().assertBody("null");
+               a.request("PUT", 
"/Boolean?body=bad&noTrace=true").execute().assertStatus(400);
+       }
+       @Test
+       public void c05_bodyParam_boolean() throws Exception {
+               a.request("PUT", 
"/boolean?body=true").execute().assertBody("true");
+               a.request("PUT", 
"/boolean?body=false").execute().assertBody("false");
+               a.request("PUT", 
"/boolean?body=null").execute().assertBody("false");
+               a.request("PUT", 
"/boolean?body=").execute().assertBody("false");
+               a.request("PUT", 
"/boolean?body=bad&noTrace=true").execute().assertStatus(400);
+       }
+       @Test
+       public void c06_bodyParam_Float() throws Exception {
+               a.request("PUT", 
"/Float?body=1.23").execute().assertBody("1.23");
+               a.request("PUT", 
"/Float?body=-1.23").execute().assertBody("-1.23");
+               a.request("PUT", 
"/Float?body=null").execute().assertBody("null");
+               a.request("PUT", "/Float?body=").execute().assertBody("null");
+               a.request("PUT", 
"/Float?body=bad&noTrace=true").execute().assertStatus(400);
+       }
+       @Test
+       public void c07_bodyParam_float() throws Exception {
+               a.request("PUT", 
"/float?body=1.23").execute().assertBody("1.23");
+               a.request("PUT", 
"/float?body=-1.23").execute().assertBody("-1.23");
+               a.request("PUT", 
"/float?body=null").execute().assertBody("0.0");
+               a.request("PUT", "/float?body=").execute().assertBody("0.0");
+               a.request("PUT", 
"/float?body=bad&noTrace=true").execute().assertStatus(400);
+       }
+       @Test
+       public void c08_bodyParam_Map() throws Exception {
+               a.request("PUT", 
"/Map?body=(foo=123)").execute().assertBody("{foo:123}");
+               a.request("PUT", "/Map?body=()").execute().assertBody("{}");
+               a.request("PUT", "/Map?body=null").execute().assertBody("null");
+               a.request("PUT", "/Map?body=").execute().assertBody("null");
+               a.request("PUT", 
"/Map?body=bad&noTrace=true").execute().assertStatus(400);
+       }
+       @Test
+       public void c09_bodyParam_enum() throws Exception {
+               a.request("PUT", 
"/enum?body=ONE").execute().assertBody("'ONE'");
+               a.request("PUT", 
"/enum?body=TWO").execute().assertBody("'TWO'");
+               a.request("PUT", 
"/enum?body=null").execute().assertBody("null");
+               a.request("PUT", "/enum?body=").execute().assertBody("null");
+               a.request("PUT", 
"/enum?body=bad&noTrace=true").execute().assertStatus(400);
+       }
+       @Test
+       public void c11_bodyParam_Bean() throws Exception {
+               a.request("PUT", 
"/Bean?body=(f1=a)").execute().assertBody("{f1:'a'}");
+               a.request("PUT", "/Bean?body=()").execute().assertBody("{}");
+               a.request("PUT", 
"/Bean?body=null").execute().assertBody("null");
+               a.request("PUT", "/Bean?body=").execute().assertBody("null");
+               a.request("PUT", 
"/Bean?body=bad&noTrace=true").execute().assertStatus(400);
+       }
+       @Test
+       public void c12_bodyParam_InputStream() throws Exception {
+               a.request("PUT", 
"/InputStream?body=a").execute().assertBody("'a'");
+               a.request("PUT", 
"/InputStream?body=null").execute().assertBody("'null'");
+               a.request("PUT", 
"/InputStream?body=").execute().assertBody("''");
+       }
+       @Test
+       public void c13_bodyParam_Reader() throws Exception {
+               a.request("PUT", "/Reader?body=a").execute().assertBody("'a'");
+               a.request("PUT", 
"/Reader?body=null").execute().assertBody("'null'");
+               a.request("PUT", "/Reader?body=").execute().assertBody("''");
+       }
+       
+       // It's not currently possible to pass in a &body parameter for 
InputStream/Reader transforms.
+
+       
+       
//=================================================================================================================
+       // No serializers or parsers needed when using only streams and readers.
+       
//=================================================================================================================
+       
+       @RestResource
+       public static class D {
+               
+               @RestMethod(name=PUT, path="/String")
+               public Reader d01(@Body Reader b) throws Exception {
+                       return b;
+               }
+
+               @RestMethod(name=PUT, path="/InputStream")
+               public InputStream d02(@Body InputStream b) throws Exception {
+                       return b;
+               }
+
+               @RestMethod(name=PUT, path="/Reader")
+               public Reader d03(@Body Reader b) throws Exception {
+                       return b;
+               }
+               
+               @RestMethod(name=PUT, path="/StringTransform")
+               public Reader d04(@Body D04 b) throws Exception {
+                       return new StringReader(b.toString());
+               }
+               public static class D04 {
+                       private String s;
+                       public D04(String in) throws Exception { this.s = in; }
+                       @Override public String toString() { return s; }
+               }
+               
+               @RestMethod(name=PUT, path="/InputStreamTransform")
+               public Reader d05(@Body D05 b) throws Exception {
+                       return new StringReader(b.toString());
+               }
+               public static class D05 {
+                       String s;
+                       public D05(InputStream in) throws Exception { this.s = 
IOUtils.read(in); }
+                       @Override public String toString() { return s; }
+               }
+               
+               @RestMethod(name=PUT, path="/ReaderTransform")
+               public Reader d06(@Body D06 b) throws Exception {
+                       return new StringReader(b.toString());
+               }
+               public static class D06 {
+                       private String s;
+                       public D06(Reader in) throws Exception{ this.s = 
IOUtils.read(in); }
+                       @Override public String toString() { return s; }
+               }
+               
+               @RestMethod(name=PUT, path="/StringTransformBodyOnPojo")
+               public Reader d07(D07 b) throws Exception {
+                       return new StringReader(b.toString());
+               }
+               @Body
+               public static class D07 {
+                       private String s;
+                       public D07(String in) throws Exception { this.s = in; }
+                       @Override public String toString() { return s; }
+               }
+               
+               @RestMethod(name=PUT, path="/InputStreamTransformBodyOnPojo")
+               public Reader d08(D08 b) throws Exception {
+                       return new StringReader(b.toString());
+               }
+               @Body
+               public static class D08 {
+                       String s;
+                       public D08(InputStream in) throws Exception { this.s = 
IOUtils.read(in); }
+                       @Override public String toString() { return s; }
+               }
+               
+               @RestMethod(name=PUT, path="/ReaderTransformBodyOnPojo")
+               public Reader d09(D09 b) throws Exception {
+                       return new StringReader(b.toString());
+               }
+               @Body
+               public static class D09 {
+                       private String s;
+                       public D09(Reader in) throws Exception{ this.s = 
IOUtils.read(in); }
+                       @Override public String toString() { return s; }
+               }
+       }
+       
+       private static MockRest d = MockRest.create(D.class);
+       
+       @Test
+       public void d01a_noMediaTypes_String() throws Exception {
+               d.request("PUT", "/String").body("a").execute().assertBody("a");
+       }
+       @Test
+       public void d01b_noMediaTypes_String_withContentType() throws Exception 
{
+               d.request("PUT", 
"/String").body("a").json().execute().assertBody("a");
+       }
+       @Test
+       public void d02a_noMediaTypes_InputStream() throws Exception {
+               d.request("PUT", 
"/InputStream").body("a").execute().assertBody("a");
+       }
+       @Test
+       public void d02b_noMediaTypes_InputStream_withContentType() throws 
Exception {
+               d.request("PUT", 
"/InputStream").body("a").json().execute().assertBody("a");
+       }
+       @Test
+       public void d03a_noMediaTypes_Reader() throws Exception {
+               d.request("PUT", "/Reader").body("a").execute().assertBody("a");
+       }
+       @Test
+       public void d03b_noMediaTypes_Reader_withContentType() throws Exception 
{
+               d.request("PUT", 
"/Reader").body("a").json().execute().assertBody("a");
+       }
+       @Test
+       public void d04a_noMediaTypes_StringTransform() throws Exception {
+               d.request("PUT", 
"/StringTransform").body("a").execute().assertBody("a");
+       }
+       @Test
+       public void d04b_noMediaTypes_StringTransform_withContentType() throws 
Exception {
+               d.request("PUT", 
"/StringTransform?noTrace=true").body("a").json().execute().assertStatus(415);
+       }
+       @Test
+       public void d05a_noMediaTypes_InputStreamTransform() throws Exception {
+               d.request("PUT", 
"/InputStreamTransform").body("a").execute().assertBody("a");
+       }
+       @Test
+       public void d05b_noMediaTypes_InputStreamTransform_withContentType() 
throws Exception {
+               d.request("PUT", 
"/InputStreamTransform").body("a").json().execute().assertBody("a");
+       }
+       @Test
+       public void d06a_noMediaTypes_ReaderTransform() throws Exception {
+               d.request("PUT", 
"/ReaderTransform").body("a").execute().assertBody("a");
+       }
+       @Test
+       public void d06b_noMediaTypes_ReaderTransform_withContentType() throws 
Exception {
+               d.request("PUT", 
"/ReaderTransform").body("a").json().execute().assertBody("a");
+       }
+       @Test
+       public void d07a_noMediaTypes_StringTransformBodyOnPojo() throws 
Exception {
+               d.request("PUT", 
"/StringTransformBodyOnPojo").body("a").execute().assertBody("a");
+       }
+       @Test
+       public void 
d07b_noMediaTypes_StringTransformBodyOnPojo_withContentType() throws Exception {
+               d.request("PUT", 
"/StringTransformBodyOnPojo?noTrace=true").body("a").json().execute().assertStatus(415);
+       }
+       @Test
+       public void d08a_noMediaTypes_InputStreamTransformBodyOnPojo() throws 
Exception {
+               d.request("PUT", 
"/InputStreamTransformBodyOnPojo").body("a").execute().assertBody("a");
+       }
+       @Test
+       public void 
d08b_noMediaTypes_InputStreamTransformBodyOnPojo_withContentType() throws 
Exception {
+               d.request("PUT", 
"/InputStreamTransformBodyOnPojo").body("a").json().execute().assertBody("a");
+       }
+       @Test
+       public void d09a_noMediaTypes_ReaderTransformBodyOnPojo() throws 
Exception {
+               d.request("PUT", 
"/ReaderTransformBodyOnPojo").body("a").execute().assertBody("a");
+       }
+       @Test
+       public void 
d09b_noMediaTypes_ReaderTransformBodyOnPojo_withContentType() throws Exception {
+               d.request("PUT", 
"/ReaderTransformBodyOnPojo").body("a").json().execute().assertBody("a");
+       }
+       
+       
+       
//=================================================================================================================
+       // Complex POJOs
+       
//=================================================================================================================
+       
+       @RestResource(serializers=JsonSerializer.Simple.class, 
parsers=JsonParser.class)
+       public static class E {
+       
+               @RestMethod(name=PUT, path="/B")
+               public DTOs.B testPojo1(@Body DTOs.B b) {
+                       return b;
+               }
+       
+               @RestMethod(name=PUT, path="/C")
+               public DTOs.C testPojo2(@Body DTOs.C c) {
+                       return c;
+               }
+       }
+       
+       private static MockRest e = MockRest.create(E.class);
+       
+       @Test
+       public void e01_complexPojos_B_body() throws Exception {
+               String expected = 
"{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}
 [...]
+               e.request("PUT", 
"/B").body(JsonSerializer.DEFAULT_LAX.toString(DTOs.B.INSTANCE)).json().execute().assertBody(expected);
+       }
+       @Test
+       public void e02_complexPojos_B_bodyParam() throws Exception {
+               String expected = 
"{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}
 [...]
+               e.request("PUT", "/B?body=" + 
UonSerializer.DEFAULT.serialize(DTOs.B.INSTANCE)).body("a").execute().assertBody(expected);
+       }
+       @Test
+       public void e03_complexPojos_C_body() throws Exception {
+               String expected = 
"{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}
 [...]
+               e.request("PUT", 
"/C").body(JsonSerializer.DEFAULT_LAX.toString(DTOs.B.INSTANCE)).json().execute().assertBody(expected);
+       }
+       @Test
+       public void e04_complexPojos_C_bodyParam() throws Exception {
+               String expected = 
"{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}
 [...]
+               e.request("PUT", "/C?body=" + 
UonSerializer.DEFAULT.serialize(DTOs.B.INSTANCE)).body("a").execute().assertBody(expected);
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyTest.java
 
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyTest.java
deleted file mode 100644
index 07707bb..0000000
--- 
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/BodyTest.java
+++ /dev/null
@@ -1,533 +0,0 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              * 
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.rest.annotation;
-
-import static org.apache.juneau.http.HttpMethodName.*;
-import static org.junit.Assert.*;
-
-import java.io.*;
-import java.util.*;
-
-
-import org.apache.juneau.internal.*;
-import org.apache.juneau.json.*;
-import org.apache.juneau.rest.mock.*;
-import org.apache.juneau.rest.testutils.*;
-import org.apache.juneau.uon.*;
-import org.junit.*;
-import org.junit.runners.*;
-
-/**
- * Tests the {@link Body} annotation.
- */
-@SuppressWarnings({"javadoc","serial"})
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class BodyTest {
-       
-       
//-----------------------------------------------------------------------------------------------------------------
-       // @Body on parameter
-       
//-----------------------------------------------------------------------------------------------------------------
-       
-       @RestResource(serializers=JsonSerializer.Simple.class, 
parsers=JsonParser.class)
-       public static class A {
-               
-               @RestMethod(name=PUT, path="/String")
-               public String a01(@Body String b) {
-                       return b;
-               }
-
-               @RestMethod(name=PUT, path="/Integer")
-               public Integer a02(@Body Integer b) {
-                       return b;
-               }
-
-               @RestMethod(name=PUT, path="/int")
-               public Integer a03(@Body int b) {
-                       return b;
-               }
-
-               @RestMethod(name=PUT, path="/Boolean")
-               public Boolean a04(@Body Boolean b) {
-                       return b;
-               }
-
-               @RestMethod(name=PUT, path="/boolean")
-               public Boolean a05(@Body boolean b) {
-                       return b;
-               }
-
-               @RestMethod(name=PUT, path="/float")
-               public float a06(@Body float f) {
-                       return f;
-               }
-
-               @RestMethod(name=PUT, path="/Float")
-               public Float a07(@Body Float f) {
-                       return f;
-               }
-               
-               @RestMethod(name=PUT, path="/Map")
-               public TreeMap<String,Integer> a08(@Body 
TreeMap<String,Integer> m) {
-                       return m;
-               }
-
-               @RestMethod(name=PUT, path="/enum")
-               public TestEnum a09(@Body TestEnum e) {
-                       return e;
-               }
-
-               public static class A11 {
-                       public String f1;
-               }
-               
-               @RestMethod(name=PUT, path="/bean")
-               public A11 a11(@Body A11 b) {
-                       return b;
-               }
-
-               @RestMethod(name=PUT, path="/inputStream")
-               public String a12(@Body InputStream b) throws Exception {
-                       return IOUtils.read(b);
-               }
-
-               @RestMethod(name=PUT, path="/reader")
-               public String a13(@Body Reader b) throws Exception {
-                       return IOUtils.read(b);
-               }
-
-               public static class A14 {
-                       String s;
-                       
-                       public A14(InputStream in) throws Exception {
-                               this.s = IOUtils.read(in);
-                       }
-                       
-                       @Override /* Object */
-                       public String toString() {
-                               return s;
-                       }
-               }
-               
-               @RestMethod(name=PUT, path="/inputStreamTransform")
-               public A14 a14(@Body A14 b) throws Exception {
-                       return b;
-               }
-
-               public static class A15 {
-                       private String s;
-                       
-                       public A15(Reader in) throws Exception {
-                               this.s = IOUtils.read(in);
-                       }
-                       
-                       @Override /* Object */
-                       public String toString() {
-                               return s;
-                       }
-               }
-               
-               @RestMethod(name=PUT, path="/readerTransform")
-               public A15 a15(@Body A15 b) throws Exception {
-                       return b;
-               }
-       }
-       
-       private MockRest a = MockRest.create(A.class);
-       
-       @Test
-       public void a01_onParameter_String() throws Exception {
-               assertEquals("'foo'", a.request("PUT", 
"/String").body("'foo'").execute().getBodyAsString());
-       }
-       @Test
-       public void a02_onParameter_Integer() throws Exception {
-               assertEquals("123", a.request("PUT", 
"/Integer").body("123").execute().getBodyAsString());
-       }
-       @Test
-       public void a03_onParameter_int() throws Exception {
-               assertEquals("123", a.request("PUT", 
"/int").body("123").execute().getBodyAsString());
-       }
-       @Test
-       public void a04_onParameter_Boolean() throws Exception {
-               assertEquals("true", a.request("PUT", 
"/Boolean").body("true").execute().getBodyAsString());
-       }
-       @Test
-       public void a05_onParameter_boolean() throws Exception {
-               assertEquals("true", a.request("PUT", 
"/boolean").body("true").execute().getBodyAsString());
-       }
-       @Test
-       public void a06_onParameter_float() throws Exception {
-               assertEquals("1.23", a.request("PUT", 
"/float").body("1.23").execute().getBodyAsString());
-       }
-       @Test
-       public void a07_onParameter_Float() throws Exception {
-               assertEquals("1.23", a.request("PUT", 
"/Float").body("1.23").execute().getBodyAsString());
-       }
-       @Test
-       public void a08_onParameter_Map() throws Exception {
-               assertEquals("{foo:123}", a.request("PUT", 
"/Map").body("{foo:123}").execute().getBodyAsString());
-       }
-       @Test
-       public void a09_onParameter_enum() throws Exception {
-               assertEquals("'ONE'", a.request("PUT", 
"/enum").body("'ONE'").execute().getBodyAsString());
-       }
-       @Test
-       public void a11_onParameter_bean() throws Exception {
-               assertEquals("{f1:'a'}", a.request("PUT", 
"/bean").body("{f1:'a'}").execute().getBodyAsString());
-       }
-       @Test
-       public void a12_onParameter_inputStream() throws Exception {
-               assertEquals("'a'", a.request("PUT", 
"/inputStream").body("a").execute().getBodyAsString());
-       }
-       @Test
-       public void a13_onParameter_reader() throws Exception {
-               assertEquals("'a'", a.request("PUT", 
"/reader").body("a").execute().getBodyAsString());
-       }
-       @Test
-       public void a14_onParameter_inputStreamTransform() throws Exception {
-               assertEquals("'a'", a.request("PUT", 
"/inputStreamTransform").body("a").execute().getBodyAsString());
-       }
-       @Test
-       public void a15_onParameter_readerTransform() throws Exception {
-               assertEquals("'a'", a.request("PUT", 
"/readerTransform").body("a").execute().getBodyAsString());
-       }
-       
-       
-       
//-----------------------------------------------------------------------------------------------------------------
-       // @Body on POJO
-       
//-----------------------------------------------------------------------------------------------------------------
-       
-       @RestResource(serializers=JsonSerializer.Simple.class, 
parsers=JsonParser.class)
-       public static class B {
-               
-               @Body 
-               public static class B01 {
-                       private String val;
-                       
-                       public B01(String val) {
-                               this.val = val;
-                       }
-                       
-                       @Override
-                       public String toString() {
-                               return val;
-                       }
-               }
-               
-               @RestMethod(name=PUT, path="/string")
-               public B01 simple(B01 b) {
-                       return b;
-               }
-
-               @Body
-               public static class B02 {
-                       public String f1;
-               }
-               
-               @RestMethod(name=PUT, path="/bean")
-               public B02 b02(B02 b) {
-                       return b;
-               }
-
-               @Body
-               public static class B03 extends LinkedList<B02> {}
-               
-               @RestMethod(name=PUT, path="/beanList")
-               public B03 b03(B03 b) {
-                       return b;
-               }
-               
-               @Body 
-               public static class B04 {
-                       String s;
-                       
-                       public B04(InputStream in) throws Exception {
-                               this.s = IOUtils.read(in);
-                       }
-                       
-                       @Override /* Object */
-                       public String toString() {
-                               return s;
-                       }
-               }
-               
-               @RestMethod(name=PUT, path="/inputStreamTransform")
-               public B04 b04(B04 b) throws Exception {
-                       return b;
-               }
-               
-               @Body 
-               public static class B05 {
-                       private String s;
-                       
-                       public B05(Reader in) throws Exception {
-                               this.s = IOUtils.read(in);
-                       }
-                       
-                       @Override /* Object */
-                       public String toString() {
-                               return s;
-                       }
-               }
-               
-               @RestMethod(name=PUT, path="/readerTransform")
-               public B05 b05(B05 b) throws Exception {
-                       return b;
-               }
-       }
-       
-       private MockRest b = MockRest.create(B.class);
-
-       @Test
-       public void b01_onPojo_string() throws Exception {
-               assertEquals("'foo'", b.request("PUT", 
"/string").body("'foo'").execute().getBodyAsString());
-       }
-       @Test
-       public void b02_onPojo_bean() throws Exception {
-               assertEquals("{f1:'a'}", b.request("PUT", 
"/bean").body("{f1:'a'}").execute().getBodyAsString());
-       }
-       @Test
-       public void b03_onPojo_beanList() throws Exception {
-               assertEquals("[{f1:'a'}]", b.request("PUT", 
"/beanList").body("[{f1:'a'}]").execute().getBodyAsString());
-       }
-       @Test
-       public void b04_onPojo_inputStream() throws Exception {
-               assertEquals("'a'", b.request("PUT", 
"/inputStreamTransform").body("a").execute().getBodyAsString());
-       }
-       @Test
-       public void b05_onPojo_reader() throws Exception {
-               assertEquals("'a'", b.request("PUT", 
"/readerTransform").body("a").execute().getBodyAsString());
-       }
-
-       
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Basic tests using @Body parameter
-       
//-----------------------------------------------------------------------------------------------------------------
-
-       public void c01_bodyParam_String() throws Exception {
-               assertEquals("'foo'", a.request("PUT", 
"/String?body=foo").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/String?body=null").execute().getBodyAsString());
-               assertEquals("''", a.request("PUT", 
"/String?body=").execute().getBodyAsString());
-       }
-       @Test
-       public void c02_bodyParam_Integer() throws Exception {
-               assertEquals("123", a.request("PUT", 
"/Integer?body=123").execute().getBodyAsString());
-               assertEquals("-123", a.request("PUT", 
"/Integer?body=-123").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/Integer?body=null").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/Integer?body=").execute().getBodyAsString());
-               assertEquals(400, a.request("PUT", 
"/Integer?body=bad&noTrace=true").execute().getStatus());
-       }
-       @Test
-       public void c03_bodyParam_int() throws Exception {
-               assertEquals("123", a.request("PUT", 
"/int?body=123").execute().getBodyAsString());
-               assertEquals("-123", a.request("PUT", 
"/int?body=-123").execute().getBodyAsString());
-               assertEquals("0", a.request("PUT", 
"/int?body=null").execute().getBodyAsString());
-               assertEquals("0", a.request("PUT", 
"/int?body=").execute().getBodyAsString());
-               assertEquals(400, a.request("PUT", 
"/int?body=bad&noTrace=true").execute().getStatus());
-       }
-       @Test
-       public void c04_bodyParam_Boolean() throws Exception {
-               assertEquals("true", a.request("PUT", 
"/Boolean?body=true").execute().getBodyAsString());
-               assertEquals("false", a.request("PUT", 
"/Boolean?body=false").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/Boolean?body=null").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/Boolean?body=").execute().getBodyAsString());
-               assertEquals(400, a.request("PUT", 
"/Boolean?body=bad&noTrace=true").execute().getStatus());
-       }
-       @Test
-       public void c05_bodyParam_boolean() throws Exception {
-               assertEquals("true", a.request("PUT", 
"/boolean?body=true").execute().getBodyAsString());
-               assertEquals("false", a.request("PUT", 
"/boolean?body=false").execute().getBodyAsString());
-               assertEquals("false", a.request("PUT", 
"/boolean?body=null").execute().getBodyAsString());
-               assertEquals("false", a.request("PUT", 
"/boolean?body=").execute().getBodyAsString());
-               assertEquals(400, a.request("PUT", 
"/boolean?body=bad&noTrace=true").execute().getStatus());
-       }
-       @Test
-       public void c06_bodyParam_Float() throws Exception {
-               assertEquals("1.23", a.request("PUT", 
"/Float?body=1.23").execute().getBodyAsString());
-               assertEquals("-1.23", a.request("PUT", 
"/Float?body=-1.23").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/Float?body=null").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/Float?body=").execute().getBodyAsString());
-               assertEquals(400, a.request("PUT", 
"/Float?body=bad&noTrace=true").execute().getStatus());
-       }
-       @Test
-       public void c07_bodyParam_float() throws Exception {
-               assertEquals("1.23", a.request("PUT", 
"/float?body=1.23").execute().getBodyAsString());
-               assertEquals("-1.23", a.request("PUT", 
"/float?body=-1.23").execute().getBodyAsString());
-               assertEquals("0.0", a.request("PUT", 
"/float?body=null").execute().getBodyAsString());
-               assertEquals("0.0", a.request("PUT", 
"/float?body=").execute().getBodyAsString());
-               assertEquals(400, a.request("PUT", 
"/float?body=bad&noTrace=true").execute().getStatus());
-       }
-       @Test
-       public void c08_bodyParam_Map() throws Exception {
-               assertEquals("{foo:123}", a.request("PUT", 
"/Map?body=(foo=123)").execute().getBodyAsString());
-               assertEquals("{}", a.request("PUT", 
"/Map?body=()").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/Map?body=null").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/Map?body=").execute().getBodyAsString());
-               assertEquals(400, a.request("PUT", 
"/Map?body=bad&noTrace=true").execute().getStatus());
-       }
-       @Test
-       public void c09_bodyParam_enum() throws Exception {
-               assertEquals("'ONE'", a.request("PUT", 
"/enum?body=ONE").execute().getBodyAsString());
-               assertEquals("'TWO'", a.request("PUT", 
"/enum?body=TWO").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/enum?body=null").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/enum?body=").execute().getBodyAsString());
-               assertEquals(400, a.request("PUT", 
"/enum?body=bad&noTrace=true").execute().getStatus());
-       }
-       @Test
-       public void c11_bodyParam_bean() throws Exception {
-               assertEquals("{f1:'a'}", a.request("PUT", 
"/bean?body=(f1=a)").execute().getBodyAsString());
-               assertEquals("{}", a.request("PUT", 
"/bean?body=()").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/bean?body=null").execute().getBodyAsString());
-               assertEquals("null", a.request("PUT", 
"/bean?body=").execute().getBodyAsString());
-               assertEquals(400, a.request("PUT", 
"/bean?body=bad&noTrace=true").execute().getStatus());
-       }
-       @Test
-       public void c12_bodyParam_inputStream() throws Exception {
-               assertEquals("'a'", a.request("PUT", 
"/inputStream?body=a").execute().getBodyAsString());
-               assertEquals("'null'", a.request("PUT", 
"/inputStream?body=null").execute().getBodyAsString());
-               assertEquals("''", a.request("PUT", 
"/inputStream?body=").execute().getBodyAsString());
-       }
-       @Test
-       public void c13_bodyParam_reader() throws Exception {
-               assertEquals("'a'", a.request("PUT", 
"/reader?body=a").execute().getBodyAsString());
-               assertEquals("'null'", a.request("PUT", 
"/reader?body=null").execute().getBodyAsString());
-               assertEquals("''", a.request("PUT", 
"/reader?body=").execute().getBodyAsString());
-       }
-       @Test
-       public void c14_bodyParam_inputStreamTransform() throws Exception {
-               assertEquals("'a'", a.request("PUT", 
"/inputStreamTransform?body=a").execute().getBodyAsString());
-               assertEquals("'null'", a.request("PUT", 
"/inputStreamTransform?body=null").execute().getBodyAsString());
-               assertEquals("''", a.request("PUT", 
"/inputStreamTransform?body=").execute().getBodyAsString());
-       }
-       @Test
-       public void c15_bodyParam_readerTransform() throws Exception {
-               assertEquals("'a'", a.request("PUT", 
"/readerTransform?body=a").execute().getBodyAsString());
-               assertEquals("'null'", a.request("PUT", 
"/readerTransform?body=null").execute().getBodyAsString());
-               assertEquals("''", a.request("PUT", 
"/readerTransform?body=").execute().getBodyAsString());
-       }
-
-       
-       
//-----------------------------------------------------------------------------------------------------------------
-       // No serializers or parsers needed when using only streams and readers.
-       
//-----------------------------------------------------------------------------------------------------------------
-       
-       @RestResource
-       public static class D {
-               
-               @RestMethod(name=PUT, path="/inputStream")
-               public InputStream d01(@Body InputStream b) throws Exception {
-                       return b;
-               }
-
-               @RestMethod(name=PUT, path="/reader")
-               public Reader d02(@Body Reader b) throws Exception {
-                       return b;
-               }
-
-               public static class D03 {
-                       String s;
-                       
-                       public D03(InputStream in) throws Exception {
-                               this.s = IOUtils.read(in);
-                       }
-                       
-                       @Override /* Object */
-                       public String toString() {
-                               return s;
-                       }
-               }
-               
-               @RestMethod(name=PUT, path="/inputStreamTransform")
-               public Reader d03(@Body D03 b) throws Exception {
-                       return new StringReader(b.toString());
-               }
-
-               public static class D04 {
-                       private String s;
-                       
-                       public D04(Reader in) throws Exception {
-                               this.s = IOUtils.read(in);
-                       }
-                       
-                       @Override /* Object */
-                       public String toString() {
-                               return s;
-                       }
-               }
-               
-               @RestMethod(name=PUT, path="/readerTransform")
-               public Reader d04(@Body D04 b) throws Exception {
-                       return new StringReader(b.toString());
-               }
-       }
-       
-       private MockRest d = MockRest.create(D.class);
-       
-       @Test
-       public void d01_noMediaTypes_inputStream() throws Exception {
-               assertEquals("a", d.request("PUT", 
"/inputStream").body("a").execute().getBodyAsString());
-       }
-       @Test
-       public void d02_noMediaTypes_reader() throws Exception {
-               assertEquals("a", d.request("PUT", 
"/reader").body("a").execute().getBodyAsString());
-       }
-       @Test
-       public void d03_noMediaTypes_inputStreamTransform() throws Exception {
-               assertEquals("a", d.request("PUT", 
"/inputStreamTransform").body("a").execute().getBodyAsString());
-       }
-       @Test
-       public void d04_noMediaTypes_readerTransform() throws Exception {
-               assertEquals("a", d.request("PUT", 
"/readerTransform").body("a").execute().getBodyAsString());
-       }
-       
-       
-       
//-----------------------------------------------------------------------------------------------------------------
-       // Complex POJOs
-       
//-----------------------------------------------------------------------------------------------------------------
-       
-       @RestResource(serializers=JsonSerializer.Simple.class, 
parsers=JsonParser.class)
-       public static class E {
-       
-               @RestMethod(name=PUT, path="/B")
-               public DTOs.B testPojo1(@Body DTOs.B b) {
-                       return b;
-               }
-       
-               @RestMethod(name=PUT, path="/C")
-               public DTOs.C testPojo2(@Body DTOs.C c) {
-                       return c;
-               }
-       }
-       
-       private MockRest e = MockRest.create(E.class);
-       
-       @Test
-       public void e01_complexPojos_B_body() throws Exception {
-               String expected = 
"{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}
 [...]
-               assertEquals(expected, e.request("PUT", 
"/B").body(JsonSerializer.DEFAULT_LAX.toString(DTOs.B.INSTANCE)).execute().getBodyAsString());
-       }
-       @Test
-       public void e02_complexPojos_B_bodyParam() throws Exception {
-               String expected = 
"{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}
 [...]
-               assertEquals(expected, e.request("PUT", "/B?body=" + 
UonSerializer.DEFAULT.serialize(DTOs.B.INSTANCE)).body("a").execute().getBodyAsString());
-       }
-       @Test
-       public void e03_complexPojos_C_body() throws Exception {
-               String expected = 
"{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}
 [...]
-               assertEquals(expected, e.request("PUT", 
"/C").body(JsonSerializer.DEFAULT_LAX.toString(DTOs.B.INSTANCE)).execute().getBodyAsString());
-       }
-       @Test
-       public void e04_complexPojos_C_bodyParam() throws Exception {
-               String expected = 
"{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}
 [...]
-               assertEquals(expected, e.request("PUT", "/C?body=" + 
UonSerializer.DEFAULT.serialize(DTOs.B.INSTANCE)).body("a").execute().getBodyAsString());
-       }
-}
diff --git 
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/DefaultContentTypesTest.java
 
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/DefaultContentTypesTest.java
new file mode 100644
index 0000000..3a9907b
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/DefaultContentTypesTest.java
@@ -0,0 +1,384 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              *
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.rest.annotation;
+
+import static org.apache.juneau.http.HttpMethodName.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.parser.*;
+import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.serializer.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+
+/**
+ * Tests related to @RestRequest(defaultRequestHeaders).
+ */
+@SuppressWarnings({"javadoc"})
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class DefaultContentTypesTest {
+       
+       
//=================================================================================================================
+       // Setup classes
+       
//=================================================================================================================
+
+       public static class DummyParser extends ReaderParser {
+
+               String name;
+
+               DummyParser(PropertyStore ps, String name, String...consumes) {
+                       super(ps, consumes);
+                       this.name = name;
+               }
+
+               @Override /* Parser */
+               public ReaderParserSession createSession(ParserSessionArgs 
args) {
+                       return new ReaderParserSession(args) {
+                               @Override /* ParserSession */
+                               @SuppressWarnings("unchecked")
+                               protected <T> T doParse(ParserPipe pipe, 
ClassMeta<T> type) throws Exception {
+                                       return (T)name;
+                               }
+                       };
+               }
+       }
+
+       public static class DummySerializer extends WriterSerializer {
+
+               String name;
+
+               DummySerializer(PropertyStore ps, String name, String produces) 
{
+                       super(ps, produces, null);
+                       this.name = name;
+               }
+
+               @Override /* Serializer */
+               public WriterSerializerSession 
createSession(SerializerSessionArgs args) {
+                       return new WriterSerializerSession(args) {
+                               @Override /* SerializerSession */
+                               protected void doSerialize(SerializerPipe out, 
Object o) throws Exception {
+                                       out.getWriter().write(name + "/" + o);
+                               }
+                       };
+               }
+       }
+       
+       public static class P1 extends DummyParser { public P1(PropertyStore 
ps) {super(ps, "p1", "text/p1");}}
+       public static class P2 extends DummyParser { public P2(PropertyStore 
ps) {super(ps, "p2", "text/p2");}}
+       public static class P3 extends DummyParser { public P3(PropertyStore 
ps) {super(ps, "p3", "text/p3");}}
+       public static class S1 extends DummySerializer { public 
S1(PropertyStore ps) {super(ps, "s1", "text/s1");}}
+       public static class S2 extends DummySerializer { public 
S2(PropertyStore ps) {super(ps, "s2", "text/s2");}}
+       public static class S3 extends DummySerializer { public 
S3(PropertyStore ps) {super(ps, "s3", "text/s3");}}
+       
+
+       
//====================================================================================================
+       // Test that default Accept and Content-Type headers on servlet 
annotation are picked up.
+       
//====================================================================================================
+
+       @RestResource(
+               defaultRequestHeaders={" Accept : text/s2 "," Content-Type : 
text/p2 "},
+               parsers={P1.class,P2.class}, serializers={S1.class,S2.class}
+       )
+       public static class A {
+               @RestMethod(name=PUT)
+               public String a01(@Body String in) {
+                       return in;
+               }
+       }
+       
+       private static MockRest a = MockRest.create(A.class);
+       
+       @Test
+       public void a01_defaultHeadersOnServletAnnotation_valid() throws 
Exception {
+               a.request("PUT", "/").execute().assertBody("s2/p2");
+               a.request("PUT", 
"/").accept("text/s1").execute().assertBody("s1/p2");
+               a.request("PUT", 
"/").contentType("text/p1").execute().assertBody("s2/p1");
+               a.request("PUT", 
"/").accept("text/s1").contentType("text/p1").execute().assertBody("s1/p1");
+               a.request("PUT", 
"/").accept("text/s2").execute().assertBody("s2/p2");
+               a.request("PUT", 
"/").contentType("text/p2").execute().assertBody("s2/p2");
+               a.request("PUT", 
"/").accept("text/s2").contentType("text/p2").execute().assertBody("s2/p2");
+       }
+
+       @Test
+       public void a02_defaultHeadersOnServletAnnotation_invalid() throws 
Exception {
+               a.request("PUT", 
"?noTrace=true").accept("text/s3").execute().assertStatus(406).assertBodyContains("Unsupported
 media-type in request header 'Accept': 'text/s3'");
+               a.request("PUT", 
"?noTrace=true").contentType("text/p3").execute().assertStatus(415).assertBodyContains("Unsupported
 media-type in request header 'Content-Type': 'text/p3'");
+               a.request("PUT", 
"?noTrace=true").accept("text/s3").contentType("text/p3").execute().assertStatus(415).assertBodyContains("Unsupported
 media-type in request header 'Content-Type': 'text/p3'");
+       }
+
+       
//====================================================================================================
+       // Test that default Accept and Content-Type headers on servlet 
annotation are picked up
+       // when @RestMethod.parsers/serializers annotations are used.
+       
//====================================================================================================
+       
+       @RestResource(
+               defaultRequestHeaders={" Accept : text/s2 "," Content-Type : 
text/p2 "},
+               parsers={P1.class,P2.class}, serializers={S1.class,S2.class}
+       )
+       public static class B {
+               @RestMethod(name=PUT, parsers=P3.class, serializers=S3.class)
+               public String b(@Body String in) {
+                       return in;
+               }
+       }
+       
+       private static MockRest b = MockRest.create(B.class);
+       
+       @Test
+       public void b01_restMethodWithParsersSerializers_valid() throws 
Exception {
+               b.request("PUT", 
"/").accept("text/s3").contentType("text/p3").execute().assertBody("s3/p3");
+       }
+
+       @Test
+       public void b02_restMethodWithParsersSerializers_invalid() throws 
Exception {
+               b.request("PUT", "?noTrace=true").execute()
+                       .assertStatus(415)
+                       .assertBodyContains( 
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
+                               "Supported media-types: ['text/p3']"
+                       );
+               b.request("PUT", "?noTrace=true").accept("text/s1").execute()
+                       .assertStatus(415)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
+                               "Supported media-types: ['text/p3']"
+                       );
+               b.request("PUT", 
"?noTrace=true").contentType("text/p1").execute()
+                       .assertStatus(415)
+                       .assertBodyContains( 
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p1'",
+                               "Supported media-types: ['text/p3']"
+                       );
+               b.request("PUT", 
"?noTrace=true").accept("text/s1").contentType("text/p1").execute()
+                       .assertStatus(415)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p1'",
+                               "Supported media-types: ['text/p3']"
+                       );
+               b.request("PUT", 
"?noTrace=true").accept("text/s1").accept("text/s2").execute()
+                       .assertStatus(415)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
+                               "Supported media-types: ['text/p3']"
+                       );
+               b.request("PUT", 
"?noTrace=true").accept("text/s1").contentType("text/p2").execute()
+                       .assertStatus(415)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
+                               "Supported media-types: ['text/p3']"
+                       );
+               b.request("PUT", 
"?noTrace=true").accept("text/s2").contentType("text/p2").execute()
+                       .assertStatus(415)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
+                               "Supported media-types: ['text/p3']"
+                       );
+               b.request("PUT", "?noTrace=true").accept("text/s3").execute()
+                       .assertStatus(415)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
+                               "Supported media-types: ['text/p3']"
+                       );
+               b.request("PUT", 
"?noTrace=true").contentType("text/p3").execute()
+                       .assertStatus(406)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Accept': 'text/s2'",
+                               "Supported media-types: ['text/s3']"
+                       );
+       }
+       
+       
+       
//====================================================================================================
+       // Test that default Accept and Content-Type headers on servlet 
annotation are picked up
+       // when @RestMethod.addParsers/addSerializers annotations are used.
+       
//====================================================================================================
+       
+       @RestResource(
+               defaultRequestHeaders={" Accept : text/s2 "," Content-Type : 
text/p2 "},
+               parsers={P1.class,P2.class}, serializers={S1.class,S2.class}
+       )
+       public static class C {
+               @RestMethod(name=PUT, parsers=P3.class, serializers=S3.class, 
inherit="SERIALIZERS,PARSERS")
+               public String c(@Body String in) {
+                       return in;
+               }
+       }
+       
+       private static MockRest c = MockRest.create(C.class);
+
+       @Test
+       public void c01_restMethodAddParsersSerializersInherit() throws 
Exception {
+               c.request("PUT", "/").execute().assertBody("s2/p2");
+               c.request("PUT", 
"/").accept("text/s1").execute().assertBody("s1/p2");
+               c.request("PUT", 
"/").contentType("text/p1").execute().assertBody("s2/p1");
+               c.request("PUT", 
"/").accept("text/s1").contentType("text/p1").execute().assertBody("s1/p1");
+               c.request("PUT", 
"/").accept("text/s2").execute().assertBody("s2/p2");
+               c.request("PUT", 
"/").contentType("text/p2").execute().assertBody("s2/p2");
+               c.request("PUT", 
"/").accept("text/s2").contentType("text/p2").execute().assertBody("s2/p2");
+               c.request("PUT", 
"/").accept("text/s3").execute().assertBody("s3/p2");
+               c.request("PUT", 
"/").contentType("text/p3").execute().assertBody("s2/p3");
+               c.request("PUT", 
"/").accept("text/s3").contentType("text/p3").execute().assertBody("s3/p3");
+       }
+       
+       @Test
+       public void c02_restMethodAddParsersSerializersInherit_invalid() throws 
Exception {
+               c.request("PUT", 
"?noTrace=true").contentType("text/p4").execute()
+                       .assertStatus(415)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p4'",
+                               "Supported media-types: 
['text/p3','text/p1','text/p2']"
+                       );
+               c.request("PUT", "?noTrace=true").accept("text/s4").execute()
+                       .assertStatus(406)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Accept': 'text/s4'",
+                               "Supported media-types: 
['text/s3','text/s1','text/s2']"
+                       );
+       }
+
+
+       
//====================================================================================================
+       // Various Accept incantations.
+       
//====================================================================================================
+       @RestResource(
+               defaultRequestHeaders={" Accept : text/s2 "," Content-Type : 
text/p2 "},
+               parsers={P1.class,P2.class}, serializers={S1.class,S2.class}
+       )
+       public static class D {
+               @RestMethod(name=PUT)
+               public String d(@Body String in) {
+                       return in;
+               }
+       }
+       
+       private static MockRest d = MockRest.create(D.class);
+       
+       @Test
+       public void d01_accept_valid() throws Exception {
+               // "*/*" should match the first serializer, not the default 
serializer.
+               d.request("PUT", 
"/").contentType("text/p1").accept("*/*").execute().assertBody("s1/p1");
+               // "text/*" should match the first serializer, not the default 
serializer.
+               d.request("PUT", 
"/").contentType("text/p1").accept("text/*").execute().assertBody("s1/p1");
+               d.request("PUT", 
"/").contentType("text/p1").accept("bad/*,text/*").execute().assertBody("s1/p1");
+               d.request("PUT", 
"/").contentType("text/p1").accept("text/*,bad/*").execute().assertBody("s1/p1");
+               d.request("PUT", 
"/").contentType("text/p1").accept("text/s1;q=0.5,text/s2").execute().assertBody("s2/p1");
+               d.request("PUT", 
"/").contentType("text/p1").accept("text/s1,text/s2;q=0.5").execute().assertBody("s1/p1");
+       }
+       @Test
+       public void d02_accept_invalid() throws Exception {
+               d.request("PUT", 
"?noTrace=true").contentType("text/p1").accept("bad/*").execute()
+                       .assertStatus(406)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Accept': 'bad/*'",
+                               "Supported media-types: ['text/s1','text/s2']"
+                       );
+       }
+
+       
+       
//====================================================================================================
+       // Test that default Accept and Content-Type headers on method 
annotation are picked up
+       // when @RestMethod.parsers/serializers annotations are used.
+       
//====================================================================================================
+       @RestResource(
+               defaultRequestHeaders={" Accept : text/s2 "," Content-Type : 
text/p2 "},
+               parsers={P1.class,P2.class}, serializers={S1.class,S2.class}
+       )
+       public static class E {
+               @RestMethod(name=PUT, defaultRequestHeaders={"Accept: 
text/s3","Content-Type: text/p3"}, parsers=P3.class, serializers=S3.class)
+               public String e(@Body String in) {
+                       return in;
+               }
+       }
+       
+       private static MockRest e = MockRest.create(E.class);
+
+       @Test
+       public void e01_restMethodParserSerializerAnnotations_valid() throws 
Exception {
+               e.request("PUT", "/").execute().assertBody("s3/p3");
+               e.request("PUT", 
"/").accept("text/s3").execute().assertBody("s3/p3");
+               e.request("PUT", 
"/").contentType("text/p3").execute().assertBody("s3/p3");
+               e.request("PUT", 
"/").accept("text/s3").contentType("text/p3").execute().assertBody("s3/p3");
+       }
+       @Test
+       public void e02_restMethodParserSerializerAnnotations_invalid() throws 
Exception {
+               e.request("PUT", "?noTrace=true").accept("text/s1").execute()
+                       .assertStatus(406)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Accept': 'text/s1'",
+                               "Supported media-types: ['text/s3']"
+                       );
+               e.request("PUT", 
"?noTrace=true").contentType("text/p1").execute()
+                       .assertStatus(415)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p1'",
+                               "Supported media-types: ['text/p3']"
+                       );
+               e.request("PUT", 
"?noTrace=true").accept("text/s1").contentType("text/p1").execute()
+                       .assertStatus(415)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p1'",
+                               "Supported media-types: ['text/p3']"
+                       );
+               e.request("PUT", "?noTrace=true").accept("text/s2").execute()
+                       .assertStatus(406)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Accept': 'text/s2'",
+                               "Supported media-types: ['text/s3']"
+                       );
+               e.request("PUT", 
"?noTrace=true").contentType("text/p2").execute()
+                       .assertStatus(415)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
+                               "Supported media-types: ['text/p3']"
+                       );
+               e.request("PUT", 
"?noTrace=true").accept("text/s2").contentType("text/p2").execute()
+                       .assertStatus(415)
+                       .assertBodyContains(
+                               "Unsupported media-type in request header 
'Content-Type': 'text/p2'",
+                               "Supported media-types: ['text/p3']"
+                       );
+       }
+
+       
+       
//====================================================================================================
+       // Test that default Accept and Content-Type headers on method 
annotation are picked up
+       //      when @RestMethod.addParsers/addSerializers annotations are used.
+       
//====================================================================================================
+       @RestResource(
+               defaultRequestHeaders={" Accept : text/s2 "," Content-Type : 
text/p2 "},
+               parsers={P1.class,P2.class}, serializers={S1.class,S2.class}
+       )
+       public static class F {
+               @RestMethod(name=PUT, defaultRequestHeaders={"Accept: 
text/s3","Content-Type: text/p3"}, parsers=P3.class, serializers=S3.class, 
inherit="SERIALIZERS,PARSERS")
+               public String f(@Body String in) {
+                       return in;
+               }
+       }
+       
+       private static MockRest f = MockRest.create(F.class);
+
+       @Test
+       public void f01_restMethodAddParsersSerializersAnnotations_valid() 
throws Exception {
+               f.request("PUT", "/").execute().assertBody("s3/p3");
+               f.request("PUT", 
"/").accept("text/s1").execute().assertBody("s1/p3");
+               f.request("PUT", 
"/").contentType("text/p1").execute().assertBody("s3/p1");
+               f.request("PUT", 
"/").accept("text/s1").contentType("text/p1").execute().assertBody("s1/p1");
+               f.request("PUT", 
"/").accept("text/s2").execute().assertBody("s2/p3");
+               f.request("PUT", 
"/").contentType("text/p2").execute().assertBody("s3/p2");
+               f.request("PUT", 
"/").accept("text/s2").contentType("text/p2").execute().assertBody("s2/p2");
+               f.request("PUT", 
"/").accept("text/s3").execute().assertBody("s3/p3");
+               f.request("PUT", 
"/").contentType("text/p3").execute().assertBody("s3/p3");
+               f.request("PUT", 
"/").accept("text/s3").contentType("text/p3").execute().assertBody("s3/p3");
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/StatusCodesTest.java
 
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/StatusCodesTest.java
new file mode 100644
index 0000000..546844a
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-server/src/test/java/org/apache/juneau/rest/annotation/StatusCodesTest.java
@@ -0,0 +1,48 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              * 
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.rest.annotation;
+
+import static org.apache.juneau.http.HttpMethodName.*;
+
+import java.io.*;
+
+import org.apache.juneau.rest.mock.*;
+import org.junit.*;
+
+/**
+ * Validates that the correct status codes are returned on REST requests.
+ */
+@SuppressWarnings("javadoc")
+public class StatusCodesTest {
+
+       
//=================================================================================================================
+       // OK
+       
//=================================================================================================================
+       
+       @RestResource
+       public static class A {
+               @RestMethod(name=PUT)
+               public Reader a01(@Body String b) {
+                       return new StringReader(b);
+               }
+       }
+       
+       private static MockRest a = MockRest.create(A.class);
+       
+       @Test
+       public void a01a_OK() throws Exception {
+               a.request("PUT", "/").body("foo").execute().assertStatus(200);
+       }
+       
+       // TODO - Test all the status codes
+}

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

Reply via email to