http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/750916a9/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ContentTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ContentTest.java
 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ContentTest.java
new file mode 100644
index 0000000..1db53ad
--- /dev/null
+++ 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ContentTest.java
@@ -0,0 +1,450 @@
+// 
***************************************************************************************************************************
+// * 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.internal.StringUtils.*;
+import static org.junit.Assert.*;
+
+import org.apache.juneau.json.*;
+import org.apache.juneau.plaintext.*;
+import org.apache.juneau.rest.client.*;
+import org.apache.juneau.uon.*;
+import org.junit.*;
+
+public class ContentTest extends RestTestcase {
+
+       private static String URL = "/testContent";
+
+       
//====================================================================================================
+       // Basic tests using @Body parameter
+       
//====================================================================================================
+       @Test
+       public void testUsingContentParam() throws Exception {
+               RestClient c = 
TestMicroservice.client().accept("text/json+simple").build();
+               String r;
+
+               //      @RestMethod(name="POST", path="/boolean")
+               //      public boolean testBool(@Body boolean b) {
+               //              return b;
+               //      }
+               r = c.doPost(URL + "/boolean?body=true", 
null).getResponseAsString();
+               assertEquals("true", r);
+               r = c.doPost(URL + "/boolean?body=false", 
null).getResponseAsString();
+               assertEquals("false", r);
+               r = c.doPost(URL + "/boolean?body=null", 
null).getResponseAsString();
+               assertEquals("false", r);
+               try {
+                       r = c.doPost(URL + "/boolean?body=bad&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+
+               //      @RestMethod(name="POST", path="/Boolean")
+               //      public Boolean testBoolean(@Body Boolean b) {
+               //              return b;
+               //      }
+               r = c.doPost(URL + "/Boolean?body=true", 
null).getResponseAsString();
+               assertEquals("true", r);
+               r = c.doPost(URL + "/Boolean?body=false", 
null).getResponseAsString();
+               assertEquals("false", r);
+               r = c.doPost(URL + "/Boolean?body=null", 
null).getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + "/Boolean?body=bad&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/int")
+               //      public int testInt(@Body int i) {
+               //              return i;
+               //      }
+               r = c.doPost(URL + "/int?body=-123", 
null).getResponseAsString();
+               assertEquals("-123", r);
+               r = c.doPost(URL + "/int?body=null", 
null).getResponseAsString();
+               assertEquals("0", r);
+               try {
+                       r = c.doPost(URL + "/int?body=bad&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/Integer")
+               //      public Integer testInteger(@Body Integer i) {
+               //              return i;
+               //      }
+               r = c.doPost(URL + "/Integer?body=-123", 
null).getResponseAsString();
+               assertEquals("-123", r);
+               r = c.doPost(URL + "/Integer?body=null", 
null).getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + "/Integer?body=bad&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/float")
+               //      public float testFloat(@Body float f) {
+               //              return f;
+               //      }
+               r = c.doPost(URL + "/float?body=-1.23", 
null).getResponseAsString();
+               assertEquals("-1.23", r);
+               r = c.doPost(URL + "/float?body=null", 
null).getResponseAsString();
+               assertEquals("0.0", r);
+               try {
+                       r = c.doPost(URL + "/float?body=bad&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/Float")
+               //      public Float testFloat2(@Body Float f) {
+               //              return f;
+               //      }
+               r = c.doPost(URL + "/Float?body=-1.23", 
null).getResponseAsString();
+               assertEquals("-1.23", r);
+               r = c.doPost(URL + "/Float?body=null", 
null).getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + "/Float?body=bad&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/Map")
+               //      public TreeMap<String,String> testMap(@Body 
TreeMap<String,String> m) {
+               //              return m;
+               //      }
+               r = c.doPost(URL + "/Map?body=(a=b,c=d)", 
null).getResponseAsString();
+               assertEquals("{a:'b',c:'d'}", r);
+               r = c.doPost(URL + "/Map?body=null", 
null).getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + "/Map?body=bad&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/B")
+               //      public DTO2s.B testPojo1(@Body DTO2s.B b) {
+               //              return b;
+               //      }
+               DTOs.B b = DTOs.B.create();
+               r = c.doPost(URL + "/B?body=" + 
UonSerializer.DEFAULT.serialize(b), null).getResponseAsString();
+               
assertEquals("{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}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}",
 r);
+
+               //      @RestMethod(name="POST", path="/C")
+               //      public DTO2s.C testPojo2(@Body DTO2s.C c) {
+               //              return c;
+               //      }
+               DTOs.C x = DTOs.C.create();
+               r = c.doPost(URL + "/C?body=" + 
UonSerializer.DEFAULT.serialize(x), null).getResponseAsString();
+               
assertEquals("{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}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}",
 r);
+
+               c.closeQuietly();
+       }
+
+       
//====================================================================================================
+       // Basic tests using &Body parameter with &Accept=text/json
+       
//====================================================================================================
+       @Test
+       public void testUsingContentParamJsonParam() throws Exception {
+               RestClient c = 
TestMicroservice.client().accept("text/json+simple").build();
+               String r;
+
+               //      @RestMethod(name="POST", path="/boolean")
+               //      public boolean testBool(@Body boolean b) {
+               //              return b;
+               //      }
+               r = c.doPost(URL + "/boolean?body=true&Content-Type=text/json", 
null).getResponseAsString();
+               assertEquals("true", r);
+               r = c.doPost(URL + 
"/boolean?body=false&Content-Type=text/json", null).getResponseAsString();
+               assertEquals("false", r);
+               try {
+                       r = c.doPost(URL + 
"/boolean?body=null&Content-Type=text/json&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+               try {
+                       r = c.doPost(URL + 
"/boolean?body=bad&Content-Type=text/json&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+
+               //      @RestMethod(name="POST", path="/Boolean")
+               //      public Boolean testBoolean(@Body Boolean b) {
+               //              return b;
+               //      }
+               r = c.doPost(URL + "/Boolean?body=true&Content-Type=text/json", 
null).getResponseAsString();
+               assertEquals("true", r);
+               r = c.doPost(URL + 
"/Boolean?body=false&Content-Type=text/json", null).getResponseAsString();
+               assertEquals("false", r);
+               r = c.doPost(URL + "/Boolean?body=null&Content-Type=text/json", 
null).getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + 
"/Boolean?body=bad&Content-Type=text/json&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/int")
+               //      public int testInt(@Body int i) {
+               //              return i;
+               //      }
+               r = c.doPost(URL + "/int?body=-123&Content-Type=text/json", 
null).getResponseAsString();
+               assertEquals("-123", r);
+               try {
+                       r = c.doPost(URL + 
"/int?body=null&Content-Type=text/json&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+               try {
+                       r = c.doPost(URL + 
"/int?body=bad&Content-Type=text/json&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/Integer")
+               //      public Integer testInteger(@Body Integer i) {
+               //              return i;
+               //      }
+               r = c.doPost(URL + "/Integer?body=-123&Content-Type=text/json", 
null).getResponseAsString();
+               assertEquals("-123", r);
+               r = c.doPost(URL + "/Integer?body=null&Content-Type=text/json", 
null).getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + 
"/Integer?body=bad&Content-Type=text/json&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/float")
+               //      public float testFloat(@Body float f) {
+               //              return f;
+               //      }
+               r = c.doPost(URL + "/float?body=-1.23&Content-Type=text/json", 
null).getResponseAsString();
+               assertEquals("-1.23", r);
+               try {
+                       r = c.doPost(URL + 
"/float?body=null&Content-Type=text/json&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+               try {
+                       r = c.doPost(URL + 
"/float?body=bad&Content-Type=text/json&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/Float")
+               //      public Float testFloat2(@Body Float f) {
+               //              return f;
+               //      }
+               r = c.doPost(URL + "/Float?body=-1.23&Content-Type=text/json", 
null).getResponseAsString();
+               assertEquals("-1.23", r);
+               r = c.doPost(URL + "/Float?body=null&Content-Type=text/json", 
null).getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + 
"/Float?body=bad&Content-Type=text/json&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/Map")
+               //      public TreeMap<String,String> testMap(@Body 
TreeMap<String,String> m) {
+               //              return m;
+               //      }
+               r = c.doPost(URL + "/Map?body=" + urlEncode("{a:'b',c:'d'}") + 
"&Content-Type=text/json", null).getResponseAsString();
+               assertEquals("{a:'b',c:'d'}", r);
+               r = c.doPost(URL + "/Map?body=null&Content-Type=text/json", 
null).getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + 
"/Map?body=bad&Content-Type=text/json&noTrace=true", 
null).getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/B")
+               //      public DTO2s.B testPojo1(@Body DTO2s.B b) {
+               //              return b;
+               //      }
+               DTOs.B b = DTOs.B.create();
+               r = c.doPost(URL + "/B?body=" + 
urlEncode(JsonSerializer.DEFAULT_LAX.serialize(b)) + "&Content-Type=text/json", 
null).getResponseAsString();
+               
assertEquals("{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}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}",
 r);
+
+               //      @RestMethod(name="POST", path="/C")
+               //      public DTO2s.C testPojo2(@Body DTO2s.C c) {
+               //              return c;
+               //      }
+               DTOs.C x = DTOs.C.create();
+               r = c.doPost(URL + "/C?body=" + 
urlEncode(JsonSerializer.DEFAULT_LAX.serialize(x)) + "&Content-Type=text/json", 
null).getResponseAsString();
+               
assertEquals("{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}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}",
 r);
+
+               c.closeQuietly();
+       }
+
+       
//====================================================================================================
+       // Basic tests using HTTP body content
+       
//====================================================================================================
+       @Test
+       public void testUsingContent() throws Exception {
+               RestClient c = 
TestMicroservice.client().accept("text/json+simple").contentType("text/uon").serializer(PlainTextSerializer.class).build();
+               String r;
+
+               //      @RestMethod(name="POST", path="/boolean")
+               //      public boolean testBool(@Body boolean b) {
+               //              return b;
+               //      }
+               r = c.doPost(URL + "/boolean", "true").getResponseAsString();
+               assertEquals("true", r);
+               r = c.doPost(URL + "/boolean", "false").getResponseAsString();
+               assertEquals("false", r);
+               r = c.doPost(URL + "/boolean", "null").getResponseAsString();
+               assertEquals("false", r);
+               try {
+                       r = c.doPost(URL + "/boolean?noTrace=true", 
"bad").getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+
+               //      @RestMethod(name="POST", path="/Boolean")
+               //      public Boolean testBoolean(@Body Boolean b) {
+               //              return b;
+               //      }
+               r = c.doPost(URL + "/Boolean", "true").getResponseAsString();
+               assertEquals("true", r);
+               r = c.doPost(URL + "/Boolean", "false").getResponseAsString();
+               assertEquals("false", r);
+               r = c.doPost(URL + "/Boolean", "null").getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + "/Boolean?noTrace=true", 
"bad").getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/int")
+               //      public int testInt(@Body int i) {
+               //              return i;
+               //      }
+               r = c.doPost(URL + "/int", "-123").getResponseAsString();
+               assertEquals("-123", r);
+               r = c.doPost(URL + "/int", "null").getResponseAsString();
+               assertEquals("0", r);
+               try {
+                       r = c.doPost(URL + "/int?noTrace=true", 
"bad").getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/Integer")
+               //      public Integer testInteger(@Body Integer i) {
+               //              return i;
+               //      }
+               r = c.doPost(URL + "/Integer", "-123").getResponseAsString();
+               assertEquals("-123", r);
+               r = c.doPost(URL + "/Integer", "null").getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + "/Integer?noTrace=true", 
"bad").getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/float")
+               //      public float testFloat(@Body float f) {
+               //              return f;
+               //      }
+               r = c.doPost(URL + "/float", "-1.23").getResponseAsString();
+               assertEquals("-1.23", r);
+               r = c.doPost(URL + "/float", "null").getResponseAsString();
+               assertEquals("0.0", r);
+               try {
+                       r = c.doPost(URL + "/float?noTrace=true", 
"bad").getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/Float")
+               //      public Float testFloat2(@Body Float f) {
+               //              return f;
+               //      }
+               r = c.doPost(URL + "/Float", "-1.23").getResponseAsString();
+               assertEquals("-1.23", r);
+               r = c.doPost(URL + "/Float", "null").getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + "/Float?noTrace=true", 
"bad").getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/Map")
+               //      public TreeMap<String,String> testMap(@Body 
TreeMap<String,String> m) {
+               //              return m;
+               //      }
+               r = c.doPost(URL + "/Map", "(a=b,c=d)").getResponseAsString();
+               assertEquals("{a:'b',c:'d'}", r);
+               r = c.doPost(URL + "/Map", "null").getResponseAsString();
+               assertEquals("null", r);
+               try {
+                       r = c.doPost(URL + "/Map?noTrace=true", 
"bad").getResponseAsString();
+                       fail("Exception expected!");
+               } catch (RestCallException e) {
+                       assertEquals(400, e.getResponseCode());
+               }
+
+               //      @RestMethod(name="POST", path="/B")
+               //      public DTO2s.B testPojo1(@Body DTO2s.B b) {
+               //              return b;
+               //      }
+               DTOs.B b = DTOs.B.create();
+               r = c.doPost(URL + "/B", "" + 
UonSerializer.DEFAULT.serialize(b)).getResponseAsString();
+               
assertEquals("{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}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}",
 r);
+
+               //      @RestMethod(name="POST", path="/C")
+               //      public DTO2s.C testPojo2(@Body DTO2s.C c) {
+               //              return c;
+               //      }
+               DTOs.C x = DTOs.C.create();
+               r = c.doPost(URL + "/C", "" + 
UonSerializer.DEFAULT.serialize(x)).getResponseAsString();
+               
assertEquals("{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}],f19:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f20:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]]}",
 r);
+
+               c.closeQuietly();
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/750916a9/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/DTOs.java
----------------------------------------------------------------------
diff --git 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/DTOs.java
 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/DTOs.java
new file mode 100644
index 0000000..69a925e
--- /dev/null
+++ 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/DTOs.java
@@ -0,0 +1,138 @@
+// 
***************************************************************************************************************************
+// * 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 java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.urlencoding.annotation.*;
+import org.apache.juneau.utils.*;
+
+public class DTOs {
+
+       @Bean(sort=true)
+       public static class A {
+               public String a;
+               public int b;
+               public boolean c;
+
+               public static A create() {
+                       A t = new A();
+                       t.a = "a";
+                       t.b = 1;
+                       t.c = true;
+                       return t;
+               }
+
+       }
+
+       @Bean(sort=true)
+       public static class B {
+               public String[] f01;
+               public List<String> f02;
+               public int[] f03;
+               public List<Integer> f04;
+               public String[][] f05;
+               public List<String[]> f06;
+               public A[] f07;
+               public List<A> f08;
+               public A[][] f09;
+               public List<List<A>> f10;
+
+               private String[] f11;
+               private List<String> f12;
+               private int[] f13;
+               private List<Integer> f14;
+               private String[][] f15;
+               private List<String[]> f16;
+               private A[] f17;
+               private List<A> f18;
+               private A[][] f19;
+               private List<List<A>> f20;
+
+               public String[] getF11() { return f11; }
+               public List<String> getF12() { return f12; }
+               public int[] getF13() { return f13; }
+               public List<Integer> getF14() { return f14; }
+               public String[][] getF15() { return f15; }
+               public List<String[]> getF16() { return f16; }
+               public A[] getF17() { return f17; }
+               public List<A> getF18() { return f18; }
+               public A[][] getF19() { return f19; }
+               public List<List<A>> getF20() { return f20; }
+
+               public void setF11(String[] f11) { this.f11 = f11; }
+               public void setF12(List<String> f12) { this.f12 = f12; }
+               public void setF13(int[] f13) { this.f13 = f13; }
+               public void setF14(List<Integer> f14) { this.f14 = f14; }
+               public void setF15(String[][] f15) { this.f15 = f15; }
+               public void setF16(List<String[]> f16) { this.f16 = f16; }
+               public void setF17(A[] f17) { this.f17 = f17; }
+               public void setF18(List<A> f18) { this.f18 = f18; }
+               public void setF19(A[][] f19) { this.f19 = f19; }
+               public void setF20(List<List<A>> f20) { this.f20 = f20; }
+
+               static B create() {
+                       B t = new B();
+                       t.f01 = new String[]{"a","b"};
+                       t.f02 = new AList<String>().append("c").append("d");
+                       t.f03 = new int[]{1,2};
+                       t.f04 = new AList<Integer>().append(3).append(4);
+                       t.f05 = new String[][]{{"e","f"},{"g","h"}};
+                       t.f06 = new AList<String[]>().append(new 
String[]{"i","j"}).append(new String[]{"k","l"});
+                       t.f07 = new A[]{A.create(),A.create()};
+                       t.f08 = new 
AList<A>().append(A.create()).append(A.create());
+                       t.f09 = new A[][]{{A.create()},{A.create()}};
+                       t.f10 = new 
AList<List<A>>().append(Arrays.asList(A.create())).append(Arrays.asList(A.create()));
+                       t.setF11(new String[]{"a","b"});
+                       t.setF12(new AList<String>().append("c").append("d"));
+                       t.setF13(new int[]{1,2});
+                       t.setF14(new AList<Integer>().append(3).append(4));
+                       t.setF15(new String[][]{{"e","f"},{"g","h"}});
+                       t.setF16(new AList<String[]>().append(new 
String[]{"i","j"}).append(new String[]{"k","l"}));
+                       t.setF17(new A[]{A.create(),A.create()});
+                       t.setF18(new 
AList<A>().append(A.create()).append(A.create()));
+                       t.setF19(new A[][]{{A.create()},{A.create()}});
+                       t.setF20(new 
AList<List<A>>().append(Arrays.asList(A.create())).append(Arrays.asList(A.create())));
+                       return t;
+               }
+       }
+
+       @UrlEncoding(expandedParams=true)
+       public static class C extends B {
+               static C create() {
+                       C t = new C();
+                       t.f01 = new String[]{"a","b"};
+                       t.f02 = new AList<String>().append("c").append("d");
+                       t.f03 = new int[]{1,2};
+                       t.f04 = new AList<Integer>().append(3).append(4);
+                       t.f05 = new String[][]{{"e","f"},{"g","h"}};
+                       t.f06 = new AList<String[]>().append(new 
String[]{"i","j"}).append(new String[]{"k","l"});
+                       t.f07 = new A[]{A.create(),A.create()};
+                       t.f08 = new 
AList<A>().append(A.create()).append(A.create());
+                       t.f09 = new A[][]{{A.create()},{A.create()}};
+                       t.f10 = new 
AList<List<A>>().append(Arrays.asList(A.create())).append(Arrays.asList(A.create()));
+                       t.setF11(new String[]{"a","b"});
+                       t.setF12(new AList<String>().append("c").append("d"));
+                       t.setF13(new int[]{1,2});
+                       t.setF14(new AList<Integer>().append(3).append(4));
+                       t.setF15(new String[][]{{"e","f"},{"g","h"}});
+                       t.setF16(new AList<String[]>().append(new 
String[]{"i","j"}).append(new String[]{"k","l"}));
+                       t.setF17(new A[]{A.create(),A.create()});
+                       t.setF18(new 
AList<A>().append(A.create()).append(A.create()));
+                       t.setF19(new A[][]{{A.create()},{A.create()}});
+                       t.setF20(new 
AList<List<A>>().append(Arrays.asList(A.create())).append(Arrays.asList(A.create())));
+                       return t;
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/750916a9/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/DefaultContentTypesTest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..57199ce
--- /dev/null
+++ 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/DefaultContentTypesTest.java
@@ -0,0 +1,427 @@
+// 
***************************************************************************************************************************
+// * 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.rest.test.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);
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/750916a9/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ErrorConditionsTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ErrorConditionsTest.java
 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ErrorConditionsTest.java
new file mode 100644
index 0000000..81bce1d
--- /dev/null
+++ 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/ErrorConditionsTest.java
@@ -0,0 +1,210 @@
+// 
***************************************************************************************************************************
+// * 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.rest.test.TestUtils.*;
+import static org.junit.Assert.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.client.*;
+import org.junit.*;
+
+
+public class ErrorConditionsTest extends RestTestcase {
+
+       private static String URL = "/testErrorConditions";
+       private static boolean debug = false;
+       private RestClient client = TestMicroservice.DEFAULT_CLIENT;
+
+
+       
//====================================================================================================
+       // Test non-existent properties
+       
//====================================================================================================
+       @Test
+       public void testNonExistentBeanProperties() throws Exception {
+               String url = URL + "/testNonExistentBeanProperties";
+
+               try {
+                       client.doPut(url + "?noTrace=true", new 
ObjectMap("{f2:'foo'}")).getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_BAD_REQUEST,
+                               "Could not convert request body content to 
class type 'org.apache.juneau.rest.test.ErrorConditionsResource$Test1' using 
parser 'org.apache.juneau.json.JsonParser'",
+                               "Unknown property 'f2' encountered while trying 
to parse into class 
'org.apache.juneau.rest.test.ErrorConditionsResource$Test1'");
+               }
+
+               try {
+                       client.doPut(url + "?noTrace=true", new 
ObjectMap("{f1:'foo', f2:'foo'}")).getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_BAD_REQUEST,
+                               "Could not convert request body content to 
class type 'org.apache.juneau.rest.test.ErrorConditionsResource$Test1' using 
parser 'org.apache.juneau.json.JsonParser'",
+                               "Unknown property 'f2' encountered while trying 
to parse into class 
'org.apache.juneau.rest.test.ErrorConditionsResource$Test1'");
+               }
+       }
+
+       
//====================================================================================================
+       // Test trying to set properties to wrong data type
+       
//====================================================================================================
+       @Test
+       public void testWrongDataType() throws Exception {
+               String url = URL + "/testWrongDataType";
+               try {
+                       client.doPut(url + "?noTrace=true", new 
ObjectMap("{f1:'foo'}")).getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_BAD_REQUEST,
+                               "Invalid number");
+               }
+       }
+
+       
//====================================================================================================
+       // Test trying to parse into class with non-public no-arg constructor.
+       
//====================================================================================================
+       @Test
+       public void testParseIntoNonConstructableBean() throws Exception {
+               String url = URL + "/testParseIntoNonConstructableBean";
+               try {
+                       client.doPut(url + "?noTrace=true", new 
ObjectMap("{f1:1}")).getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_BAD_REQUEST,
+                               "Class 
'org.apache.juneau.rest.test.ErrorConditionsResource$Test3a' could not be 
instantiated.");
+               }
+       }
+
+       
//====================================================================================================
+       // Test trying to parse into non-static inner class
+       
//====================================================================================================
+       @Test
+       public void testParseIntoNonStaticInnerClass() throws Exception {
+               String url = URL + "/testParseIntoNonStaticInnerClass";
+               try {
+                       client.doPut(url + "?noTrace=true", new 
ObjectMap("{f1:1}")).getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_BAD_REQUEST,
+                               "Class 
'org.apache.juneau.rest.test.ErrorConditionsResource$Test3b' could not be 
instantiated.  Reason: 'No properties detected on bean class'");
+               }
+       }
+
+       
//====================================================================================================
+       // Test trying to parse into non-public inner class
+       
//====================================================================================================
+       @Test
+       public void testParseIntoNonPublicInnerClass() throws Exception {
+               String url = URL + "/testParseIntoNonPublicInnerClass";
+               try {
+                       client.doPut(url + "?noTrace=true", new 
ObjectMap("{f1:1}")).getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_BAD_REQUEST,
+                               "Class 
'org.apache.juneau.rest.test.ErrorConditionsResource$Test3b1' could not be 
instantiated",
+                               "Class is not public");
+               }
+       }
+
+       
//====================================================================================================
+       // Test exception thrown during bean construction.
+       
//====================================================================================================
+       @Test
+       public void testThrownConstructorException() throws Exception {
+               String url = URL + "/testThrownConstructorException";
+               try {
+                       client.doPut(url + "?noTrace=true", 
"'foo'").getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_BAD_REQUEST,
+                               "Could not convert request body content to 
class type 'org.apache.juneau.rest.test.ErrorConditionsResource$Test3c' using 
parser 'org.apache.juneau.json.JsonParser'.",
+                               "Test error");
+               }
+       }
+
+       
//====================================================================================================
+       // Test trying to set parameters to invalid types.
+       
//====================================================================================================
+       @Test
+       public void testSetParameterToInvalidTypes() throws Exception {
+               String url = URL + "/testSetParameterToInvalidTypes";
+               try {
+                       client.doPut(url + "/1?noTrace=true&p1=foo", 
"").getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_BAD_REQUEST,
+                               "Could not convert QUERY 'p1' to type 'int' on 
method 
'org.apache.juneau.rest.test.ErrorConditionsResource.testSetParameterToInvalidTypes'");
+               }
+
+               try {
+                       client.doPut(url + "/foo?noTrace=true&p1=1", 
"").getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_BAD_REQUEST,
+                               "Could not convert PATH 'a1' to type 'int' on 
method 
'org.apache.juneau.rest.test.ErrorConditionsResource.testSetParameterToInvalidTypes'");
+               }
+
+               try {
+                       client.doPut(url + "/1?noTrace=true&p1=1", 
"").header("h1", "foo").getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_BAD_REQUEST,
+                               "Could not convert HEADER 'h1' to type 'int' on 
method 
'org.apache.juneau.rest.test.ErrorConditionsResource.testSetParameterToInvalidTypes'");
+               }
+       }
+
+       
//====================================================================================================
+       // Test SC_NOT_FOUND & SC_METHOD_NOT_ALLOWED
+       
//====================================================================================================
+       @Test
+       public void test404and405() throws Exception {
+               String url = URL + "/test404and405";
+               try {
+                       client.doGet(URL + 
"/testNonExistent?noTrace=true").getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_FOUND,
+                               "Method 'GET' not found on resource with 
matching pattern on path '/testNonExistent'");
+               }
+
+               try {
+                       client.doPut(url + "?noTrace=true", 
"").getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_FOUND,
+                               "Method 'PUT' not found on resource with 
matching pattern on path '/test404and405'");
+               }
+
+               try {
+                       client.doPost(url + "?noTrace=true", 
"").getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_METHOD_NOT_ALLOWED,
+                               "Method 'POST' not found on resource.");
+               }
+       }
+
+       
//====================================================================================================
+       // Test SC_PRECONDITION_FAILED
+       
//====================================================================================================
+       @Test
+       public void test412() throws Exception {
+               String url = URL + "/test412";
+               try {
+                       client.doGet(url + 
"?noTrace=true").getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_PRECONDITION_FAILED,
+                               "Method 'GET' not found on resource on path 
'/test412' with matching matcher.");
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/750916a9/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
new file mode 100644
index 0000000..d0f1874
--- /dev/null
+++ 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
@@ -0,0 +1,135 @@
+// 
***************************************************************************************************************************
+// * 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.rest.test.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.rest.client.*;
+import org.apache.juneau.urlencoding.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+
+/**
+ * Tests client-side form posts.
+ */
+public class FormDataTest extends RestTestcase {
+
+       private static String URL = "/testFormData";
+       RestClient client = TestMicroservice.DEFAULT_CLIENT;
+
+       
//====================================================================================================
+       // Form data tests using RestCall.formData() method.
+       
//====================================================================================================
+       @Test
+       public void testFormDataMethod() throws Exception {
+               RestClient c = TestMicroservice.DEFAULT_CLIENT;
+               String r;
+
+               r = c.doPost(URL)
+                       .formData("foo", 123)
+                       .formData("bar", "baz")
+                       .getResponseAsString();
+               assertEquals("Content-Type=[application/x-www-form-urlencoded], 
contents=[foo=123&bar=baz]", r);
+       }
+
+       
//====================================================================================================
+       // Form data tests using RestClient.doPost(NameValuePairs).
+       
//====================================================================================================
+       @Test
+       public void testDoPostNameValuePairs() throws Exception {
+               RestClient c = TestMicroservice.DEFAULT_CLIENT;
+               String r;
+
+               r = c.doPost(URL, new 
NameValuePairs().append("foo",123).append("bar","baz"))
+                       .getResponseAsString();
+               assertEquals("Content-Type=[application/x-www-form-urlencoded], 
contents=[foo=123&bar=baz]", r);
+       }
+
+       public static class A {
+               public int f1 = 1;
+       }
+
+       
//====================================================================================================
+       // Form data tests using RestClientBuilder.plainTextParams().
+       
//====================================================================================================
+       @Test
+       public void testPlainTextParams() throws Exception {
+               RestClient c = 
TestMicroservice.client(UrlEncodingSerializer.class, 
UrlEncodingParser.class).plainTextParts().build();
+               String r;
+
+               Map<String,Object> m = new AMap<String,Object>()
+                       .append("foo", "foo")
+                       .append("'foo'", "'foo'")
+                       .append("(foo)", "(foo)")
+                       .append("@(foo)", "@(foo)");
+
+               r = c.doPost(URL, m).getResponseAsString();
+               assertEquals("Content-Type=[application/x-www-form-urlencoded], 
contents=[foo=foo&'foo'='foo'&(foo)=(foo)&@(foo)=@(foo)]", r);
+
+               List<String> l = new AList<String>().appendAll("foo", "'foo'", 
"(foo)", "@(foo)");
+               r = c.doPost(URL, l).getResponseAsString();
+               assertEquals("Content-Type=[application/x-www-form-urlencoded], 
contents=[0=foo&1='foo'&2=(foo)&3=@(foo)]", r);
+
+               NameValuePairs nvp = new NameValuePairs()
+                       .append("foo", "foo")
+                       .append("'foo'", "'foo'")
+                       .append("(foo)", "(foo)")
+                       .append("@(foo)", "@(foo)");
+               r = c.doPost(URL, nvp).getResponseAsString();
+               assertEquals("Content-Type=[application/x-www-form-urlencoded], 
contents=[foo=foo&%27foo%27=%27foo%27&%28foo%29=%28foo%29&%40%28foo%29=%40%28foo%29]",
 r);
+
+               r = c.doPost(URL)
+                       .formData("foo", "foo")
+                       .formData("'foo'", "'foo'")
+                       .formData("(foo)", "(foo)")
+                       .formData("@(foo)", "@(foo)")
+                       .getResponseAsString();
+               assertEquals("Content-Type=[application/x-www-form-urlencoded], 
contents=[foo=foo&%27foo%27=%27foo%27&%28foo%29=%28foo%29&%40%28foo%29=%40%28foo%29]",
 r);
+       }
+
+       
//====================================================================================================
+       // Default values.
+       
//====================================================================================================
+
+       @Test
+       public void defaultFormData() throws Exception {
+               assertObjectEquals("{f1:'1',f2:'2',f3:'3'}", client.doPost(URL 
+ "/defaultFormData").getResponse(ObjectMap.class));
+               assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL 
+ 
"/defaultFormData").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class));
+               assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL 
+ 
"/defaultFormData").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class));
+       }
+
+       @Test
+       public void annotatedFormData() throws Exception {
+               assertObjectEquals("{f1:null,f2:null,f3:null}", 
client.doPost(URL + "/annotatedFormData").getResponse(ObjectMap.class));
+               assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL 
+ 
"/annotatedFormData").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class));
+               assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL 
+ 
"/annotatedFormData").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class));
+       }
+
+       @Test
+       public void annotatedFormDataDefault() throws Exception {
+               assertObjectEquals("{f1:'1',f2:'2',f3:'3'}", client.doPost(URL 
+ "/annotatedFormDataDefault").getResponse(ObjectMap.class));
+               assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL 
+ 
"/annotatedFormDataDefault").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class));
+               assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL 
+ 
"/annotatedFormDataDefault").formData("f1",4).formData("f2",5).formData("f3",6).getResponse(ObjectMap.class));
+       }
+
+       @Test
+       public void annotatedAndDefaultFormData() throws Exception {
+               assertObjectEquals("{f1:'4',f2:'5',f3:'6'}", client.doPost(URL 
+ "/annotatedAndDefaultFormData").getResponse(ObjectMap.class));
+               assertObjectEquals("{f1:'7',f2:'8',f3:'9'}", client.doPost(URL 
+ 
"/annotatedAndDefaultFormData").formData("f1",7).formData("f2",8).formData("f3",9).getResponse(ObjectMap.class));
+               assertObjectEquals("{f1:'7',f2:'8',f3:'9'}", client.doPost(URL 
+ 
"/annotatedAndDefaultFormData").formData("f1",7).formData("f2",8).formData("f3",9).getResponse(ObjectMap.class));
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/750916a9/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/GroupsTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/GroupsTest.java
 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/GroupsTest.java
new file mode 100644
index 0000000..874b0da
--- /dev/null
+++ 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/GroupsTest.java
@@ -0,0 +1,109 @@
+// 
***************************************************************************************************************************
+// * 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.rest.test.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.io.*;
+
+import org.apache.juneau.rest.client.*;
+import org.junit.*;
+
+
+public class GroupsTest extends RestTestcase {
+
+       private static String URL = "/testGroups";
+       private static boolean debug = false;
+
+       
//====================================================================================================
+       // Serializer defined on class.
+       
//====================================================================================================
+       @Test
+       public void testSerializerDefinedOnClass() throws Exception {
+               RestClient client = TestMicroservice.DEFAULT_CLIENT;
+               String url = URL + "/testSerializerDefinedOnClass";
+               String r;
+
+               try {
+                       r = 
client.doGet(url+"?noTrace=true").contentType("text/p1").getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported media-type in request header 
'Accept': 'application/json'",
+                               "Supported media-types: ['text/s1','text/s2']"
+                       );
+               }
+
+               r = 
client.doGet(url).accept("text/s1").contentType("").getResponseAsString();
+               assertEquals("text/s,GET", r);
+
+               r = 
client.doGet(url).accept("text/s2").contentType("").getResponseAsString();
+               assertEquals("text/s,GET", r);
+
+               try {
+                       r = 
client.doGet(url+"?noTrace=true").accept("text/s3").contentType("").getResponseAsString();
+                       assertEquals("text/s,GET", r);
+               } 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", new 
StringReader("foo")).accept("text/json").contentType("text/p1").getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported media-type in request header 
'Accept': 'text/json'",
+                               "Supported media-types: ['text/s1','text/s2']"
+                       );
+               }
+
+               try {
+                       r = client.doPut(url+"?noTrace=true", new 
StringReader("foo")).accept("text/s1").contentType("text/json").getResponseAsString();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
+                               "Unsupported media-type in request header 
'Content-Type': 'text/json'",
+                               "Supported media-types: ['text/p1','text/p2']"
+                       );
+               }
+
+               r = client.doPut(url, new 
StringReader("foo")).contentType("text/p1").accept("text/s1").getResponseAsString();
+               assertEquals("text/s,foo", r);
+
+               r = client.doPut(url, new 
StringReader("foo")).contentType("text/p2").accept("text/s2").getResponseAsString();
+               assertEquals("text/s,foo", r);
+
+               try {
+                       r = client.doPut(url+"?noTrace=true", new 
StringReader("foo")).contentType("text/p1").accept("text/s3").getResponseAsString();
+               } 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", new 
StringReader("foo")).contentType("text/p3").accept("text/s1").getResponseAsString();
+               } 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']"
+                       );
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/750916a9/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/GzipTest.java
----------------------------------------------------------------------
diff --git 
a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/GzipTest.java
 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/GzipTest.java
new file mode 100644
index 0000000..2df12fd
--- /dev/null
+++ 
b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/GzipTest.java
@@ -0,0 +1,340 @@
+// 
***************************************************************************************************************************
+// * 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.internal.IOUtils.*;
+import static org.apache.juneau.rest.test.TestUtils.*;
+import static org.junit.Assert.*;
+
+import java.io.*;
+import java.util.zip.*;
+
+import org.apache.http.impl.client.*;
+import org.apache.juneau.rest.client.*;
+import org.junit.*;
+
+/**
+ * Test Accept-Encoding and Content-Encoding handling.
+ *
+ * Note:  WAS does automatic gzip decompression on http request messages, so 
we have to invent
+ *     our own 'mycoding' compression.
+ */
+public class GzipTest extends RestTestcase {
+
+       private static boolean debug = false;
+
+       private static String testGzipOff = "/testGzipOff";
+       private static String testGzipOn = "/testGzipOn";
+
+       // Converts string into a GZipped input stream.
+       private static InputStream compress(String contents) throws Exception {
+               ByteArrayOutputStream baos = new 
ByteArrayOutputStream(contents.length()>>1);
+               GZIPOutputStream gos = new GZIPOutputStream(baos);
+               gos.write(contents.getBytes());
+               gos.finish();
+               gos.close();
+               return new ByteArrayInputStream(baos.toByteArray());
+       }
+
+       private static String decompress(InputStream is) throws Exception {
+               return read(new GZIPInputStream(is));
+       }
+
+       
//====================================================================================================
+       // Test with no compression enabled.
+       
//====================================================================================================
+       @Test
+       public void testGzipOff() throws Exception {
+               RestClient c = 
TestMicroservice.client().accept("text/plain").contentType("text/plain").build();
+               RestCall r;
+               String url = testGzipOff;
+
+               // *** GET ***
+
+               r = c.doGet(url);
+               assertEquals("foo", r.getResponseAsString());
+
+               r = c.doGet(url).acceptEncoding("");
+               assertEquals("foo", r.getResponseAsString());
+
+               r = c.doGet(url).acceptEncoding("*");
+               assertEquals("foo", r.getResponseAsString());
+
+               r = c.doGet(url).acceptEncoding("identity");
+               assertEquals("foo", r.getResponseAsString());
+
+               // Should match identity.
+               r = c.doGet(url).acceptEncoding("mycoding");
+               assertEquals("foo", r.getResponseAsString());
+
+               // Shouldn't match.
+               try {
+                       r = 
c.doGet(url+"?noTrace=true").acceptEncoding("mycoding,identity;q=0").connect();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported encoding in request header 
'Accept-Encoding': 'mycoding,identity;q=0'",
+                               "Supported codings: ['identity']"
+                       );
+               }
+
+               // Shouldn't match.
+               try {
+                       
c.doGet(url+"?noTrace=true").acceptEncoding("mycoding,*;q=0").connect();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported encoding in request header 
'Accept-Encoding': 'mycoding,*;q=0'",
+                               "Supported codings: ['identity']"
+                       );
+               }
+
+               // Should match identity
+               r = 
c.doGet(url).acceptEncoding("identity;q=0.8,mycoding;q=0.6");
+               assertEquals("foo", r.getResponseAsString());
+
+               // Should match identity
+               r = 
c.doGet(url).acceptEncoding("mycoding;q=0.8,identity;q=0.6");
+               assertEquals("foo", r.getResponseAsString());
+
+               // Should match identity
+               r = c.doGet(url).acceptEncoding("mycoding;q=0.8,*;q=0.6");
+               assertEquals("foo", r.getResponseAsString());
+
+               // Should match identity
+               r = c.doGet(url).acceptEncoding("*;q=0.8,myencoding;q=0.6");
+               assertEquals("foo", r.getResponseAsString());
+
+               // Shouldn't match
+               try {
+                       
c.doGet(url+"?noTrace=true").acceptEncoding("identity;q=0").connect();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported encoding in request header 
'Accept-Encoding': 'identity;q=0'",
+                               "Supported codings: ['identity']"
+                       );
+               }
+
+               // Shouldn't match
+               try {
+                       
c.doGet(url+"?noTrace=true").acceptEncoding("identity;q=0.0").connect();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported encoding in request header 
'Accept-Encoding': 'identity;q=0.0'",
+                               "Supported codings: ['identity']"
+                       );
+               }
+
+               // Shouldn't match
+               try {
+                       
c.doGet(url+"?noTrace=true").acceptEncoding("*;q=0").connect();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported encoding in request header 
'Accept-Encoding': '*;q=0'",
+                               "Supported codings: ['identity']"
+                       );
+               }
+
+               // Shouldn't match
+               try {
+                       
c.doGet(url+"?noTrace=true").acceptEncoding("*;q=0.0").connect();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported encoding in request header 
'Accept-Encoding': '*;q=0.0'",
+                               "Supported codings: ['identity']"
+                       );
+               }
+
+
+               // *** PUT ***
+
+               r = c.doPut(url, new StringReader("foo"));
+               assertEquals("foo", r.getResponseAsString());
+
+               r = c.doPut(url, new 
StringReader("foo")).header("Content-Encoding", "");
+               assertEquals("foo", r.getResponseAsString());
+
+               r = c.doPut(url, new 
StringReader("foo")).header("Content-Encoding", "identity");
+               assertEquals("foo", r.getResponseAsString());
+
+               try {
+                       c.doPut(url+"?noTrace=true", 
compress("foo")).header("Content-Encoding", "mycoding").connect();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_UNSUPPORTED_MEDIA_TYPE,
+                               "Unsupported encoding in request header 
'Content-Encoding': 'mycoding'",
+                               "Supported codings: ['identity']"
+                       );
+               }
+
+               c.closeQuietly();
+       }
+
+       
//====================================================================================================
+       // Test with compression enabled.
+       
//====================================================================================================
+       @Test
+       public void testGzipOn() throws Exception {
+
+               // Create a client that disables content compression support so 
that we can get the gzipped content directly.
+               CloseableHttpClient httpClient = 
HttpClients.custom().setSSLSocketFactory(TestMicroservice.getSSLSocketFactory()).disableContentCompression().build();
+
+               RestClient c = TestMicroservice.client().httpClient(httpClient, 
false).accept("text/plain").contentType("text/plain").build();
+               RestCall r;
+               String url = testGzipOn;
+
+               // *** GET ***
+
+               r = c.doGet(url);
+               assertEquals("foo", r.getResponseAsString());
+
+               r = c.doGet(url).acceptEncoding("");
+               assertEquals("foo", r.getResponseAsString());
+
+               r = c.doGet(url).acceptEncoding("*");
+               assertEquals("foo", decompress(r.getInputStream()));
+
+               r = c.doGet(url).acceptEncoding("identity");
+               assertEquals("foo", r.getResponseAsString());
+
+               // Should match identity.
+               r = c.doGet(url).acceptEncoding("mycoding");
+               assertEquals("foo", decompress(r.getInputStream()));
+
+               r = 
c.doGet(url).acceptEncoding("mycoding,identity;q=0").connect();
+               assertEquals("foo", decompress(r.getInputStream()));
+
+               r = c.doGet(url).acceptEncoding("mycoding,*;q=0").connect();
+               assertEquals("foo", decompress(r.getInputStream()));
+
+               // Should match identity
+               r = 
c.doGet(url).acceptEncoding("identity;q=0.8,mycoding;q=0.6");
+               assertEquals("foo", r.getResponseAsString());
+
+               // Should match mycoding
+               r = 
c.doGet(url).acceptEncoding("mycoding;q=0.8,identity;q=0.6");
+               assertEquals("foo", decompress(r.getInputStream()));
+
+               // Should match mycoding
+               r = c.doGet(url).acceptEncoding("mycoding;q=0.8,*;q=0.6");
+               assertEquals("foo", decompress(r.getInputStream()));
+
+               // Shouldn't match
+               try {
+                       
c.doGet(url+"?noTrace=true").acceptEncoding("identity;q=0").connect();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported encoding in request header 
'Accept-Encoding': 'identity;q=0'",
+                               "Supported codings: ['mycoding','identity']"
+                       );
+               }
+
+               // Shouldn't match
+               try {
+                       
c.doGet(url+"?noTrace=true").acceptEncoding("identity;q=0.0").connect();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported encoding in request header 
'Accept-Encoding': 'identity;q=0.0'",
+                               "Supported codings: ['mycoding','identity']"
+                       );
+               }
+
+               // Shouldn't match
+               try {
+                       
c.doGet(url+"?noTrace=true").acceptEncoding("*;q=0").connect();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported encoding in request header 
'Accept-Encoding': '*;q=0'",
+                               "Supported codings: ['mycoding','identity']"
+                       );
+               }
+
+               // Shouldn't match
+               try {
+                       
c.doGet(url+"?noTrace=true").acceptEncoding("*;q=0.0").connect();
+                       fail("Exception expected");
+               } catch (RestCallException e) {
+                       checkErrorResponse(debug, e, SC_NOT_ACCEPTABLE,
+                               "Unsupported encoding in request header 
'Accept-Encoding': '*;q=0.0'",
+                               "Supported codings: ['mycoding','identity']"
+                       );
+               }
+
+
+               // *** PUT ***
+
+               r = c.doPut(url, new StringReader("foo"));
+               assertEquals("foo", r.getResponseAsString());
+
+               r = c.doPut(url, new 
StringReader("foo")).header("Content-Encoding", "");
+               assertEquals("foo", r.getResponseAsString());
+
+               r = c.doPut(url, new 
StringReader("foo")).header("Content-Encoding", "identity");
+               assertEquals("foo", r.getResponseAsString());
+
+               r = c.doPut(url, compress("foo")).header("Content-Encoding", 
"mycoding");
+               assertEquals("foo", r.getResponseAsString());
+
+               c.closeQuietly(); // We want to close our client because we 
created the HttpClient in this method.
+       }
+
+       
//====================================================================================================
+       // Test with compression enabled but with servlet using output stream 
directly.
+       
//====================================================================================================
+       @Test
+       public void testGzipOnDirect() throws Exception {
+               // Create a client that disables content compression support so 
that we can get the gzipped content directly.
+               CloseableHttpClient httpClient = 
HttpClientBuilder.create().setSSLSocketFactory(TestMicroservice.getSSLSocketFactory()).build();
+               RestClient c = TestMicroservice.client().httpClient(httpClient, 
false).accept("text/plain").contentType("text/plain").build();
+               RestCall r = null;
+               String s = null;
+
+               // res.getOutputStream() called....should bypass encoding.
+               r = c.doGet(testGzipOn + "/direct").acceptEncoding("mycoding");
+               s = r.getResponseAsString();
+               assertEquals("test", s);
+               
assertTrue(r.getResponse().getHeaders("Content-Type")[0].getValue().contains("text/direct"));
 // Should get header set manually.
+               assertEquals(0, 
r.getResponse().getHeaders("Content-Encoding").length);                // 
Should not be set.
+
+               // res.getWriter() called....should bypass encoding.
+               r = c.doGet(testGzipOn + "/direct2").acceptEncoding("mycoding");
+               s = r.getResponseAsString();
+               assertEquals("test", s);
+               assertEquals(0, 
r.getResponse().getHeaders("Content-Encoding").length);                // 
Should not be set.
+
+               // res.getNegotiateWriter() called....should NOT bypass 
encoding.
+               r = c.doGet(testGzipOn + "/direct3").acceptEncoding("mycoding");
+               try {
+                       assertEquals("mycoding", 
r.getResponse().getHeaders("content-encoding")[0].getValue());
+               } catch (RestCallException e) {
+                       // OK - HttpClient doesn't know what mycoding is.
+                       // Newer versions of HttpClient ignore this condition.
+               }
+
+               // res.getNegotiateWriter() called but 
@RestMethod(encoders={})...should bypass encoding.
+               r = c.doGet(testGzipOn + "/direct4").acceptEncoding("mycoding");
+               s = r.getResponseAsString();
+               assertEquals("test", s);
+               assertEquals(0, 
r.getResponse().getHeaders("Content-Encoding").length);                // 
Should not be set.
+
+               c.closeQuietly(); // We want to close our client because we 
created the HttpClient in this method.
+       }
+}

Reply via email to