You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2017/06/02 00:00:30 UTC

[1/3] incubator-juneau git commit: Improvements to @Query/@FormData/@Header/@Path remoteable annotations.

Repository: incubator-juneau
Updated Branches:
  refs/heads/master 13f816fb6 -> 93aadae1d


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RequestBeanProxyTest.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RequestBeanProxyTest.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RequestBeanProxyTest.java
new file mode 100644
index 0000000..93403fb
--- /dev/null
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RequestBeanProxyTest.java
@@ -0,0 +1,1988 @@
+// ***************************************************************************************************************************
+// * 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.junit.Assert.*;
+
+import java.io.*;
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.plaintext.*;
+import org.apache.juneau.remoteable.*;
+import org.apache.juneau.rest.client.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.utils.*;
+import org.junit.*;
+import org.junit.runners.*;
+
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class RequestBeanProxyTest extends RestTestcase {
+
+	private <T> T getProxyPlainText(Class<T> t) {
+		RestClient rc = TestMicroservice.client(PlainTextSerializer.class, PlainTextParser.class).plainTextParts().build();
+		addClientToLifecycle(rc);
+		return rc.getRemoteableProxy(t, null);
+	}
+
+	private <T> T getProxyUon(Class<T> t) {
+		RestClient rc = TestMicroservice.client(PlainTextSerializer.class, PlainTextParser.class).build();
+		addClientToLifecycle(rc);
+		return rc.getRemoteableProxy(t, null);
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// @Query
+	//-------------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void a01_querySimpleValsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Query.class).querySimpleValsPlainText(new RequestBean_QuerySimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',e:'',g:'true',h:'123'}", r);
+	}
+
+	@Test
+	public void a02_querySimpleValsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Query.class).querySimpleValsUon(new RequestBean_QuerySimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',e:'',g:'\\'true\\'',h:'\\'123\\''}", r);
+	}
+
+	@Test
+	public void a03_querySimpleValsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Query.class).querySimpleValsX(new RequestBean_QuerySimpleVals());
+		assertEquals("{a:'xa1x',b:'xb1x',c:'xc1x',d:'xd1x',e:'xx',g:'xtruex',h:'x123x'}", r);
+	}
+
+	@Test
+	public void a04_queryMapsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Query.class).queryMapsPlainText(new RequestBean_QueryMaps());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void a05_queryMapsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Query.class).queryMapsUon(new RequestBean_QueryMaps());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'\\'true\\'',b2:'\\'123\\'',b3:'\\'null\\'',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void a06_queryMapsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Query.class).queryMapsX(new RequestBean_QueryMaps());
+		assertEquals("{a1:'xv1x',a2:'x123x',a4:'xx',b1:'xtruex',b2:'x123x',b3:'xnullx',c1:'xv1x',c2:'x123x',c4:'xx'}", r);
+	}
+
+	@Test
+	public void a07_queryNameValuePairsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Query.class).queryNameValuePairsPlainText(new RequestBean_QueryNameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void a08_queryNameValuePairsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Query.class).queryNameValuePairsUon(new RequestBean_QueryNameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void a09_queryNameValuePairsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Query.class).queryNameValuePairsX(new RequestBean_QueryNameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void a10_queryCharSequence() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Query.class).queryCharSequence(new RequestBean_QueryCharSequence());
+		assertEquals("{baz:'qux',foo:'bar'}", r);
+	}
+
+	@Test
+	public void a11_queryReader() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Query.class).queryReader(new RequestBean_QueryReader());
+		assertEquals("{baz:'qux',foo:'bar'}", r);
+	}
+
+	@Test
+	public void a12_queryCollectionsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Query.class).queryCollectionsPlainText(new RequestBean_QueryCollections());
+		assertEquals("{a:'foo,,true,123,null,true,123,null',b:'foo,,true,123,null,true,123,null',c:'foo||true|123|null|true|123|null',d:'',f:'foo,,true,123,null,true,123,null',g:'foo||true|123|null|true|123|null',h:''}", r);
+	}
+
+	@Test
+	public void a13_queryCollectionsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Query.class).queryCollectionsUon(new RequestBean_QueryCollections());
+		assertEquals("{a:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',b:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',c:'foo||true|123|null|true|123|null',d:'@()',f:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',g:'foo||true|123|null|true|123|null',h:'@()'}", r);
+	}
+
+	@Test
+	public void a14_queryCollectionsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Query.class).queryCollectionsX(new RequestBean_QueryCollections());
+		assertEquals("{a:'fooXXtrueX123XnullXtrueX123Xnull',b:'fooXXtrueX123XnullXtrueX123Xnull',c:'fooXXtrueX123XnullXtrueX123Xnull',d:'',f:'fooXXtrueX123XnullXtrueX123Xnull',g:'fooXXtrueX123XnullXtrueX123Xnull',h:''}", r);
+	}
+
+	@Remoteable(path="/testRequestBeanProxy")
+	public static interface RequestBeanProxy_Query {
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String querySimpleValsPlainText(@RequestBean RequestBean_QuerySimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String querySimpleValsUon(@RequestBean RequestBean_QuerySimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String querySimpleValsX(@RequestBean(serializer=XSerializer.class) RequestBean_QuerySimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryMapsPlainText(@RequestBean RequestBean_QueryMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryMapsUon(@RequestBean RequestBean_QueryMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryMapsX(@RequestBean(serializer=XSerializer.class) RequestBean_QueryMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryNameValuePairsPlainText(@RequestBean RequestBean_QueryNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryNameValuePairsUon(@RequestBean RequestBean_QueryNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryNameValuePairsX(@RequestBean(serializer=XSerializer.class) RequestBean_QueryNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryCharSequence(@RequestBean RequestBean_QueryCharSequence rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryReader(@RequestBean RequestBean_QueryReader rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryCollectionsPlainText(@RequestBean RequestBean_QueryCollections rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryCollectionsUon(@RequestBean RequestBean_QueryCollections rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryCollectionsX(@RequestBean(serializer=XSerializer.class) RequestBean_QueryCollections rb);
+	}
+
+	public static class RequestBean_QuerySimpleVals {
+
+		@Query
+		public String getA() {
+			return "a1";
+		}
+
+		@Query("b")
+		public String getX1() {
+			return "b1";
+		}
+
+		@Query(name="c")
+		public String getX2() {
+			return "c1";
+		}
+
+		@Query
+		@BeanProperty("d")
+		public String getX3() {
+			return "d1";
+		}
+
+		@Query("e")
+		public String getX4() {
+			return "";
+		}
+
+		@Query("f")
+		public String getX5() {
+			return null;
+		}
+
+		@Query("g")
+		public String getX6() {
+			return "true";
+		}
+
+		@Query("h")
+		public String getX7() {
+			return "123";
+		}
+	}
+
+	public static class RequestBean_QueryMaps {
+
+		@Query
+		public Map<String,Object> getA() {
+			return new AMap<String,Object>().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@Query("*")
+		public Map<String,Object> getB() {
+			return new AMap<String,Object>().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@Query(name="*")
+		public Map<String,Object> getC() {
+			return new AMap<String,Object>().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@Query("*")
+		public Map<String,Object> getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_QueryNameValuePairs {
+
+		@Query
+		public NameValuePairs getA() {
+			return new NameValuePairs().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@Query("*")
+		public NameValuePairs getB() {
+			return new NameValuePairs().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@Query(name="*")
+		public NameValuePairs getC() {
+			return new NameValuePairs().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@Query("*")
+		public NameValuePairs getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_QueryCharSequence {
+
+		@Query("*")
+		public StringBuilder getA() {
+			return new StringBuilder("foo=bar&baz=qux");
+		}
+	}
+
+	public static class RequestBean_QueryReader {
+
+		@Query("*")
+		public Reader getA() {
+			return new StringReader("foo=bar&baz=qux");
+		}
+	}
+
+	public static class RequestBean_QueryCollections {
+
+		@Query
+		public List<Object> getA() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@Query("b")
+		public List<Object> getX1() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@Query(name="c", serializer=ListSerializer.class)
+		public List<Object> getX2() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@Query("d")
+		public List<Object> getX3() {
+			return new AList<Object>();
+		}
+
+		@Query("e")
+		public List<Object> getX4() {
+			return null;
+		}
+
+		@Query("f")
+		public Object[] getX5() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@Query(name="g", serializer=ListSerializer.class)
+		public Object[] getX6() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@Query("h")
+		public Object[] getX7() {
+			return new Object[]{};
+		}
+
+		@Query("i")
+		public Object[] getX8() {
+			return null;
+		}
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// @QueryIfNE
+	//-------------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void b01_queryIfNESimpleValsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_QueryIfNE.class).querySimpleValsPlainText(new RequestBean_QueryIfNESimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',g:'true',h:'123'}", r);
+	}
+
+	@Test
+	public void b02_queryIfNESimpleValsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_QueryIfNE.class).querySimpleValsUon(new RequestBean_QueryIfNESimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',g:'\\'true\\'',h:'\\'123\\''}", r);
+	}
+
+	@Test
+	public void b03_queryIfNESimpleValsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_QueryIfNE.class).querySimpleValsX(new RequestBean_QueryIfNESimpleVals());
+		assertEquals("{a:'xa1x',b:'xb1x',c:'xc1x',d:'xd1x',g:'xtruex',h:'x123x'}", r);
+	}
+
+	@Test
+	public void b04_queryIfNEMapsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_QueryIfNE.class).queryMapsPlainText(new RequestBean_QueryIfNEMaps());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void b05_queryIfNEMapsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_QueryIfNE.class).queryMapsUon(new RequestBean_QueryIfNEMaps());
+		assertEquals("{a1:'v1',a2:'123',b1:'\\'true\\'',b2:'\\'123\\'',b3:'\\'null\\'',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void b06_queryIfNEMapsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_QueryIfNE.class).queryMapsX(new RequestBean_QueryIfNEMaps());
+		assertEquals("{a1:'xv1x',a2:'x123x',b1:'xtruex',b2:'x123x',b3:'xnullx',c1:'xv1x',c2:'x123x'}", r);
+	}
+
+	@Test
+	public void b07_queryIfNENameValuePairsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_QueryIfNE.class).queryNameValuePairsPlainText(new RequestBean_QueryIfNENameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void b08_queryIfNENameValuePairsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_QueryIfNE.class).queryNameValuePairsUon(new RequestBean_QueryIfNENameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void b09_queryIfNENameValuePairsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_QueryIfNE.class).queryNameValuePairsX(new RequestBean_QueryIfNENameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void b10_queryIfNECharSequence() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_QueryIfNE.class).queryCharSequence(new RequestBean_QueryIfNECharSequence());
+		assertEquals("{baz:'qux',foo:'bar'}", r);
+	}
+
+	@Test
+	public void b11_queryIfNEReader() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_QueryIfNE.class).queryReader(new RequestBean_QueryIfNEReader());
+		assertEquals("{baz:'qux',foo:'bar'}", r);
+	}
+
+	@Test
+	public void b12_queryIfNECollectionsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_QueryIfNE.class).queryCollectionsPlainText(new RequestBean_QueryIfNECollections());
+		assertEquals("{a:'foo,,true,123,null,true,123,null',b:'foo,,true,123,null,true,123,null',c:'foo||true|123|null|true|123|null',f:'foo,,true,123,null,true,123,null',g:'foo||true|123|null|true|123|null'}", r);
+	}
+
+	@Test
+	public void b13_queryIfNECollectionsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_QueryIfNE.class).queryCollectionsUon(new RequestBean_QueryIfNECollections());
+		assertEquals("{a:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',b:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',c:'foo||true|123|null|true|123|null',f:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',g:'foo||true|123|null|true|123|null'}", r);
+	}
+
+	@Test
+	public void b14_queryIfNECollectionsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_QueryIfNE.class).queryCollectionsX(new RequestBean_QueryIfNECollections());
+		assertEquals("{a:'fooXXtrueX123XnullXtrueX123Xnull',b:'fooXXtrueX123XnullXtrueX123Xnull',c:'fooXXtrueX123XnullXtrueX123Xnull',f:'fooXXtrueX123XnullXtrueX123Xnull',g:'fooXXtrueX123XnullXtrueX123Xnull'}", r);
+	}
+
+	@Remoteable(path="/testRequestBeanProxy")
+	public static interface RequestBeanProxy_QueryIfNE {
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String querySimpleValsPlainText(@RequestBean RequestBean_QueryIfNESimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String querySimpleValsUon(@RequestBean RequestBean_QueryIfNESimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String querySimpleValsX(@RequestBean(serializer=XSerializer.class) RequestBean_QueryIfNESimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryMapsPlainText(@RequestBean RequestBean_QueryIfNEMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryMapsUon(@RequestBean RequestBean_QueryIfNEMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryMapsX(@RequestBean(serializer=XSerializer.class) RequestBean_QueryIfNEMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryNameValuePairsPlainText(@RequestBean RequestBean_QueryIfNENameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryNameValuePairsUon(@RequestBean RequestBean_QueryIfNENameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryNameValuePairsX(@RequestBean(serializer=XSerializer.class) RequestBean_QueryIfNENameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryCharSequence(@RequestBean RequestBean_QueryIfNECharSequence rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryReader(@RequestBean RequestBean_QueryIfNEReader rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryCollectionsPlainText(@RequestBean RequestBean_QueryIfNECollections rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryCollectionsUon(@RequestBean RequestBean_QueryIfNECollections rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoQuery")
+		String queryCollectionsX(@RequestBean(serializer=XSerializer.class) RequestBean_QueryIfNECollections rb);
+	}
+
+	public static class RequestBean_QueryIfNESimpleVals {
+
+		@QueryIfNE
+		public String getA() {
+			return "a1";
+		}
+
+		@QueryIfNE("b")
+		public String getX1() {
+			return "b1";
+		}
+
+		@QueryIfNE(name="c")
+		public String getX2() {
+			return "c1";
+		}
+
+		@QueryIfNE
+		@BeanProperty("d")
+		public String getX3() {
+			return "d1";
+		}
+
+		@QueryIfNE("e")
+		public String getX4() {
+			return "";
+		}
+
+		@QueryIfNE("f")
+		public String getX5() {
+			return null;
+		}
+
+		@QueryIfNE("g")
+		public String getX6() {
+			return "true";
+		}
+
+		@QueryIfNE("h")
+		public String getX7() {
+			return "123";
+		}
+	}
+
+	public static class RequestBean_QueryIfNEMaps {
+
+		@QueryIfNE
+		public Map<String,Object> getA() {
+			return new AMap<String,Object>().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@QueryIfNE("*")
+		public Map<String,Object> getB() {
+			return new AMap<String,Object>().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@QueryIfNE(name="*")
+		public Map<String,Object> getC() {
+			return new AMap<String,Object>().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@QueryIfNE("*")
+		public Map<String,Object> getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_QueryIfNENameValuePairs {
+
+		@QueryIfNE
+		public NameValuePairs getA() {
+			return new NameValuePairs().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@QueryIfNE("*")
+		public NameValuePairs getB() {
+			return new NameValuePairs().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@QueryIfNE(name="*")
+		public NameValuePairs getC() {
+			return new NameValuePairs().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@QueryIfNE("*")
+		public NameValuePairs getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_QueryIfNECharSequence {
+
+		@QueryIfNE("*")
+		public StringBuilder getA() {
+			return new StringBuilder("foo=bar&baz=qux");
+		}
+	}
+
+	public static class RequestBean_QueryIfNEReader {
+
+		@QueryIfNE("*")
+		public Reader getA() {
+			return new StringReader("foo=bar&baz=qux");
+		}
+	}
+
+	public static class RequestBean_QueryIfNECollections {
+
+		@QueryIfNE
+		public List<Object> getA() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@QueryIfNE("b")
+		public List<Object> getX1() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@QueryIfNE(name="c", serializer=ListSerializer.class)
+		public List<Object> getX2() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@QueryIfNE("d")
+		public List<Object> getX3() {
+			return new AList<Object>();
+		}
+
+		@QueryIfNE("e")
+		public List<Object> getX4() {
+			return null;
+		}
+
+		@QueryIfNE("f")
+		public Object[] getX5() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@QueryIfNE(name="g", serializer=ListSerializer.class)
+		public Object[] getX6() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@QueryIfNE("h")
+		public Object[] getX7() {
+			return new Object[]{};
+		}
+
+		@QueryIfNE("i")
+		public Object[] getX8() {
+			return null;
+		}
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// @FormData
+	//-------------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void c01_formDataSimpleValsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_FormData.class).formDataSimpleValsPlainText(new RequestBean_FormDataSimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',e:'',g:'true',h:'123'}", r);
+	}
+
+	@Test
+	public void c02_formDataSimpleValsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormData.class).formDataSimpleValsUon(new RequestBean_FormDataSimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',e:'',g:'\\'true\\'',h:'\\'123\\''}", r);
+	}
+
+	@Test
+	public void c03_formDataSimpleValsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormData.class).formDataSimpleValsX(new RequestBean_FormDataSimpleVals());
+		assertEquals("{a:'xa1x',b:'xb1x',c:'xc1x',d:'xd1x',e:'xx',g:'xtruex',h:'x123x'}", r);
+	}
+
+	@Test
+	public void c04_formDataMapsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_FormData.class).formDataMapsPlainText(new RequestBean_FormDataMaps());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void c05_formDataMapsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormData.class).formDataMapsUon(new RequestBean_FormDataMaps());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'\\'true\\'',b2:'\\'123\\'',b3:'\\'null\\'',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void c06_formDataMapsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormData.class).formDataMapsX(new RequestBean_FormDataMaps());
+		assertEquals("{a1:'xv1x',a2:'x123x',a4:'xx',b1:'xtruex',b2:'x123x',b3:'xnullx',c1:'xv1x',c2:'x123x',c4:'xx'}", r);
+	}
+
+	@Test
+	public void c07_formDataNameValuePairsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_FormData.class).formDataNameValuePairsPlainText(new RequestBean_FormDataNameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void c08_formDataNameValuePairsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormData.class).formDataNameValuePairsUon(new RequestBean_FormDataNameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void c09_formDataNameValuePairsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormData.class).formDataNameValuePairsX(new RequestBean_FormDataNameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void c10_formDataCharSequence() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormData.class).formDataCharSequence(new RequestBean_FormDataCharSequence());
+		assertEquals("{baz:'qux',foo:'bar'}", r);
+	}
+
+	@Test
+	public void c11_formDataReader() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormData.class).formDataReader(new RequestBean_FormDataReader());
+		assertEquals("{baz:'qux',foo:'bar'}", r);
+	}
+
+	@Test
+	public void c12_formDataCollectionsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_FormData.class).formDataCollectionsPlainText(new RequestBean_FormDataCollections());
+		assertEquals("{a:'foo,,true,123,null,true,123,null',b:'foo,,true,123,null,true,123,null',c:'foo||true|123|null|true|123|null',d:'',f:'foo,,true,123,null,true,123,null',g:'foo||true|123|null|true|123|null',h:''}", r);
+	}
+
+	@Test
+	public void c13_formDataCollectionsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormData.class).formDataCollectionsUon(new RequestBean_FormDataCollections());
+		assertEquals("{a:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',b:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',c:'foo||true|123|null|true|123|null',d:'@()',f:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',g:'foo||true|123|null|true|123|null',h:'@()'}", r);
+	}
+
+	@Test
+	public void c14_formDataCollectionsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormData.class).formDataCollectionsX(new RequestBean_FormDataCollections());
+		assertEquals("{a:'fooXXtrueX123XnullXtrueX123Xnull',b:'fooXXtrueX123XnullXtrueX123Xnull',c:'fooXXtrueX123XnullXtrueX123Xnull',d:'',f:'fooXXtrueX123XnullXtrueX123Xnull',g:'fooXXtrueX123XnullXtrueX123Xnull',h:''}", r);
+	}
+
+	@Remoteable(path="/testRequestBeanProxy")
+	public static interface RequestBeanProxy_FormData {
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataSimpleValsPlainText(@RequestBean RequestBean_FormDataSimpleVals rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataSimpleValsUon(@RequestBean RequestBean_FormDataSimpleVals rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataSimpleValsX(@RequestBean(serializer=XSerializer.class) RequestBean_FormDataSimpleVals rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataMapsPlainText(@RequestBean RequestBean_FormDataMaps rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataMapsUon(@RequestBean RequestBean_FormDataMaps rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataMapsX(@RequestBean(serializer=XSerializer.class) RequestBean_FormDataMaps rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataNameValuePairsPlainText(@RequestBean RequestBean_FormDataNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataNameValuePairsUon(@RequestBean RequestBean_FormDataNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataNameValuePairsX(@RequestBean(serializer=XSerializer.class) RequestBean_FormDataNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataCharSequence(@RequestBean RequestBean_FormDataCharSequence rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataReader(@RequestBean RequestBean_FormDataReader rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataCollectionsPlainText(@RequestBean RequestBean_FormDataCollections rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataCollectionsUon(@RequestBean RequestBean_FormDataCollections rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataCollectionsX(@RequestBean(serializer=XSerializer.class) RequestBean_FormDataCollections rb);
+	}
+
+	public static class RequestBean_FormDataSimpleVals {
+
+		@FormData
+		public String getA() {
+			return "a1";
+		}
+
+		@FormData("b")
+		public String getX1() {
+			return "b1";
+		}
+
+		@FormData(name="c")
+		public String getX2() {
+			return "c1";
+		}
+
+		@FormData
+		@BeanProperty("d")
+		public String getX3() {
+			return "d1";
+		}
+
+		@FormData("e")
+		public String getX4() {
+			return "";
+		}
+
+		@FormData("f")
+		public String getX5() {
+			return null;
+		}
+
+		@FormData("g")
+		public String getX6() {
+			return "true";
+		}
+
+		@FormData("h")
+		public String getX7() {
+			return "123";
+		}
+	}
+
+	public static class RequestBean_FormDataMaps {
+
+		@FormData
+		public Map<String,Object> getA() {
+			return new AMap<String,Object>().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@FormData("*")
+		public Map<String,Object> getB() {
+			return new AMap<String,Object>().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@FormData(name="*")
+		public Map<String,Object> getC() {
+			return new AMap<String,Object>().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@FormData("*")
+		public Map<String,Object> getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_FormDataNameValuePairs {
+
+		@FormData
+		public NameValuePairs getA() {
+			return new NameValuePairs().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@FormData("*")
+		public NameValuePairs getB() {
+			return new NameValuePairs().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@FormData(name="*")
+		public NameValuePairs getC() {
+			return new NameValuePairs().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@FormData("*")
+		public NameValuePairs getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_FormDataCharSequence {
+
+		@FormData("*")
+		public StringBuilder getA() {
+			return new StringBuilder("foo=bar&baz=qux");
+		}
+	}
+
+	public static class RequestBean_FormDataReader {
+
+		@FormData("*")
+		public Reader getA() {
+			return new StringReader("foo=bar&baz=qux");
+		}
+	}
+
+	public static class RequestBean_FormDataCollections {
+
+		@FormData
+		public List<Object> getA() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@FormData("b")
+		public List<Object> getX1() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@FormData(name="c", serializer=ListSerializer.class)
+		public List<Object> getX2() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@FormData("d")
+		public List<Object> getX3() {
+			return new AList<Object>();
+		}
+
+		@FormData("e")
+		public List<Object> getX4() {
+			return null;
+		}
+
+		@FormData("f")
+		public Object[] getX5() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@FormData(name="g", serializer=ListSerializer.class)
+		public Object[] getX6() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@FormData("h")
+		public Object[] getX7() {
+			return new Object[]{};
+		}
+
+		@FormData("i")
+		public Object[] getX8() {
+			return null;
+		}
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// @FormDataIfNE
+	//-------------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void d01_formDataIfNESimpleValsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_FormDataIfNE.class).formDataSimpleValsPlainText(new RequestBean_FormDataIfNESimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',g:'true',h:'123'}", r);
+	}
+
+	@Test
+	public void d02_formDataIfNESimpleValsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormDataIfNE.class).formDataSimpleValsUon(new RequestBean_FormDataIfNESimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',g:'\\'true\\'',h:'\\'123\\''}", r);
+	}
+
+	@Test
+	public void d03_formDataIfNESimpleValsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormDataIfNE.class).formDataSimpleValsX(new RequestBean_FormDataIfNESimpleVals());
+		assertEquals("{a:'xa1x',b:'xb1x',c:'xc1x',d:'xd1x',g:'xtruex',h:'x123x'}", r);
+	}
+
+	@Test
+	public void d04_formDataIfNEMapsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_FormDataIfNE.class).formDataMapsPlainText(new RequestBean_FormDataIfNEMaps());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void d05_formDataIfNEMapsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormDataIfNE.class).formDataMapsUon(new RequestBean_FormDataIfNEMaps());
+		assertEquals("{a1:'v1',a2:'123',b1:'\\'true\\'',b2:'\\'123\\'',b3:'\\'null\\'',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void d06_formDataIfNEMapsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormDataIfNE.class).formDataMapsX(new RequestBean_FormDataIfNEMaps());
+		assertEquals("{a1:'xv1x',a2:'x123x',b1:'xtruex',b2:'x123x',b3:'xnullx',c1:'xv1x',c2:'x123x'}", r);
+	}
+
+	@Test
+	public void d07_formDataIfNENameValuePairsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_FormDataIfNE.class).formDataNameValuePairsPlainText(new RequestBean_FormDataIfNENameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void d08_formDataIfNENameValuePairsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormDataIfNE.class).formDataNameValuePairsUon(new RequestBean_FormDataIfNENameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void d09_formDataIfNENameValuePairsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormDataIfNE.class).formDataNameValuePairsX(new RequestBean_FormDataIfNENameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void d10_formDataIfNECharSequence() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormDataIfNE.class).formDataCharSequence(new RequestBean_FormDataIfNECharSequence());
+		assertEquals("{baz:'qux',foo:'bar'}", r);
+	}
+
+	@Test
+	public void d11_formDataIfNEReader() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormDataIfNE.class).formDataReader(new RequestBean_FormDataIfNEReader());
+		assertEquals("{baz:'qux',foo:'bar'}", r);
+	}
+
+	@Test
+	public void d12_formDataIfNECollectionsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_FormDataIfNE.class).formDataCollectionsPlainText(new RequestBean_FormDataIfNECollections());
+		assertEquals("{a:'foo,,true,123,null,true,123,null',b:'foo,,true,123,null,true,123,null',c:'foo||true|123|null|true|123|null',f:'foo,,true,123,null,true,123,null',g:'foo||true|123|null|true|123|null'}", r);
+	}
+
+	@Test
+	public void d13_formDataIfNECollectionsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormDataIfNE.class).formDataCollectionsUon(new RequestBean_FormDataIfNECollections());
+		assertEquals("{a:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',b:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',c:'foo||true|123|null|true|123|null',f:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',g:'foo||true|123|null|true|123|null'}", r);
+	}
+
+	@Test
+	public void d14_formDataIfNECollectionsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_FormDataIfNE.class).formDataCollectionsX(new RequestBean_FormDataIfNECollections());
+		assertEquals("{a:'fooXXtrueX123XnullXtrueX123Xnull',b:'fooXXtrueX123XnullXtrueX123Xnull',c:'fooXXtrueX123XnullXtrueX123Xnull',f:'fooXXtrueX123XnullXtrueX123Xnull',g:'fooXXtrueX123XnullXtrueX123Xnull'}", r);
+	}
+
+	@Remoteable(path="/testRequestBeanProxy")
+	public static interface RequestBeanProxy_FormDataIfNE {
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataSimpleValsPlainText(@RequestBean RequestBean_FormDataIfNESimpleVals rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataSimpleValsUon(@RequestBean RequestBean_FormDataIfNESimpleVals rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataSimpleValsX(@RequestBean(serializer=XSerializer.class) RequestBean_FormDataIfNESimpleVals rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataMapsPlainText(@RequestBean RequestBean_FormDataIfNEMaps rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataMapsUon(@RequestBean RequestBean_FormDataIfNEMaps rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataMapsX(@RequestBean(serializer=XSerializer.class) RequestBean_FormDataIfNEMaps rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataNameValuePairsPlainText(@RequestBean RequestBean_FormDataIfNENameValuePairs rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataNameValuePairsUon(@RequestBean RequestBean_FormDataIfNENameValuePairs rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataNameValuePairsX(@RequestBean(serializer=XSerializer.class) RequestBean_FormDataIfNENameValuePairs rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataCharSequence(@RequestBean RequestBean_FormDataIfNECharSequence rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataReader(@RequestBean RequestBean_FormDataIfNEReader rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataCollectionsPlainText(@RequestBean RequestBean_FormDataIfNECollections rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataCollectionsUon(@RequestBean RequestBean_FormDataIfNECollections rb);
+
+		@RemoteMethod(httpMethod="POST", path="/echoFormData")
+		String formDataCollectionsX(@RequestBean(serializer=XSerializer.class) RequestBean_FormDataIfNECollections rb);
+	}
+
+	public static class RequestBean_FormDataIfNESimpleVals {
+
+		@FormDataIfNE
+		public String getA() {
+			return "a1";
+		}
+
+		@FormDataIfNE("b")
+		public String getX1() {
+			return "b1";
+		}
+
+		@FormDataIfNE(name="c")
+		public String getX2() {
+			return "c1";
+		}
+
+		@FormDataIfNE
+		@BeanProperty("d")
+		public String getX3() {
+			return "d1";
+		}
+
+		@FormDataIfNE("e")
+		public String getX4() {
+			return "";
+		}
+
+		@FormDataIfNE("f")
+		public String getX5() {
+			return null;
+		}
+
+		@FormDataIfNE("g")
+		public String getX6() {
+			return "true";
+		}
+
+		@FormDataIfNE("h")
+		public String getX7() {
+			return "123";
+		}
+	}
+
+	public static class RequestBean_FormDataIfNEMaps {
+
+		@FormDataIfNE
+		public Map<String,Object> getA() {
+			return new AMap<String,Object>().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@FormDataIfNE("*")
+		public Map<String,Object> getB() {
+			return new AMap<String,Object>().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@FormDataIfNE(name="*")
+		public Map<String,Object> getC() {
+			return new AMap<String,Object>().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@FormDataIfNE("*")
+		public Map<String,Object> getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_FormDataIfNENameValuePairs {
+
+		@FormDataIfNE
+		public NameValuePairs getA() {
+			return new NameValuePairs().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@FormDataIfNE("*")
+		public NameValuePairs getB() {
+			return new NameValuePairs().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@FormDataIfNE(name="*")
+		public NameValuePairs getC() {
+			return new NameValuePairs().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@FormDataIfNE("*")
+		public NameValuePairs getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_FormDataIfNECharSequence {
+
+		@FormDataIfNE("*")
+		public StringBuilder getA() {
+			return new StringBuilder("foo=bar&baz=qux");
+		}
+	}
+
+	public static class RequestBean_FormDataIfNEReader {
+
+		@FormDataIfNE("*")
+		public Reader getA() {
+			return new StringReader("foo=bar&baz=qux");
+		}
+	}
+
+	public static class RequestBean_FormDataIfNECollections {
+
+		@FormDataIfNE
+		public List<Object> getA() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@FormDataIfNE("b")
+		public List<Object> getX1() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@FormDataIfNE(name="c", serializer=ListSerializer.class)
+		public List<Object> getX2() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@FormDataIfNE("d")
+		public List<Object> getX3() {
+			return new AList<Object>();
+		}
+
+		@FormDataIfNE("e")
+		public List<Object> getX4() {
+			return null;
+		}
+
+		@FormDataIfNE("f")
+		public Object[] getX5() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@FormDataIfNE(name="g", serializer=ListSerializer.class)
+		public Object[] getX6() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@FormDataIfNE("h")
+		public Object[] getX7() {
+			return new Object[]{};
+		}
+
+		@FormDataIfNE("i")
+		public Object[] getX8() {
+			return null;
+		}
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// @Header
+	//-------------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void e01_headerSimpleValsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Header.class).headerSimpleValsPlainText(new RequestBean_HeaderSimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',e:'',g:'true',h:'123'}", r);
+	}
+
+	@Test
+	public void e02_headerSimpleValsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Header.class).headerSimpleValsUon(new RequestBean_HeaderSimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',e:'',g:'true',h:'123'}", r);
+	}
+
+	@Test
+	public void e03_headerSimpleValsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Header.class).headerSimpleValsX(new RequestBean_HeaderSimpleVals());
+		assertEquals("{a:'xa1x',b:'xb1x',c:'xc1x',d:'xd1x',e:'xx',g:'xtruex',h:'x123x'}", r);
+	}
+
+	@Test
+	public void e04_headerMapsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Header.class).headerMapsPlainText(new RequestBean_HeaderMaps());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void e05_headerMapsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Header.class).headerMapsUon(new RequestBean_HeaderMaps());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void e06_headerMapsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Header.class).headerMapsX(new RequestBean_HeaderMaps());
+		assertEquals("{a1:'xv1x',a2:'x123x',a4:'xx',b1:'xtruex',b2:'x123x',b3:'xnullx',c1:'xv1x',c2:'x123x',c4:'xx'}", r);
+	}
+
+	@Test
+	public void e07_headerNameValuePairsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Header.class).headerNameValuePairsPlainText(new RequestBean_HeaderNameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void e08_headerNameValuePairsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Header.class).headerNameValuePairsUon(new RequestBean_HeaderNameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void e09_headerNameValuePairsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Header.class).headerNameValuePairsX(new RequestBean_HeaderNameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',a4:'',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123',c4:''}", r);
+	}
+
+	@Test
+	public void e10_headerCollectionsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Header.class).headerCollectionsPlainText(new RequestBean_HeaderCollections());
+		assertEquals("{a:'foo,,true,123,null,true,123,null',b:'foo,,true,123,null,true,123,null',c:'foo||true|123|null|true|123|null',d:'',f:'foo,,true,123,null,true,123,null',g:'foo||true|123|null|true|123|null',h:''}", r);
+	}
+
+	@Test
+	public void e11_headerCollectionsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Header.class).headerCollectionsUon(new RequestBean_HeaderCollections());
+		assertEquals("{a:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',b:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',c:'foo||true|123|null|true|123|null',d:'@()',f:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',g:'foo||true|123|null|true|123|null',h:'@()'}", r);
+	}
+
+	@Test
+	public void e12_headerCollectionsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Header.class).headerCollectionsX(new RequestBean_HeaderCollections());
+		assertEquals("{a:'fooXXtrueX123XnullXtrueX123Xnull',b:'fooXXtrueX123XnullXtrueX123Xnull',c:'fooXXtrueX123XnullXtrueX123Xnull',d:'',f:'fooXXtrueX123XnullXtrueX123Xnull',g:'fooXXtrueX123XnullXtrueX123Xnull',h:''}", r);
+	}
+
+	@Remoteable(path="/testRequestBeanProxy")
+	public static interface RequestBeanProxy_Header {
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerSimpleValsPlainText(@RequestBean RequestBean_HeaderSimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerSimpleValsUon(@RequestBean RequestBean_HeaderSimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerSimpleValsX(@RequestBean(serializer=XSerializer.class) RequestBean_HeaderSimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerMapsPlainText(@RequestBean RequestBean_HeaderMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerMapsUon(@RequestBean RequestBean_HeaderMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerMapsX(@RequestBean(serializer=XSerializer.class) RequestBean_HeaderMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerNameValuePairsPlainText(@RequestBean RequestBean_HeaderNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerNameValuePairsUon(@RequestBean RequestBean_HeaderNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerNameValuePairsX(@RequestBean(serializer=XSerializer.class) RequestBean_HeaderNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerCollectionsPlainText(@RequestBean RequestBean_HeaderCollections rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerCollectionsUon(@RequestBean RequestBean_HeaderCollections rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerCollectionsX(@RequestBean(serializer=XSerializer.class) RequestBean_HeaderCollections rb);
+	}
+
+	public static class RequestBean_HeaderSimpleVals {
+
+		@Header
+		public String getA() {
+			return "a1";
+		}
+
+		@Header("b")
+		public String getX1() {
+			return "b1";
+		}
+
+		@Header(name="c")
+		public String getX2() {
+			return "c1";
+		}
+
+		@Header
+		@BeanProperty("d")
+		public String getX3() {
+			return "d1";
+		}
+
+		@Header("e")
+		public String getX4() {
+			return "";
+		}
+
+		@Header("f")
+		public String getX5() {
+			return null;
+		}
+
+		@Header("g")
+		public String getX6() {
+			return "true";
+		}
+
+		@Header("h")
+		public String getX7() {
+			return "123";
+		}
+	}
+
+	public static class RequestBean_HeaderMaps {
+
+		@Header
+		public Map<String,Object> getA() {
+			return new AMap<String,Object>().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@Header("*")
+		public Map<String,Object> getB() {
+			return new AMap<String,Object>().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@Header(name="*")
+		public Map<String,Object> getC() {
+			return new AMap<String,Object>().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@Header("*")
+		public Map<String,Object> getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_HeaderNameValuePairs {
+
+		@Header
+		public NameValuePairs getA() {
+			return new NameValuePairs().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@Header("*")
+		public NameValuePairs getB() {
+			return new NameValuePairs().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@Header(name="*")
+		public NameValuePairs getC() {
+			return new NameValuePairs().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@Header("*")
+		public NameValuePairs getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_HeaderCollections {
+
+		@Header
+		public List<Object> getA() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@Header("b")
+		public List<Object> getX1() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@Header(name="c", serializer=ListSerializer.class)
+		public List<Object> getX2() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@Header("d")
+		public List<Object> getX3() {
+			return new AList<Object>();
+		}
+
+		@Header("e")
+		public List<Object> getX4() {
+			return null;
+		}
+
+		@Header("f")
+		public Object[] getX5() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@Header(name="g", serializer=ListSerializer.class)
+		public Object[] getX6() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@Header("h")
+		public Object[] getX7() {
+			return new Object[]{};
+		}
+
+		@Header("i")
+		public Object[] getX8() {
+			return null;
+		}
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// @HeaderIfNE
+	//-------------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void f01_headerIfNESimpleValsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_HeaderIfNE.class).headerSimpleValsPlainText(new RequestBean_HeaderIfNESimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',g:'true',h:'123'}", r);
+	}
+
+	@Test
+	public void f02_headerIfNESimpleValsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_HeaderIfNE.class).headerSimpleValsUon(new RequestBean_HeaderIfNESimpleVals());
+		assertEquals("{a:'a1',b:'b1',c:'c1',d:'d1',g:'true',h:'123'}", r);
+	}
+
+	@Test
+	public void f03_headerIfNESimpleValsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_HeaderIfNE.class).headerSimpleValsX(new RequestBean_HeaderIfNESimpleVals());
+		assertEquals("{a:'xa1x',b:'xb1x',c:'xc1x',d:'xd1x',g:'xtruex',h:'x123x'}", r);
+	}
+
+	@Test
+	public void f04_headerIfNEMapsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_HeaderIfNE.class).headerMapsPlainText(new RequestBean_HeaderIfNEMaps());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void f05_headerIfNEMapsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_HeaderIfNE.class).headerMapsUon(new RequestBean_HeaderIfNEMaps());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void f06_headerIfNEMapsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_HeaderIfNE.class).headerMapsX(new RequestBean_HeaderIfNEMaps());
+		assertEquals("{a1:'xv1x',a2:'x123x',b1:'xtruex',b2:'x123x',b3:'xnullx',c1:'xv1x',c2:'x123x'}", r);
+	}
+
+	@Test
+	public void f07_headerIfNENameValuePairsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_HeaderIfNE.class).headerNameValuePairsPlainText(new RequestBean_HeaderIfNENameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void f08_headerIfNENameValuePairsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_HeaderIfNE.class).headerNameValuePairsUon(new RequestBean_HeaderIfNENameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void f09_headerIfNENameValuePairsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_HeaderIfNE.class).headerNameValuePairsX(new RequestBean_HeaderIfNENameValuePairs());
+		assertEquals("{a1:'v1',a2:'123',b1:'true',b2:'123',b3:'null',c1:'v1',c2:'123'}", r);
+	}
+
+	@Test
+	public void f10_headerIfNECollectionsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_HeaderIfNE.class).headerCollectionsPlainText(new RequestBean_HeaderIfNECollections());
+		assertEquals("{a:'foo,,true,123,null,true,123,null',b:'foo,,true,123,null,true,123,null',c:'foo||true|123|null|true|123|null',f:'foo,,true,123,null,true,123,null',g:'foo||true|123|null|true|123|null'}", r);
+	}
+
+	@Test
+	public void f11_headerIfNECollectionsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_HeaderIfNE.class).headerCollectionsUon(new RequestBean_HeaderIfNECollections());
+		assertEquals("{a:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',b:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',c:'foo||true|123|null|true|123|null',f:'@(foo,\\'\\',\\'true\\',\\'123\\',\\'null\\',true,123,null)',g:'foo||true|123|null|true|123|null'}", r);
+	}
+
+	@Test
+	public void f12_headerIfNECollectionsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_HeaderIfNE.class).headerCollectionsX(new RequestBean_HeaderIfNECollections());
+		assertEquals("{a:'fooXXtrueX123XnullXtrueX123Xnull',b:'fooXXtrueX123XnullXtrueX123Xnull',c:'fooXXtrueX123XnullXtrueX123Xnull',f:'fooXXtrueX123XnullXtrueX123Xnull',g:'fooXXtrueX123XnullXtrueX123Xnull'}", r);
+	}
+
+	@Remoteable(path="/testRequestBeanProxy")
+	public static interface RequestBeanProxy_HeaderIfNE {
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerSimpleValsPlainText(@RequestBean RequestBean_HeaderIfNESimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerSimpleValsUon(@RequestBean RequestBean_HeaderIfNESimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerSimpleValsX(@RequestBean(serializer=XSerializer.class) RequestBean_HeaderIfNESimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerMapsPlainText(@RequestBean RequestBean_HeaderIfNEMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerMapsUon(@RequestBean RequestBean_HeaderIfNEMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerMapsX(@RequestBean(serializer=XSerializer.class) RequestBean_HeaderIfNEMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerNameValuePairsPlainText(@RequestBean RequestBean_HeaderIfNENameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerNameValuePairsUon(@RequestBean RequestBean_HeaderIfNENameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerNameValuePairsX(@RequestBean(serializer=XSerializer.class) RequestBean_HeaderIfNENameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerCollectionsPlainText(@RequestBean RequestBean_HeaderIfNECollections rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerCollectionsUon(@RequestBean RequestBean_HeaderIfNECollections rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoHeaders")
+		String headerCollectionsX(@RequestBean(serializer=XSerializer.class) RequestBean_HeaderIfNECollections rb);
+	}
+
+	public static class RequestBean_HeaderIfNESimpleVals {
+
+		@HeaderIfNE
+		public String getA() {
+			return "a1";
+		}
+
+		@HeaderIfNE("b")
+		public String getX1() {
+			return "b1";
+		}
+
+		@HeaderIfNE(name="c")
+		public String getX2() {
+			return "c1";
+		}
+
+		@HeaderIfNE
+		@BeanProperty("d")
+		public String getX3() {
+			return "d1";
+		}
+
+		@HeaderIfNE("e")
+		public String getX4() {
+			return "";
+		}
+
+		@HeaderIfNE("f")
+		public String getX5() {
+			return null;
+		}
+
+		@HeaderIfNE("g")
+		public String getX6() {
+			return "true";
+		}
+
+		@HeaderIfNE("h")
+		public String getX7() {
+			return "123";
+		}
+	}
+
+	public static class RequestBean_HeaderIfNEMaps {
+
+		@HeaderIfNE
+		public Map<String,Object> getA() {
+			return new AMap<String,Object>().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@HeaderIfNE("*")
+		public Map<String,Object> getB() {
+			return new AMap<String,Object>().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@HeaderIfNE(name="*")
+		public Map<String,Object> getC() {
+			return new AMap<String,Object>().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@HeaderIfNE("*")
+		public Map<String,Object> getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_HeaderIfNENameValuePairs {
+
+		@HeaderIfNE
+		public NameValuePairs getA() {
+			return new NameValuePairs().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@HeaderIfNE("*")
+		public NameValuePairs getB() {
+			return new NameValuePairs().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@HeaderIfNE(name="*")
+		public NameValuePairs getC() {
+			return new NameValuePairs().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@HeaderIfNE("*")
+		public NameValuePairs getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_HeaderIfNECollections {
+
+		@HeaderIfNE
+		public List<Object> getA() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@HeaderIfNE("b")
+		public List<Object> getX1() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@HeaderIfNE(name="c", serializer=ListSerializer.class)
+		public List<Object> getX2() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@HeaderIfNE("d")
+		public List<Object> getX3() {
+			return new AList<Object>();
+		}
+
+		@HeaderIfNE("e")
+		public List<Object> getX4() {
+			return null;
+		}
+
+		@HeaderIfNE("f")
+		public Object[] getX5() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@HeaderIfNE(name="g", serializer=ListSerializer.class)
+		public Object[] getX6() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@HeaderIfNE("h")
+		public Object[] getX7() {
+			return new Object[]{};
+		}
+
+		@HeaderIfNE("i")
+		public Object[] getX8() {
+			return null;
+		}
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// @Path
+	//-------------------------------------------------------------------------------------------------------------------
+
+	@Test
+	public void g01_pathSimpleValsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Path.class).pathSimpleValsPlainText(new RequestBean_PathSimpleVals());
+		assertEquals("a1/b1/c1/d1//null/true/123", r);
+	}
+
+	@Test
+	public void g02_pathSimpleValsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Path.class).pathSimpleValsUon(new RequestBean_PathSimpleVals());
+		assertEquals("a1/b1/c1/d1//null/'true'/'123'", r);
+	}
+
+	@Test
+	public void g03_pathSimpleValsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Path.class).pathSimpleValsX(new RequestBean_PathSimpleVals());
+		assertEquals("xa1x/xb1x/xc1x/xd1x/xx/NULL/xtruex/x123x", r);
+	}
+
+	@Test
+	public void g04_pathMapsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Path.class).pathMapsPlainText(new RequestBean_PathMaps());
+		assertEquals("v1/123/null//true/123/null/v1/123/null/", r);
+	}
+
+	@Test
+	public void g05_pathMapsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Path.class).pathMapsUon(new RequestBean_PathMaps());
+		assertEquals("v1/123/null//'true'/'123'/'null'/v1/123/null/", r);
+	}
+
+	@Test
+	public void g06_pathMapsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Path.class).pathMapsX(new RequestBean_PathMaps());
+		assertEquals("xv1x/x123x/NULL/xx/xtruex/x123x/xnullx/xv1x/x123x/NULL/xx", r);
+	}
+
+	@Test
+	public void g07_pathNameValuePairsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Path.class).pathNameValuePairsPlainText(new RequestBean_PathNameValuePairs());
+		assertEquals("plainText/v1/123/null//true/123/null/v1/123/null/", r);
+	}
+
+	@Test
+	public void g08_pathNameValuePairsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Path.class).pathNameValuePairsUon(new RequestBean_PathNameValuePairs());
+		assertEquals("v1/'123'/null//'true'/'123'/'null'/v1/'123'/null/", r);
+	}
+
+	@Test
+	public void g09_pathNameValuePairsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Path.class).pathNameValuePairsX(new RequestBean_PathNameValuePairs());
+		assertEquals("xv1x/x123x/NULL/xx/xtruex/x123x/xnullx/xv1x/x123x/NULL/xx", r);
+	}
+
+	@Test
+	public void g10_pathCollectionsPlainText() throws Exception {
+		String r = getProxyPlainText(RequestBeanProxy_Path.class).pathCollectionsPlainText(new RequestBean_PathCollections());
+		assertEquals("foo,,true,123,null,true,123,null/foo,,true,123,null,true,123,null/foo||true|123|null|true|123|null//null/foo,,true,123,null,true,123,null/foo||true|123|null|true|123|null//null", r);
+	}
+
+	@Test
+	public void g11_pathCollectionsUon() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Path.class).pathCollectionsUon(new RequestBean_PathCollections());
+		assertEquals("@(foo,'','true','123','null',true,123,null)/@(foo,'','true','123','null',true,123,null)/foo||true|123|null|true|123|null/@()/null/@(foo,'','true','123','null',true,123,null)/foo||true|123|null|true|123|null/@()/null", r);
+	}
+
+	@Test
+	public void g12_pathCollectionsX() throws Exception {
+		String r = getProxyUon(RequestBeanProxy_Path.class).pathCollectionsX(new RequestBean_PathCollections());
+		assertEquals("fooXXtrueX123XnullXtrueX123Xnull/fooXXtrueX123XnullXtrueX123Xnull/fooXXtrueX123XnullXtrueX123Xnull//NULL/fooXXtrueX123XnullXtrueX123Xnull/fooXXtrueX123XnullXtrueX123Xnull//NULL", r);
+	}
+
+	@Remoteable(path="/testRequestBeanProxy")
+	public static interface RequestBeanProxy_Path {
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/{a}/{b}/{c}/{d}/{e}/{f}/{g}/{h}")
+		String pathSimpleValsPlainText(@RequestBean RequestBean_PathSimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/{a}/{b}/{c}/{d}/{e}/{f}/{g}/{h}")
+		String pathSimpleValsUon(@RequestBean RequestBean_PathSimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/{a}/{b}/{c}/{d}/{e}/{f}/{g}/{h}")
+		String pathSimpleValsX(@RequestBean(serializer=XSerializer.class) RequestBean_PathSimpleVals rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/{a1}/{a2}/{a3}/{a4}/{b1}/{b2}/{b3}/{c1}/{c2}/{c3}/{c4}")
+		String pathMapsPlainText(@RequestBean RequestBean_PathMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/{a1}/{a2}/{a3}/{a4}/{b1}/{b2}/{b3}/{c1}/{c2}/{c3}/{c4}")
+		String pathMapsUon(@RequestBean RequestBean_PathMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/{a1}/{a2}/{a3}/{a4}/{b1}/{b2}/{b3}/{c1}/{c2}/{c3}/{c4}")
+		String pathMapsX(@RequestBean(serializer=XSerializer.class) RequestBean_PathMaps rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/plainText/{a1}/{a2}/{a3}/{a4}/{b1}/{b2}/{b3}/{c1}/{c2}/{c3}/{c4}")
+		String pathNameValuePairsPlainText(@RequestBean RequestBean_PathNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/{a1}/{a2}/{a3}/{a4}/{b1}/{b2}/{b3}/{c1}/{c2}/{c3}/{c4}")
+		String pathNameValuePairsUon(@RequestBean RequestBean_PathNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/{a1}/{a2}/{a3}/{a4}/{b1}/{b2}/{b3}/{c1}/{c2}/{c3}/{c4}")
+		String pathNameValuePairsX(@RequestBean(serializer=XSerializer.class) RequestBean_PathNameValuePairs rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/{a}/{b}/{c}/{d}/{e}/{f}/{g}/{h}/{i}")
+		String pathCollectionsPlainText(@RequestBean RequestBean_PathCollections rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/{a}/{b}/{c}/{d}/{e}/{f}/{g}/{h}/{i}")
+		String pathCollectionsUon(@RequestBean RequestBean_PathCollections rb);
+
+		@RemoteMethod(httpMethod="GET", path="/echoPath/{a}/{b}/{c}/{d}/{e}/{f}/{g}/{h}/{i}")
+		String pathCollectionsX(@RequestBean(serializer=XSerializer.class) RequestBean_PathCollections rb);
+	}
+
+	public static class RequestBean_PathSimpleVals {
+
+		@Path
+		public String getA() {
+			return "a1";
+		}
+
+		@Path("b")
+		public String getX1() {
+			return "b1";
+		}
+
+		@Path(name="c")
+		public String getX2() {
+			return "c1";
+		}
+
+		@Path
+		@BeanProperty("d")
+		public String getX3() {
+			return "d1";
+		}
+
+		@Path("e")
+		public String getX4() {
+			return "";
+		}
+
+		@Path("f")
+		public String getX5() {
+			return null;
+		}
+
+		@Path("g")
+		public String getX6() {
+			return "true";
+		}
+
+		@Path("h")
+		public String getX7() {
+			return "123";
+		}
+	}
+
+	public static class RequestBean_PathMaps {
+
+		@Path
+		public Map<String,Object> getA() {
+			return new AMap<String,Object>().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@Path("*")
+		public Map<String,Object> getB() {
+			return new AMap<String,Object>().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@Path(name="*")
+		public Map<String,Object> getC() {
+			return new AMap<String,Object>().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@Path("*")
+		public Map<String,Object> getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_PathNameValuePairs {
+
+		@Path
+		public NameValuePairs getA() {
+			return new NameValuePairs().append("a1","v1").append("a2", 123).append("a3", null).append("a4", "");
+		}
+
+		@Path("*")
+		public NameValuePairs getB() {
+			return new NameValuePairs().append("b1","true").append("b2", "123").append("b3", "null");
+		}
+
+		@Path(name="*")
+		public NameValuePairs getC() {
+			return new NameValuePairs().append("c1","v1").append("c2", 123).append("c3", null).append("c4", "");
+		}
+
+		@Path("*")
+		public NameValuePairs getD() {
+			return null;
+		}
+	}
+
+	public static class RequestBean_PathCollections {
+
+		@Path
+		public List<Object> getA() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@Path("b")
+		public List<Object> getX1() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@Path(name="c", serializer=ListSerializer.class)
+		public List<Object> getX2() {
+			return new AList<Object>().append("foo").append("").append("true").append("123").append("null").append(true).append(123).append(null);
+		}
+
+		@Path("d")
+		public List<Object> getX3() {
+			return new AList<Object>();
+		}
+
+		@Path("e")
+		public List<Object> getX4() {
+			return null;
+		}
+
+		@Path("f")
+		public Object[] getX5() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@Path(name="g", serializer=ListSerializer.class)
+		public Object[] getX6() {
+			return new Object[]{"foo", "", "true", "123", "null", true, 123, null};
+		}
+
+		@Path("h")
+		public Object[] getX7() {
+			return new Object[]{};
+		}
+
+		@Path("i")
+		public Object[] getX8() {
+			return null;
+		}
+	}
+
+	//-------------------------------------------------------------------------------------------------------------------
+	// Support classes
+	//-------------------------------------------------------------------------------------------------------------------
+
+	public static class XSerializer implements PartSerializer {
+		@Override
+		public String serialize(PartType type, Object value) {
+			if (value == null)
+				return "NULL";
+			if (value instanceof Collection)
+				return StringUtils.join((Collection<?>)value, "X");
+			if (ArrayUtils.isArray(value))
+				return StringUtils.join(ArrayUtils.toList(value, Object.class), "X");
+			return "x" + value + "x";
+		}
+	}
+
+	public static class ListSerializer implements PartSerializer {
+		@Override
+		public String serialize(PartType type, Object value) {
+			if (value == null)
+				return "NULL";
+			if (value instanceof Collection)
+				return StringUtils.join((Collection<?>)value, '|');
+			if (ArrayUtils.isArray(value))
+				return StringUtils.join(ArrayUtils.toList(value, Object.class), "|");
+			return "?" + value + "?";
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
index 5a85bde..521c965 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/RestTestcase.java
@@ -46,7 +46,7 @@ public class RestTestcase {
 	 */
 	protected RestClient getClient(String label, Serializer serializer, Parser parser) {
 		if (! clients.containsKey(label))
-			clients.put(label, TestMicroservice.client(serializer, parser).build());
+			clients.put(label, TestMicroservice.client(serializer, parser).pooled().build());
 		return clients.get(label);
 	}
 
@@ -59,6 +59,10 @@ public class RestTestcase {
 		return clients.get(label);
 	}
 
+	protected void addClientToLifecycle(RestClient c) {
+		clients.put(UUID.randomUUID().toString(), c);
+	}
+
 	@SuppressWarnings("unchecked")
 	protected <T> T getCached(String label, Class<T> c) {
 		return (T)cache.get(label);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
index eb2f247..485fbed 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/_TestSuite.java
@@ -58,6 +58,7 @@ import org.junit.runners.Suite.*;
 	PathVariableTest.class,
 	PropertiesTest.class,
 	QueryTest.class,
+	RequestBeanProxyTest.class,
 	RestClientTest.class,
 	RestUtilsTest.class,
 	SerializersTest.class,

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest/src/main/java/org/apache/juneau/rest/RequestFormData.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestFormData.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestFormData.java
index 62adf90..453bb8b 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestFormData.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestFormData.java
@@ -17,6 +17,7 @@ import java.util.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
+import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.urlencoding.*;
 
@@ -99,7 +100,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 		// Fix for behavior difference between Tomcat and WAS.
 		// getParameter("foo") on "&foo" in Tomcat returns "".
 		// getParameter("foo") on "&foo" in WAS returns null.
-		if (v.length == 1 && v[0] == null) 
+		if (v.length == 1 && v[0] == null)
 			return "";
 
 		return v[0];
@@ -286,4 +287,24 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	private <T> T parseValue(String val, ClassMeta<T> c) throws ParseException {
 		return parser.parsePart(val, c);
 	}
+
+	/**
+	 * Converts the form data parameters to a readable string.
+	 *
+	 * @param sorted Sort the form data parameters by name.
+	 * @return A JSON string containing the contents of the form data parameters.
+	 */
+	public String toString(boolean sorted) {
+		Map<String,Object> m = (sorted ? new TreeMap<String,Object>() : new LinkedHashMap<String,Object>());
+		for (Map.Entry<String,String[]> e : this.entrySet()) {
+			String[] v = e.getValue();
+			m.put(e.getKey(), v.length == 1 ? v[0] : v);
+		}
+		return JsonSerializer.DEFAULT_LAX.toString(m);
+	}
+
+	@Override /* Object */
+	public String toString() {
+		return toString(false);
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest/src/main/java/org/apache/juneau/rest/RequestHeaders.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestHeaders.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestHeaders.java
index 03b7c38..cc0709d 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestHeaders.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestHeaders.java
@@ -19,6 +19,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.http.*;
 import org.apache.juneau.http.Date;
 import org.apache.juneau.internal.*;
+import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.urlencoding.*;
 
@@ -204,6 +205,28 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	}
 
 	/**
+	 * Returns a copy of this object, but only with the specified header names copied.
+	 * @param headers The headers to include in the copy.
+	 * @return A new headers object.
+	 */
+	public RequestHeaders subset(String...headers) {
+		RequestHeaders rh2 = new RequestHeaders().setParser(parser).setBeanSession(beanSession).setQueryParams(queryParams);
+		for (String h : headers)
+			if (containsKey(h))
+				rh2.put(h, get(h));
+		return rh2;
+	}
+
+	/**
+	 * Same as {@link #subset(String...)}, but allows you to specify header names as a comma-delimited list.
+	 * @param headers The headers to include in the copy.
+	 * @return A new headers object.
+	 */
+	public RequestHeaders subset(String headers) {
+		return subset(StringUtils.split(headers, ','));
+	}
+
+	/**
 	 * Returns the <code>Accept</code> header on the request.
 	 * <p>
 	 * Content-Types that are acceptable for the response.
@@ -671,4 +694,24 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	public Warning getWarning() {
 		return Warning.forString(getFirst("Warning"));
 	}
+
+	/**
+	 * Converts the headers to a readable string.
+	 *
+	 * @param sorted Sort the headers by name.
+	 * @return A JSON string containing the contents of the headers.
+	 */
+	public String toString(boolean sorted) {
+		Map<String,Object> m = (sorted ? new TreeMap<String,Object>() : new LinkedHashMap<String,Object>());
+		for (Map.Entry<String,String[]> e : this.entrySet()) {
+			String[] v = e.getValue();
+			m.put(e.getKey(), v.length == 1 ? v[0] : v);
+		}
+		return JsonSerializer.DEFAULT_LAX.toString(m);
+	}
+
+	@Override /* Object */
+	public String toString() {
+		return toString(false);
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest/src/main/java/org/apache/juneau/rest/RequestQuery.java
----------------------------------------------------------------------
diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestQuery.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestQuery.java
index bdb9b60..593c900 100644
--- a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestQuery.java
+++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestQuery.java
@@ -19,6 +19,7 @@ import javax.servlet.http.*;
 
 import org.apache.juneau.*;
 import org.apache.juneau.internal.*;
+import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.urlencoding.*;
 
@@ -90,7 +91,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 		// Fix for behavior difference between Tomcat and WAS.
 		// getParameter("foo") on "&foo" in Tomcat returns "".
 		// getParameter("foo") on "&foo" in WAS returns null.
-		if (v.length == 1 && v[0] == null) 
+		if (v.length == 1 && v[0] == null)
 			return "";
 
 		return v[0];
@@ -304,4 +305,24 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	private <T> T parseValue(String val, ClassMeta<T> c) throws ParseException {
 		return parser.parsePart(val, c);
 	}
+
+	/**
+	 * Converts the query parameters to a readable string.
+	 *
+	 * @param sorted Sort the query parameters by name.
+	 * @return A JSON string containing the contents of the query parameters.
+	 */
+	public String toString(boolean sorted) {
+		Map<String,Object> m = (sorted ? new TreeMap<String,Object>() : new LinkedHashMap<String,Object>());
+		for (Map.Entry<String,String[]> e : this.entrySet()) {
+			String[] v = e.getValue();
+			m.put(e.getKey(), v.length == 1 ? v[0] : v);
+		}
+		return JsonSerializer.DEFAULT_LAX.toString(m);
+	}
+
+	@Override /* Object */
+	public String toString() {
+		return toString(false);
+	}
 }


[2/3] incubator-juneau git commit: Improvements to @Query/@FormData/@Header/@Path remoteable annotations.

Posted by ja...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/javadoc/overview.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/javadoc/overview.html b/juneau-core/src/main/javadoc/overview.html
index a4e6885..ef06af5 100644
--- a/juneau-core/src/main/javadoc/overview.html
+++ b/juneau-core/src/main/javadoc/overview.html
@@ -6231,7 +6231,9 @@
 	<ja>@BeanProperty</ja>(<js>"foo"</js>)
 				</p>
 			<li>Fixed a race condition in ClassMeta.
-			
+			<li><jsf>URLENC_paramFormat</jsf> has been moved to {@link org.apache.juneau.uon.UonSerializerContext#UON_paramFormat}, 
+				and the UON/URL-Encoding serializers will now always serialize all values as plain text.
+				<br>This means that arrays and maps are converted to simple comma-delimited lists.
 		</ul>
 
 		<h6 class='topic'>org.apache.juneau.rest</h6>
@@ -6463,11 +6465,11 @@
 				<br><ja>@Remoteable</ja> annotation has been moved to this package.
 			<li>Updated doc: <a class='doclink' href='#Remoteable'>6 - Remoteable Services</a>
 			<li>New doc: <a class='doclink' href='#Remoteable.3rdParty'>6.1 -  Interface proxies against 3rd-party REST interfaces</a>
-			<li>New URL-encoding serializer setting: {@link org.apache.juneau.urlencoding.UrlEncodingSerializerContext#URLENC_paramFormat}
+			<li>New URL-encoding serializer setting: <code><del>UrlEncodingSerializerContext.URLENC_paramFormat</del></code>.
 			<li>New methods on {@link org.apache.juneau.urlencoding.UrlEncodingSerializerBuilder}:
 			<ul>
 				<li>{@link org.apache.juneau.urlencoding.UrlEncodingSerializerBuilder#paramFormat(String) paramFormat(String)}	
-				<li>{@link org.apache.juneau.urlencoding.UrlEncodingSerializerBuilder#plainTextParams() plainTextParams()}	
+				<li><code><del>UrlEncodingSerializerBuilder.plainTextParams()</del></code>	
 			</ul> 		
 		</ul>
 		
@@ -6626,7 +6628,7 @@
 				<ul>
 					<li>{@link org.apache.juneau.rest.client.RestClientBuilder#executorService(ExecutorService,boolean) executorService(ExecutorService,boolean)}
 					<li>{@link org.apache.juneau.rest.client.RestClientBuilder#paramFormat(String) paramFormat(ExecutorService,boolean)}
-					<li>{@link org.apache.juneau.rest.client.RestClientBuilder#plainTextParams() plainTextParams()}
+					<li><code><del>RestClientBuilder.plainTextParams()</del></code>
 					<li>{@link org.apache.juneau.rest.client.RestClientBuilder#noTrace() noTrace()} - Adds a <code>No-Trace: true</code> header on all requests to prevent
 						the servlet from logging errors.
 						<br>Useful for testing scenarios when you don't want the console to end up showing errors done on purpose.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
index 769e5eb..9be6df6 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
@@ -28,6 +28,7 @@ import org.apache.http.client.config.*;
 import org.apache.http.client.entity.*;
 import org.apache.http.client.methods.*;
 import org.apache.http.client.utils.*;
+import org.apache.http.entity.*;
 import org.apache.http.impl.client.*;
 import org.apache.http.util.*;
 import org.apache.juneau.*;
@@ -37,6 +38,7 @@ import org.apache.juneau.internal.ObjectUtils;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.parser.ParseException;
 import org.apache.juneau.serializer.*;
+import org.apache.juneau.urlencoding.*;
 import org.apache.juneau.utils.*;
 
 /**
@@ -191,16 +193,22 @@ public final class RestCall {
 				uriBuilder.addParameter(name, partSerializer.serialize(PartType.QUERY, value));
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
-				query(p.getName(), p.getValue(), skipIfEmpty, partSerializer);
-		} else if (value instanceof String) {
-			String s = value.toString();
-			if (! isEmpty(s))
-				uriBuilder.setCustomQuery(s);
+				query(p.getName(), p.getValue(), skipIfEmpty, UrlEncodingSerializer.DEFAULT_PLAINTEXT);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
 				query(p.getKey(), p.getValue(), skipIfEmpty, partSerializer);
-		} else if (isBean(value)){
+		} else if (isBean(value)) {
 			return query(name, toBeanMap(value), skipIfEmpty, partSerializer);
+		} else if (value instanceof Reader) {
+			try {
+				uriBuilder.setCustomQuery(IOUtils.read(value));
+			} catch (IOException e) {
+				throw new RestCallException(e);
+			}
+		} else if (value instanceof CharSequence) {
+			String s = value.toString();
+			if (! isEmpty(s))
+				uriBuilder.setCustomQuery(s);
 		} else {
 			throw new FormattedRuntimeException("Invalid name ''{0}'' passed to query(name,value,skipIfEmpty) for data type ''{1}''", name, ClassUtils.getReadableClassNameForObject(value));
 		}
@@ -291,13 +299,21 @@ public final class RestCall {
 				formData.add(new SerializedNameValuePair(name, value, partSerializer));
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
-				if (! (isEmpty(p.getValue()) && skipIfEmpty))
+				if (p.getValue() != null && ! (isEmpty(p.getValue()) && skipIfEmpty))
 					formData.add(p);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
 				formData(p.getKey(), p.getValue(), skipIfEmpty, partSerializer);
 		} else if (isBean(value)) {
 			return formData(name, toBeanMap(value), skipIfEmpty, partSerializer);
+		} else if (value instanceof Reader) {
+			contentType("application/x-www-form-urlencoded");
+			input(value);
+		} else if (value instanceof CharSequence) {
+			try {
+				contentType("application/x-www-form-urlencoded");
+				input(new StringEntity(value.toString()));
+			} catch (UnsupportedEncodingException e) {}
 		} else {
 			throw new FormattedRuntimeException("Invalid name ''{0}'' passed to formData(name,value,skipIfEmpty) for data type ''{1}''", name, ClassUtils.getReadableClassNameForObject(value));
 		}
@@ -389,13 +405,13 @@ public final class RestCall {
 			uriBuilder.setPath(newPath);
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
-				path(p.getName(), p.getValue());
+				path(p.getName(), p.getValue(), partSerializer);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
-				path(p.getKey(), p.getValue());
+				path(p.getKey(), p.getValue(), partSerializer);
 		} else if (isBean(value)) {
-			return path(name, toBeanMap(value));
-		} else {
+			return path(name, toBeanMap(value), partSerializer);
+		} else if (value != null) {
 			throw new FormattedRuntimeException("Invalid name ''{0}'' passed to path(name,value) for data type ''{1}''", name, ClassUtils.getReadableClassNameForObject(value));
 		}
 		return this;
@@ -454,6 +470,7 @@ public final class RestCall {
 	public RestCall input(final Object input) throws RestCallException {
 		this.input = input;
 		this.hasInput = true;
+		this.formData = null;
 		return this;
 	}
 
@@ -508,7 +525,7 @@ public final class RestCall {
 				request.setHeader(name, partSerializer.serialize(PartType.HEADER, value));
 		} else if (value instanceof NameValuePairs) {
 			for (NameValuePair p : (NameValuePairs)value)
-				header(p.getName(), p.getValue(), skipIfEmpty, partSerializer);
+				header(p.getName(), p.getValue(), skipIfEmpty, UrlEncodingSerializer.DEFAULT_PLAINTEXT);
 		} else if (value instanceof Map) {
 			for (Map.Entry<String,Object> p : ((Map<String,Object>) value).entrySet())
 				header(p.getKey(), p.getValue(), skipIfEmpty, partSerializer);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
index 8f26768..910a9fb 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClient.java
@@ -567,39 +567,42 @@ public class RestClient extends CoreObject {
 							if (rmm.getRequestBeanArgs().length > 0) {
 								BeanSession bs = getBeanContext().createSession();
 
-								for (Integer i : rmm.getRequestBeanArgs()) {
-									BeanMap<?> bm = bs.toBeanMap(args[i]);
-									for (BeanPropertyValue bpv : bm.getValues(true)) {
+								for (RemoteMethodArg rma : rmm.getRequestBeanArgs()) {
+									BeanMap<?> bm = bs.toBeanMap(args[rma.index]);
+
+									for (BeanPropertyValue bpv : bm.getValues(false)) {
 										BeanPropertyMeta pMeta = bpv.getMeta();
 										Object val = bpv.getValue();
 
 										Path p = pMeta.getAnnotation(Path.class);
 										if (p != null)
-											rc.path(getName(p.value(), pMeta), val, getPartSerializer(p.serializer()));
+											rc.path(getName(p.name(), p.value(), pMeta), val, getPartSerializer(p.serializer(), rma.serializer));
 
-										Query q1 = pMeta.getAnnotation(Query.class);
-										if (q1 != null)
-											rc.query(getName(q1.value(), pMeta), val, false, getPartSerializer(q1.serializer()));
+										if (val != null) {
+											Query q1 = pMeta.getAnnotation(Query.class);
+											if (q1 != null)
+												rc.query(getName(q1.name(), q1.value(), pMeta), val, q1.skipIfEmpty(), getPartSerializer(q1.serializer(), rma.serializer));
 
-										QueryIfNE q2 = pMeta.getAnnotation(QueryIfNE.class);
-										if (q2 != null)
-											rc.query(getName(q2.value(), pMeta), val, true, getPartSerializer(q2.serializer()));
+											QueryIfNE q2 = pMeta.getAnnotation(QueryIfNE.class);
+											if (q2 != null)
+												rc.query(getName(q2.name(), q2.value(), pMeta), val, true, getPartSerializer(q2.serializer(), rma.serializer));
 
-										FormData f1 = pMeta.getAnnotation(FormData.class);
-										if (f1 != null)
-											rc.formData(getName(f1.value(), pMeta), val, false, getPartSerializer(f1.serializer()));
+											FormData f1 = pMeta.getAnnotation(FormData.class);
+											if (f1 != null)
+												rc.formData(getName(f1.name(), f1.value(), pMeta), val, f1.skipIfEmpty(), getPartSerializer(f1.serializer(), rma.serializer));
 
-										FormDataIfNE f2 = pMeta.getAnnotation(FormDataIfNE.class);
-										if (f2 != null)
-											rc.formData(getName(f2.value(), pMeta), val, true, getPartSerializer(f2.serializer()));
+											FormDataIfNE f2 = pMeta.getAnnotation(FormDataIfNE.class);
+											if (f2 != null)
+												rc.formData(getName(f2.name(), f2.value(), pMeta), val, true, getPartSerializer(f2.serializer(), rma.serializer));
 
-										org.apache.juneau.remoteable.Header h1 = pMeta.getAnnotation(org.apache.juneau.remoteable.Header.class);
-										if (h1 != null)
-											rc.header(getName(h1.value(), pMeta), val, false, getPartSerializer(h1.serializer()));
+											org.apache.juneau.remoteable.Header h1 = pMeta.getAnnotation(org.apache.juneau.remoteable.Header.class);
+											if (h1 != null)
+												rc.header(getName(h1.name(), h1.value(), pMeta), val, h1.skipIfEmpty(), getPartSerializer(h1.serializer(), rma.serializer));
 
-										HeaderIfNE h2 = pMeta.getAnnotation(HeaderIfNE.class);
-										if (h2 != null)
-											rc.header(getName(h2.value(), pMeta), val, true, getPartSerializer(h2.serializer()));
+											HeaderIfNE h2 = pMeta.getAnnotation(HeaderIfNE.class);
+											if (h2 != null)
+												rc.header(getName(h2.name(), h2.value(), pMeta), val, true, getPartSerializer(h2.serializer(), rma.serializer));
+										}
 									}
 								}
 							}
@@ -628,14 +631,20 @@ public class RestClient extends CoreObject {
 		}
 	}
 
-	private static String getName(String name, BeanPropertyMeta pMeta) {
-		if ("*".equals(name) && ! pMeta.getClassMeta().isMapOrBean())
-			name = pMeta.getName();
-		return name;
+	private static String getName(String name1, String name2, BeanPropertyMeta pMeta) {
+		String n = name1.isEmpty() ? name2 : name1;
+		ClassMeta<?> cm = pMeta.getClassMeta();
+		if (n.isEmpty() && (cm.isMapOrBean() || cm.isReader() || cm.isInstanceOf(NameValuePairs.class)))
+			n = "*";
+		if (n.isEmpty())
+			n = pMeta.getName();
+		return n;
 	}
 
-	private static PartSerializer getPartSerializer(Class c) {
-		if (c == UrlEncodingSerializer.class)
+	private static PartSerializer getPartSerializer(Class c, PartSerializer c2) {
+		if (c2 != null)
+			return c2;
+		if (c == PartSerializer.class)
 			return null;
 		PartSerializer pf = partSerializerCache.get(c);
 		if (pf == null) {

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
----------------------------------------------------------------------
diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
index 463920a..65b4dc8 100644
--- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
+++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
@@ -46,6 +46,7 @@ import org.apache.juneau.internal.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.serializer.*;
+import org.apache.juneau.uon.*;
 import org.apache.juneau.urlencoding.*;
 
 /**
@@ -1101,7 +1102,7 @@ public class RestClientBuilder extends CoreObjectBuilder {
 	}
 
 	/**
-	 * Sets the {@link UrlEncodingSerializerContext#URLENC_paramFormat} property on the URL-encoding serializers in this group.
+	 * Sets the {@link UonSerializerContext#UON_paramFormat} property on the URL-encoding serializers in this group.
 	 * <p>
 	 * This overrides the behavior of the URL-encoding serializer to quote and escape characters
 	 * in query names and values that may be confused for UON notation (e.g. <js>"'(foo=123)'"</js>, <js>"'@(1,2,3)'"</js>).
@@ -1109,20 +1110,34 @@ public class RestClientBuilder extends CoreObjectBuilder {
 	 *
 	 * @param value The new value for this property.
 	 * @return This object (for method chaining).
-	 * @see UrlEncodingSerializerContext#URLENC_paramFormat
+	 * @see UonSerializerContext#UON_paramFormat
 	 */
 	public RestClientBuilder paramFormat(String value) {
-		super.property(UrlEncodingSerializerContext.URLENC_paramFormat, value);
+		super.property(UonSerializerContext.UON_paramFormat, value);
 		return this;
 	}
 
 	/**
 	 * Shortcut for calling <code>paramFormat(<js>"PLAINTEXT"</js>)</code>.
+	 * <p>
+	 * The default behavior is to serialize part values (query parameters, form data, headers, path variables) in UON notation.
+	 * Calling this method forces plain-text to be used instead.
+	 * <p>
+	 * Specifially, UON notation has the following effects:
+	 * <ul>
+	 * 	<li>Boolean strings (<js>"true"</js>/<js>"false"</js>) and numeric values (<js>"123"</js>) will be
+	 * 			quoted (<js>"'true'"</js>, <js>"'false'"</js>, <js>"'123'"</js>.
+	 * 		<br>This allows them to be differentiated from actual boolean and numeric values.
+	 * 	<li>String such as <js>"(foo='bar')"</js> that mimic UON structures will be quoted and escaped to
+	 * 		<js>"'(foo=bar~'baz~')'"</js>.
+	 * </ul>
+	 * <p>
+	 * The downside to using plain text part serialization is that you cannot serialize arbitrary POJOs.
 	 *
 	 * @return This object (for method chaining).
 	 */
-	public RestClientBuilder plainTextParams() {
-		super.property(UrlEncodingSerializerContext.URLENC_paramFormat, "PLAINTEXT");
+	public RestClientBuilder plainTextParts() {
+		super.property(UonSerializerContext.UON_paramFormat, "PLAINTEXT");
 		return this;
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/RequestBeanProxyResource.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/RequestBeanProxyResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/RequestBeanProxyResource.java
new file mode 100644
index 0000000..eed0679
--- /dev/null
+++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/RequestBeanProxyResource.java
@@ -0,0 +1,50 @@
+// ***************************************************************************************************************************
+// * 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.io.*;
+
+import org.apache.juneau.microservice.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+
+/**
+ * Validates the functionality of <ja>@RequestBeans</ja>.
+ */
+@RestResource(
+	path="/testRequestBeanProxy"
+)
+@SuppressWarnings("serial")
+public class RequestBeanProxyResource extends ResourceJena {
+
+	@RestMethod(name="GET", path="/echoQuery")
+	public Reader echoQuery(RestRequest req) throws Exception {
+		return new StringReader(req.getQuery().toString(true));
+	}
+
+	@RestMethod(name="POST", path="/echoFormData")
+	public Reader echoFormData(RestRequest req) throws Exception {
+		return new StringReader(req.getFormData().toString(true));
+	}
+
+	@RestMethod(name="GET", path="/echoHeaders")
+	public Reader echoHeaders(RestRequest req) throws Exception {
+		return new StringReader(req.getHeaders().subset("a,b,c,d,e,f,g,h,i,a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4").toString(true));
+	}
+
+	@RestMethod(name="GET", path="/echoPath/*")
+	public Reader echoPath(RestRequest req) throws Exception {
+		return new StringReader(req.getPathMatch().getRemainder());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
index f04181b..3bee867 100644
--- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
+++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/Root.java
@@ -60,6 +60,7 @@ import org.apache.juneau.rest.labels.*;
 		PathVariablesResource.class,
 		PropertiesResource.class,
 		QueryResource.class,
+		RequestBeanProxyResource.class,
 		RestClient2Resource.class,
 		SerializersResource.class,
 		StaticFilesResource.class,

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
----------------------------------------------------------------------
diff --git a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
index 9aeff98..d0f1874 100644
--- a/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
+++ b/juneau-rest-test/src/test/java/org/apache/juneau/rest/test/FormDataTest.java
@@ -68,7 +68,7 @@ public class FormDataTest extends RestTestcase {
 	//====================================================================================================
 	@Test
 	public void testPlainTextParams() throws Exception {
-		RestClient c = TestMicroservice.client(UrlEncodingSerializer.class, UrlEncodingParser.class).plainTextParams().build();
+		RestClient c = TestMicroservice.client(UrlEncodingSerializer.class, UrlEncodingParser.class).plainTextParts().build();
 		String r;
 
 		Map<String,Object> m = new AMap<String,Object>()


[3/3] incubator-juneau git commit: Improvements to @Query/@FormData/@Header/@Path remoteable annotations.

Posted by ja...@apache.org.
Improvements to @Query/@FormData/@Header/@Path remoteable annotations.

Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/93aadae1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/93aadae1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/93aadae1

Branch: refs/heads/master
Commit: 93aadae1d6c8da0b1ae81df461927ed16744576e
Parents: 13f816f
Author: JamesBognar <ja...@apache.org>
Authored: Thu Jun 1 20:00:25 2017 -0400
Committer: JamesBognar <ja...@apache.org>
Committed: Thu Jun 1 20:00:25 2017 -0400

----------------------------------------------------------------------
 .../apache/juneau/annotation/BeanProperty.java  |   17 +-
 .../java/org/apache/juneau/http/package.html    |   41 +
 .../org/apache/juneau/internal/ArrayUtils.java  |   29 +-
 .../org/apache/juneau/internal/IOUtils.java     |   30 +
 .../java/org/apache/juneau/json/package.html    |    4 +-
 .../org/apache/juneau/remoteable/FormData.java  |  150 +-
 .../apache/juneau/remoteable/FormDataIfNE.java  |   22 +-
 .../org/apache/juneau/remoteable/Header.java    |  139 +-
 .../apache/juneau/remoteable/HeaderIfNE.java    |   22 +-
 .../java/org/apache/juneau/remoteable/Path.java |  134 +-
 .../org/apache/juneau/remoteable/Query.java     |  151 +-
 .../org/apache/juneau/remoteable/QueryIfNE.java |   23 +-
 .../juneau/remoteable/RemoteMethodArg.java      |    9 +-
 .../juneau/remoteable/RemoteableMethodMeta.java |   30 +-
 .../apache/juneau/remoteable/RequestBean.java   |   16 +-
 .../juneau/serializer/PartSerializer.java       |    1 +
 .../org/apache/juneau/uon/UonSerializer.java    |   41 +-
 .../apache/juneau/uon/UonSerializerContext.java |   40 +-
 .../apache/juneau/uon/UonSerializerSession.java |   15 +-
 .../java/org/apache/juneau/uon/UonWriter.java   |   11 +-
 .../java/org/apache/juneau/uon/package.html     |    4 +-
 .../urlencoding/UrlEncodingSerializer.java      |   47 +-
 .../UrlEncodingSerializerBuilder.java           |    6 +-
 .../UrlEncodingSerializerContext.java           |   31 +-
 .../UrlEncodingSerializerSession.java           |   12 +-
 .../org/apache/juneau/urlencoding/package.html  |    4 +-
 .../java/org/apache/juneau/xml/package.html     |    4 +-
 juneau-core/src/main/javadoc/overview.html      |   10 +-
 .../org/apache/juneau/rest/client/RestCall.java |   41 +-
 .../apache/juneau/rest/client/RestClient.java   |   65 +-
 .../juneau/rest/client/RestClientBuilder.java   |   25 +-
 .../rest/test/RequestBeanProxyResource.java     |   50 +
 .../java/org/apache/juneau/rest/test/Root.java  |    1 +
 .../apache/juneau/rest/test/FormDataTest.java   |    2 +-
 .../juneau/rest/test/RequestBeanProxyTest.java  | 1988 ++++++++++++++++++
 .../apache/juneau/rest/test/RestTestcase.java   |    6 +-
 .../org/apache/juneau/rest/test/_TestSuite.java |    1 +
 .../org/apache/juneau/rest/RequestFormData.java |   23 +-
 .../org/apache/juneau/rest/RequestHeaders.java  |   43 +
 .../org/apache/juneau/rest/RequestQuery.java    |   23 +-
 40 files changed, 2986 insertions(+), 325 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/annotation/BeanProperty.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/annotation/BeanProperty.java b/juneau-core/src/main/java/org/apache/juneau/annotation/BeanProperty.java
index f2461bb..f6472c0 100644
--- a/juneau-core/src/main/java/org/apache/juneau/annotation/BeanProperty.java
+++ b/juneau-core/src/main/java/org/apache/juneau/annotation/BeanProperty.java
@@ -127,21 +127,14 @@ public @interface BeanProperty {
 	String name() default "";
 
 	/**
-	 * A synonym for {@link #name()}
+	 * A synonym for {@link #name()}.
 	 * <p>
-	 * If you're only using the <code>BeanProperty</code> annotation to override the property name, this allows you
-	 * to define it using shortened notation:
-	 * <p class='bcode'>
-	 * 		<ja>@BeanProperty</ja>(<js>"foo"</js>)
-	 * 		<jk>public</jk> String getX();
-	 * 	}
-	 * </p>
+	 * The following annotations are equivalent:
 	 * <p>
-	 * This is equivalent to the following notation:
 	 * <p class='bcode'>
-	 * 		<ja>@BeanProperty</ja>(name=<js>"foo"</js>)
-	 * 		<jk>public</jk> String getX();
-	 * 	}
+	 * 	<ja>@BeanProperty</ja>(name=<js>"foo"</js>)
+	 *
+	 * 	<ja>@BeanProperty</ja>(<js>"foo"</js>)
 	 * </p>
 	 */
 	String value() default "";

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/http/package.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/http/package.html b/juneau-core/src/main/java/org/apache/juneau/http/package.html
new file mode 100644
index 0000000..23f63da
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/http/package.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<!--
+/***************************************************************************************************************************
+ * 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.
+ *
+ ***************************************************************************************************************************/
+ -->
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<style type="text/css">
+		/* For viewing in Page Designer */
+		@IMPORT url("../../../../../../javadoc.css");
+
+		/* For viewing in REST interface */
+		@IMPORT url("../htdocs/javadoc.css");
+		body { 
+			margin: 20px; 
+		}	
+	</style>
+	<script>
+		/* Replace all @code and @link tags. */	
+		window.onload = function() {
+			document.body.innerHTML = document.body.innerHTML.replace(/\{\@code ([^\}]+)\}/g, '<code>$1</code>');
+			document.body.innerHTML = document.body.innerHTML.replace(/\{\@link (([^\}]+)\.)?([^\.\}]+)\}/g, '<code>$3</code>');
+		}
+	</script>
+</head>
+<body>
+<p>RFC2616 HTTP Headers</p>
+</body>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/internal/ArrayUtils.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/internal/ArrayUtils.java b/juneau-core/src/main/java/org/apache/juneau/internal/ArrayUtils.java
index 5199af1..176dbd5 100644
--- a/juneau-core/src/main/java/org/apache/juneau/internal/ArrayUtils.java
+++ b/juneau-core/src/main/java/org/apache/juneau/internal/ArrayUtils.java
@@ -205,6 +205,31 @@ public final class ArrayUtils {
 	}
 
 	/**
+	 * Returns <jk>true</jk> if the specified object is an array.
+	 * @param array The array to test.
+	 * @return <jk>true</jk> if the specified object is an array.
+	 */
+	public static boolean isArray(Object array) {
+		return array != null && array.getClass().isArray();
+	}
+
+	/**
+	 * Converts the specified array to an <code>ArrayList</code>
+	 * 
+	 * @param array The array to convert.
+	 * @param componentType The type of objects in the array.
+	 * 	It must match the actual component type in the array.
+	 * @return A new {@link ArrayList}
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T> List<T> toList(Object array, Class<T> componentType) {
+		List<T> l = new ArrayList<T>(Array.getLength(array));
+		for (int i = 0; i < Array.getLength(array); i++)
+			l.add((T)Array.get(array, i));
+		return l;
+	}
+
+	/**
 	 * Shortcut for calling <code>myList.toArray(new T[myList.size()]);</code>
 	 *
 	 * @param c The collection being converted to an array.
@@ -227,14 +252,16 @@ public final class ArrayUtils {
 	 *
 	 * @param array The array to copy into a list.
 	 * @param list The list to copy the values into.
+	 * @return The same list passed in.
 	 */
 	@SuppressWarnings({"unchecked","rawtypes"})
-	public static void copyToList(Object array, List list) {
+	public static List copyToList(Object array, List list) {
 		if (array != null) {
 			int length = Array.getLength(array);
 			for (int i = 0; i < length; i++)
 				list.add(Array.get(array, i));
 		}
+		return list;
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/internal/IOUtils.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/internal/IOUtils.java b/juneau-core/src/main/java/org/apache/juneau/internal/IOUtils.java
index 1d0a5cc..516cd2e 100644
--- a/juneau-core/src/main/java/org/apache/juneau/internal/IOUtils.java
+++ b/juneau-core/src/main/java/org/apache/juneau/internal/IOUtils.java
@@ -53,6 +53,36 @@ public final class IOUtils {
 	}
 
 	/**
+	 * Reads the specified object to a <code>String</code>.
+	 * <p>
+	 * Can be any of the following object types:
+	 * <ul>
+	 * 	<li>{@link CharSequence}
+	 * 	<li>{@link File}
+	 * 	<li>{@link Reader}
+	 * 	<li>{@link InputStream}
+	 * 	<li><code><jk>byte</jk>[]</code>
+	 * </ul>
+	 *
+	 * @param o The object to read.
+	 * @return The object serialized to a string, or <jk>null</jk> if it wasn't a supported type.
+	 * @throws IOException
+	 */
+	public static String read(Object o) throws IOException {
+		if (o instanceof CharSequence)
+			return o.toString();
+		if (o instanceof File)
+			return read((File)o);
+		if (o instanceof Reader)
+			return read((Reader)o);
+		if (o instanceof InputStream)
+			return read((InputStream)o);
+		if (o instanceof byte[])
+			return read(new ByteArrayInputStream((byte[])o));
+		return null;
+	}
+
+	/**
 	 * Writes the contents of the specified <code>Reader</code> to the specified file.
 	 *
 	 * @param out The file to write the output to.

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/json/package.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/json/package.html b/juneau-core/src/main/java/org/apache/juneau/json/package.html
index b6decc1..960ea0b 100644
--- a/juneau-core/src/main/java/org/apache/juneau/json/package.html
+++ b/juneau-core/src/main/java/org/apache/juneau/json/package.html
@@ -359,12 +359,12 @@
 		<p>
 			Another useful feature is the {@link org.apache.juneau.annotation.Bean#propertyNamer()} annotation that allows you to plug in your own
 				logic for determining bean property names.<br>
-			The {@link org.apache.juneau.PropertyNamerDashedLC} is an example of an alternate property namer.
+			The {@link org.apache.juneau.PropertyNamerDLC} is an example of an alternate property namer.
 			It converts bean property names to lowercase-dashed format.
 		</p>
 		<h6 class='topic'>Example:</h6>
 		<p class='bcode'>	
-	<ja>@Bean</ja>(propertyNamer=PropertyNamerDashedLC.<jk>class</jk>)
+	<ja>@Bean</ja>(propertyNamer=PropertyNamerDLC.<jk>class</jk>)
 	<jk>public class</jk> Person {
 		...
 		</p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/remoteable/FormData.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/FormData.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/FormData.java
index 83389b8..0bd91ad 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/FormData.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/FormData.java
@@ -17,7 +17,6 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
-import org.apache.juneau.annotation.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.urlencoding.*;
 
@@ -29,27 +28,39 @@ import org.apache.juneau.urlencoding.*;
  * 	<ja>@Remoteable</ja>(path=<js>"/myproxy"</js>)
  * 	<jk>public interface</jk> MyProxy {
  *
+ * 		<jc>// Explicit names specified for form data parameters.</jc>
+ * 		<jc>// pojo will be converted to UON notation (unless plain-text parts enabled).</jc>
  * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod1"</js>)
  * 		String myProxyMethod1(<ja>@FormData</ja>(<js>"foo"</js>)</ja> String foo, <ja>@FormData</ja>(<js>"bar"</js>)</ja> MyPojo pojo);
  *
+ * 		<jc>// Multiple values pulled from a NameValuePairs object.</jc>
+ * 		<jc>// Same as @FormData("*").</jc>
  * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod2"</js>)
- * 		String myProxyMethod2(<ja>@FormData</ja> NameValuePairs form);
+ * 		String myProxyMethod2(<ja>@FormData</ja> NameValuePairs nameValuePairs);
  *
+ * 		<jc>// Multiple values pulled from a Map.</jc>
+ * 		<jc>// Same as @FormData("*").</jc>
  * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod3"</js>)
- * 		String myProxyMethod2(<ja>@FormData</ja> Map&lt;String,Object&gt; form);
+ * 		String myProxyMethod3(<ja>@FormData</ja> Map&lt;String,Object&gt; map);
+ *
+ * 		<jc>// Multiple values pulled from a bean.</jc>
+ * 		<jc>// Same as @FormData("*").</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod4"</js>)
+ * 		String myProxyMethod4(<ja>@FormData</ja> MyBean myBean);
+ *
+ * 		<jc>// An entire form-data HTTP body as a String.</jc>
+ * 		<jc>// Same as @FormData("*").</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod5"</js>)
+ * 		String myProxyMethod5(<ja>@FormData</ja> String string);
+ *
+ * 		<jc>// An entire form-data HTTP body as a Reader.</jc>
+ * 		<jc>// Sames as @FormData("*").</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod6"</js>)
+ * 		String myProxyMethod6(<ja>@FormData</ja> Reader reader);
+ *
  * 	}
  * </p>
  * <p>
- * The argument can be any of the following types:
- * <ul class='spaced-list'>
- * 	<li>Any serializable POJO - Converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * 	<li><code>NameValuePairs</code> - Individual name-value pairs.
- * 	<li><code>Map&lt;String,Object&gt;</code> - Individual name-value pairs.
- * 		Values are converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * 	<li>A bean - Individual name-value pairs.
- * 		Values are converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * </ul>
- * <p>
  * The annotation can also be applied to a bean property field or getter when the argument is annotated with
  *  {@link RequestBean @RequestBean}:
  * <p>
@@ -63,18 +74,52 @@ import org.apache.juneau.urlencoding.*;
  * 	}
  *
  * 	<jk>public interface</jk> MyRequestBean {
+ *
+ * 		<jc>// Name explicitly specified.</jc>
+ * 		<ja>@FormData</ja>(<js>"foo"</js>)
+ * 		String getX();
+ *
+ * 		<jc>// Name inherited from bean property.</jc>
+ * 		<jc>// Same as @FormData("bar")</jc>
+ * 		<ja>@FormData</ja>
+ * 		String getBar();
+ *
+ * 		<jc>// Name inherited from bean property.</jc>
+ * 		<jc>// Same as @FormData("baz")</jc>
+ * 		<ja>@FormData</ja>
+ * 		<ja>@BeanProperty</ja>(<js>"baz"</js>)
+ * 		String getY();
+ *
+ * 		<jc>// Multiple values pulled from NameValuePairs object.</jc>
+ * 		<jc>// Same as @FormData("*")</jc>
+ * 		<ja>@FormData</ja>
+ * 		NameValuePairs getNameValuePairs();
+ *
+ * 		<jc>// Multiple values pulled from Map.</jc>
+ * 		<jc>// Same as @FormData("*")</jc>
+ * 		<ja>@FormData</ja>
+ * 	 	Map&lt;String,Object&gt; getMap();
+ *
+ * 		<jc>// Multiple values pulled from bean.</jc>
+ * 		<jc>// Same as @FormData("*")</jc>
  * 		<ja>@FormData</ja>
- * 		String getFoo();
+ * 	 	MyBean getMyBean();
  *
+ * 		<jc>// An entire form-data HTTP body as a Reader.</jc>
+ * 		<jc>// Same as @FormData("*")</jc>
  * 		<ja>@FormData</ja>
- * 		MyPojo getBar();
+ * 		Reader getReader();
  * 	}
  * </p>
  * <p>
- * When used in a request bean, the {@link #value()} can be used to override the form data parameter name.
- * It can also be overridden via the {@link BeanProperty#name @BeanProperty.name()} annotation.
- * A name of <js>"*"</js> where the bean property value is a map or bean will cause the individual entries in the
- * map or bean to be expanded to form data parameters.
+ * The {@link #name()} and {@link #value()} elements are synonyms for specifying the parameter name.  Only one should be used.
+ * <br>The following annotations are fully equivalent:
+ * <p>
+ * <p class='bcode'>
+ * 	<ja>@FormData</ja>(name=<js>"foo"</js>)
+ *
+ * 	<ja>@FormData</ja>(<js>"foo"</js>)
+ * </p>
  */
 @Documented
 @Target({PARAMETER,FIELD,METHOD})
@@ -85,22 +130,71 @@ public @interface FormData {
 	/**
 	 * The form post parameter name.
 	 * <p>
-	 * A value of <js>"*"</js> indicates the value should be serialized as name/value pairs and is applicable
-	 * for the following data types:
-	 * <ul>
-	 * 	<li><code>NameValuePairs</code>
-	 * 	<li><code>Map&lt;String,Object&gt;</code>
-	 * 	<li>A bean
+	 * Note that {@link #name()} and {@link #value()} are synonyms.
+	 * <p>
+	 * The value should be either <js>"*"</js> to represent multiple name/value pairs, or a label that defines the
+	 * 	form data parameter name.
+	 * <p>
+	 * A blank value (the default) has the following behavior:
+	 * <ul class='spaced-list'>
+	 * 	<li>If the data type is <code>NameValuePairs</code>, <code>Map</code>, or a bean,
+	 * 		then it's the equivalent to <js>"*"</js> which will cause the value to be serialized as name/value pairs.
+	 * 		<h6 class='figure'>Example:</h6>
+	 * 		<p class='bcode'>
+	 * 	<jc>// When used on a remote method parameter</jc>
+	 * 	<ja>@Remoteable</ja>(path=<js>"/myproxy"</js>)
+	 * 	<jk>public interface</jk> MyProxy {
+	 *
+	 * 		<jc>// Equivalent to @FormData("*")</jc>
+	 * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod"</js>)
+	 * 		String myProxyMethod1(<ja>@FormData</ja> Map&lt;String,Object&gt; formData);
+	 * 	}
+	 *
+	 * 	<jc>// When used on a request bean method</jc>
+	 * 	<jk>public interface</jk> MyRequestBean {
+	 *
+	 * 		<jc>// Equivalent to @FormData("*")</jc>
+	 * 		<ja>@FormData</ja>
+	 * 		Map&lt;String,Object&gt; getFoo();
+	 * 	}
+	 * 		</p>
+	 *			<br>
+	 * 	<li>If used on a request bean method, uses the bean property name.
+	 * 		<h6 class='figure'>Example:</h6>
+	 * 		<p class='bcode'>
+	 * 	<jk>public interface</jk> MyRequestBean {
+	 *
+	 * 		<jc>// Equivalent to @FormData("foo")</jc>
+	 * 		<ja>@FormData</ja>
+	 * 		String getFoo();
+	 * 	}
+	 * 		</p>
+	 * 	</ul>
 	 * </ul>
 	 */
-	String value() default "*";
+	String name() default "";
+
+	/**
+	 * A synonym for {@link #name()}.
+	 * <p>
+	 * Allows you to use shortened notation if you're only specifying the name.
+	 */
+	String value() default "";
+
+	/**
+	 * Skips this value if it's an empty string or empty collection/array.
+	 * <p>
+	 * Note that <jk>null</jk> values are already ignored.
+	 */
+	boolean skipIfEmpty() default false;
 
 	/**
 	 * Specifies the {@link PartSerializer} class used for serializing values to strings.
 	 * <p>
-	 * The default serializer converters values to UON notation.
+	 * The default value defaults to the using the part serializer defined on the {@link RequestBean} annotation,
+	 * 	then on the client which by default is {@link UrlEncodingSerializer}.
 	 * <p>
 	 * This annotation is provided to allow values to be custom serialized.
 	 */
-	Class<? extends PartSerializer> serializer() default UrlEncodingSerializer.class;
+	Class<? extends PartSerializer> serializer() default PartSerializer.class;
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/remoteable/FormDataIfNE.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/FormDataIfNE.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/FormDataIfNE.java
index 2d0b3ab..494a2cf 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/FormDataIfNE.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/FormDataIfNE.java
@@ -31,23 +31,23 @@ public @interface FormDataIfNE {
 
 	/**
 	 * The form post parameter name.
-	 * <p>
-	 * A value of <js>"*"</js> indicates the value should be serialized as name/value pairs and is applicable
-	 * for the following data types:
-	 * <ul>
-	 * 	<li><code>NameValuePairs</code>
-	 * 	<li><code>Map&lt;String,Object&gt;</code>
-	 * 	<li>A bean
-	 * </ul>
+	 * @see FormData#name()
+	 */
+	String name() default "";
+
+	/**
+	 * A synonym for {@link #name()}.
+	 * @see FormData#value()
 	 */
-	String value() default "*";
+	String value() default "";
 
 	/**
 	 * Specifies the {@link PartSerializer} class used for serializing values to strings.
 	 * <p>
-	 * The default serializer converters values to UON notation.
+	 * The default value defaults to the using the part serializer defined on the {@link RequestBean} annotation,
+	 * 	then on the client which by default is {@link UrlEncodingSerializer}.
 	 * <p>
 	 * This annotation is provided to allow values to be custom serialized.
 	 */
-	Class<? extends PartSerializer> serializer() default UrlEncodingSerializer.class;
+	Class<? extends PartSerializer> serializer() default PartSerializer.class;
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/remoteable/Header.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/Header.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/Header.java
index 6eaf870..d733e0d 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/Header.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/Header.java
@@ -17,7 +17,6 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
-import org.apache.juneau.annotation.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.urlencoding.*;
 
@@ -29,24 +28,28 @@ import org.apache.juneau.urlencoding.*;
  * 	<ja>@Remoteable</ja>(path=<js>"/myproxy"</js>)
  * 	<jk>public interface</jk> MyProxy {
  *
+ * 		<jc>// Explicit names specified for HTTP headers.</jc>
+ * 		<jc>// pojo will be converted to UON notation (unless plain-text parts enabled).</jc>
  * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod1"</js>)
  * 		String myProxyMethod1(<ja>@Header</ja>(<js>"Foo"</js>)</ja> String foo, <ja>@Header</ja>(<js>"Bar"</js>)</ja> MyPojo pojo);
  *
+ * 		<jc>// Multiple values pulled from a NameValuePairs object.</jc>
+ * 		<jc>// Same as @Header("*").</jc>
  * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod2"</js>)
- * 		String myProxyMethod2(<ja>@Header</ja> Map&lt;String,Object&gt; headers);
+ * 		String myProxyMethod2(<ja>@Header</ja> NameValuePairs nameValuePairs);
+ *
+ * 		<jc>// Multiple values pulled from a Map.</jc>
+ * 		<jc>// Same as @Header("*").</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod3"</js>)
+ * 		String myProxyMethod3(<ja>@Header</ja> Map&lt;String,Object&gt; map);
+ *
+ * 		<jc>// Multiple values pulled from a bean.</jc>
+ * 		<jc>// Same as @Header("*").</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod4"</js>)
+ * 		String myProxyMethod4(<ja>@Header</ja> MyBean myBean);
  * 	}
  * </p>
  * <p>
- * The argument can be any of the following types:
- * <ul class='spaced-list'>
- * 	<li><code>NameValuePairs</code> - Individual name-value pairs.
- * 	<li>Any serializable POJO - Converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * 	<li><code>Map&lt;String,Object&gt;</code> - Individual name-value pairs.
- * 		Values are converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * 	<li>A bean - Individual name-value pairs.
- * 		Values are converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * </ul>
- * <p>
  * The annotation can also be applied to a bean property field or getter when the argument is annotated with
  *  {@link RequestBean @RequestBean}:
  * <p>
@@ -60,18 +63,47 @@ import org.apache.juneau.urlencoding.*;
  * 	}
  *
  * 	<jk>public interface</jk> MyRequestBean {
+ *
+ * 		<jc>// Name explicitly specified.</jc>
  * 		<ja>@Header</ja>(<js>"Foo"</js>)
- * 		String getFoo();
+ * 		String getX();
+ *
+ * 		<jc>// Name inherited from bean property.</jc>
+ * 		<jc>// Same as @Header("bar")</jc>
+ * 		<ja>@Header</ja>
+ * 		String getBar();
+ *
+ * 		<jc>// Name inherited from bean property.</jc>
+ * 		<jc>// Same as @Header("Baz")</jc>
+ * 		<ja>@Header</ja>
+ * 		<ja>@BeanProperty</ja>(<js>"Baz"</js>)
+ * 		String getY();
  *
- * 		<ja>@Header</ja>(<js>"Bar"</js>)
- * 		MyPojo getBar();
+ * 		<jc>// Multiple values pulled from NameValuePairs object.</jc>
+ * 		<jc>// Same as @Header("*")</jc>
+ * 		<ja>@Header</ja>
+ * 		NameValuePairs getNameValuePairs();
+ *
+ * 		<jc>// Multiple values pulled from Map.</jc>
+ * 		<jc>// Same as @Header("*")</jc>
+ * 		<ja>@Header</ja>
+ * 	 	Map&lt;String,Object&gt; getMap();
+ *
+ * 		<jc>// Multiple values pulled from bean.</jc>
+ * 		<jc>// Same as @Header("*")</jc>
+ * 		<ja>@Header</ja>
+ * 	 	MyBean getBean();
  * 	}
  * </p>
  * <p>
- * When used in a request bean, the {@link #value()} can be used to override the header name.
- * It can also be overridden via the {@link BeanProperty#name @BeanProperty.name()} annotation.
- * A name of <js>"*"</js> where the bean property value is a map or bean will cause the individual entries in the
- * map or bean to be expanded to headers.
+ * The {@link #name()} and {@link #value()} elements are synonyms for specifying the header name.  Only one should be used.
+ * <br>The following annotations are fully equivalent:
+ * <p>
+ * <p class='bcode'>
+ * 	<ja>@Header</ja>(name=<js>"Foo"</js>)
+ *
+ * 	<ja>@Header</ja>(<js>"Foo"</js>)
+ * </p>
  */
 @Documented
 @Target({PARAMETER,FIELD,METHOD})
@@ -82,22 +114,73 @@ public @interface Header {
 	/**
 	 * The HTTP header name.
 	 * <p>
-	 * A value of <js>"*"</js> indicates the value should be serialized as name/value pairs and is applicable
-	 * for the following data types:
-	 * <ul>
-	 * 	<li><code>NameValuePairs</code>
-	 * 	<li><code>Map&lt;String,Object&gt;</code>
-	 * 	<li>A bean
+	 * A blank value (the default) indicates to reuse the bean property name when used on a request bean property.
+	 * <p>
+	 * <p>
+	 * The value should be either <js>"*"</js> to represent multiple name/value pairs, or a label that defines the
+	 * 	header name.
+	 * <p>
+	 * A blank value (the default) has the following behavior:
+	 * <ul class='spaced-list'>
+	 * 	<li>If the data type is <code>NameValuePairs</code>, <code>Map</code>, or a bean,
+	 * 		then it's the equivalent to <js>"*"</js> which will cause the value to be serialized as name/value pairs.
+	 * 		<h6 class='figure'>Example:</h6>
+	 * 		<p class='bcode'>
+	 * 	<jc>// When used on a remote method parameter</jc>
+	 * 	<ja>@Remoteable</ja>(path=<js>"/myproxy"</js>)
+	 * 	<jk>public interface</jk> MyProxy {
+	 *
+	 * 		<jc>// Equivalent to @Header("*")</jc>
+	 * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod"</js>)
+	 * 		String myProxyMethod1(<ja>@Header</ja> Map&lt;String,Object&gt; headers);
+	 * 	}
+	 *
+	 * 	<jc>// When used on a request bean method</jc>
+	 * 	<jk>public interface</jk> MyRequestBean {
+	 *
+	 * 		<jc>// Equivalent to @Header("*")</jc>
+	 * 		<ja>@Header</ja>
+	 * 		Map&lt;String,Object&gt; getFoo();
+	 * 	}
+	 * 		</p>
+	 *			<br>
+	 * 	<li>If used on a request bean method, uses the bean property name.
+	 * 		<h6 class='figure'>Example:</h6>
+	 * 		<p class='bcode'>
+	 * 	<jk>public interface</jk> MyRequestBean {
+	 *
+	 * 		<jc>// Equivalent to @Header("Foo")</jc>
+	 * 		<ja>@Header</ja>
+	 * 		<ja>@BeanProperty</ja>(<js>"Foo"</js>)
+	 * 		String getFoo();
+	 * 	}
+	 * 		</p>
+	 * 	</ul>
 	 * </ul>
 	 */
-	String value() default "*";
+	String name() default "";
+
+	/**
+	 * A synonym for {@link #name()}.
+	 * <p>
+	 * Allows you to use shortened notation if you're only specifying the name.
+	 */
+	String value() default "";
+
+	/**
+	 * Skips this value if it's an empty string or empty collection/array.
+	 * <p>
+	 * Note that <jk>null</jk> values are already ignored.
+	 */
+	boolean skipIfEmpty() default false;
 
 	/**
 	 * Specifies the {@link PartSerializer} class used for serializing values to strings.
 	 * <p>
-	 * The default serializer converters values to UON notation.
+	 * The default value defaults to the using the part serializer defined on the {@link RequestBean} annotation,
+	 * 	then on the client which by default is {@link UrlEncodingSerializer}.
 	 * <p>
 	 * This annotation is provided to allow values to be custom serialized.
 	 */
-	Class<? extends PartSerializer> serializer() default UrlEncodingSerializer.class;
+	Class<? extends PartSerializer> serializer() default PartSerializer.class;
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/remoteable/HeaderIfNE.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/HeaderIfNE.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/HeaderIfNE.java
index 4839ff0..eb81015 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/HeaderIfNE.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/HeaderIfNE.java
@@ -31,23 +31,23 @@ public @interface HeaderIfNE {
 
 	/**
 	 * The HTTP header name.
-	 * <p>
-	 * A value of <js>"*"</js> indicates the value should be serialized as name/value pairs and is applicable
-	 * for the following data types:
-	 * <ul>
-	 * 	<li><code>NameValuePairs</code>
-	 * 	<li><code>Map&lt;String,Object&gt;</code>
-	 * 	<li>A bean
-	 * </ul>
+	 * @see Header#name()
+	 */
+	String name() default "";
+
+	/**
+	 * A synonym for {@link #name()}.
+	 * @see Header#value()
 	 */
-	String value() default "*";
+	String value() default "";
 
 	/**
 	 * Specifies the {@link PartSerializer} class used for serializing values to strings.
 	 * <p>
-	 * The default serializer converters values to UON notation.
+	 * The default value defaults to the using the part serializer defined on the {@link RequestBean} annotation,
+	 * 	then on the client which by default is {@link UrlEncodingSerializer}.
 	 * <p>
 	 * This annotation is provided to allow values to be custom serialized.
 	 */
-	Class<? extends PartSerializer> serializer() default UrlEncodingSerializer.class;
+	Class<? extends PartSerializer> serializer() default PartSerializer.class;
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/remoteable/Path.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/Path.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/Path.java
index 919615e..3f5874d 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/Path.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/Path.java
@@ -17,7 +17,6 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
-import org.apache.juneau.annotation.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.urlencoding.*;
 
@@ -29,21 +28,28 @@ import org.apache.juneau.urlencoding.*;
  * 	<ja>@Remoteable</ja>(path=<js>"/myproxy"</js>)
  * 	<jk>public interface</jk> MyProxy {
  *
- * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod1/{foo}"</js>)
- * 		String myProxyMethod1(<ja>@Path</ja>(<js>"foo"</js>)</ja> String foo);
+ * 		<jc>// Explicit names specified for path parameters.</jc>
+ * 		<jc>// pojo will be converted to UON notation (unless plain-text parts enabled).</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod1/{foo}/{bar}"</js>)
+ * 		String myProxyMethod1(<ja>@Path</ja>(<js>"foo"</js>)</ja> String foo, <ja>@Path</ja>(<js>"bar"</js>)</ja> MyPojo pojo);
+ *
+ * 		<jc>// Multiple values pulled from a NameValuePairs object.</jc>
+ * 		<jc>// Same as @Path("*").</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod2/{foo}/{bar}/{baz}"</js>)
+ * 		String myProxyMethod2(<ja>@Path</ja> NameValuePairs nameValuePairs);
+ *
+ * 		<jc>// Multiple values pulled from a Map.</jc>
+ * 		<jc>// Same as @Path("*").</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod3/{foo}/{bar}/{baz}"</js>)
+ * 		String myProxyMethod3(<ja>@Path</ja> Map&lt;String,Object&gt; map);
+ *
+ * 		<jc>// Multiple values pulled from a bean.</jc>
+ * 		<jc>// Same as @Path("*").</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod4/{foo}/{bar}/{baz}"</js>)
+ * 		String myProxyMethod4(<ja>@Path</ja> MyBean myBean);
  * 	}
  * </p>
  * <p>
- * The argument can be any of the following types:
- * <ul class='spaced-list'>
- * 	<li><code>NameValuePairs</code> - Individual name-value pairs.
- * 	<li>Any serializable POJO - Converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * 	<li><code>Map&lt;String,Object&gt;</code> - Individual name-value pairs.
- * 		Values are converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * 	<li>A bean - Individual name-value pairs.
- * 		Values are converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * </ul>
- * <p>
  * The annotation can also be applied to a bean property field or getter when the argument is annotated with
  *  {@link RequestBean @RequestBean}:
  * <p>
@@ -52,20 +58,52 @@ import org.apache.juneau.urlencoding.*;
  * 	<ja>@Remoteable</ja>(path=<js>"/myproxy"</js>)
  * 	<jk>public interface</jk> MyProxy {
  *
- * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod1/{foo}"</js>)
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod/{foo}/{bar}/{baz}"</js>)
  * 		String myProxyMethod(<ja>@RequestBean</ja> MyRequestBean bean);
  * 	}
  *
  * 	<jk>public interface</jk> MyRequestBean {
+ *
+ * 		<jc>// Name explicitly specified.</jc>
+ * 		<ja>@Path</ja>(<js>"foo"</js>)
+ * 		String getX();
+ *
+ * 		<jc>// Name inherited from bean property.</jc>
+ * 		<jc>// Same as @Path("bar")</jc>
+ * 		<ja>@Path</ja>
+ * 		String getBar();
+ *
+ * 		<jc>// Name inherited from bean property.</jc>
+ * 		<jc>// Same as @Path("baz")</jc>
+ * 		<ja>@Path</ja>
+ * 		<ja>@BeanProperty</ja>(<js>"baz"</js>)
+ * 		String getY();
+ *
+ * 		<jc>// Multiple values pulled from NameValuePairs object.</jc>
+ * 		<jc>// Same as @Path("*")</jc>
+ * 		<ja>@Path</ja>
+ * 		NameValuePairs getNameValuePairs();
+ *
+ * 		<jc>// Multiple values pulled from Map.</jc>
+ * 		<jc>// Same as @Path("*")</jc>
  * 		<ja>@Path</ja>
- * 		String getFoo();
+ * 	 	Map&lt;String,Object&gt; getMap();
+ *
+ * 		<jc>// Multiple values pulled from bean.</jc>
+ * 		<jc>// Same as @Path("*")</jc>
+ * 		<ja>@Path</ja>
+ * 	 	MyBean getMyBean();
  * 	}
  * </p>
  * <p>
- * When used in a request bean, the {@link #value()} can be used to override the path variable name.
- * It can also be overridden via the {@link BeanProperty#name @BeanProperty.name()} annotation.
- * A name of <js>"*"</js> where the bean property value is a map or bean will cause the individual entries in the
- * map or bean to be expanded to path variables.
+ * The {@link #name()} and {@link #value()} elements are synonyms for specifying the path variable name.  Only one should be used.
+ * <br>The following annotations are fully equivalent:
+ * <p>
+ * <p class='bcode'>
+ * 	<ja>@Path</ja>(name=<js>"foo"</js>)
+ *
+ * 	<ja>@Path</ja>(<js>"foo"</js>)
+ * </p>
  */
 @Documented
 @Target({PARAMETER,FIELD,METHOD})
@@ -76,22 +114,62 @@ public @interface Path {
 	/**
 	 * The path parameter name.
 	 * <p>
-	 * A value of <js>"*"</js> indicates the value should be serialized as name/value pairs and is applicable
-	 * for the following data types:
-	 * <ul>
-	 * 	<li><code>NameValuePairs</code>
-	 * 	<li><code>Map&lt;String,Object&gt;</code>
-	 * 	<li>A bean
+	 * Note that {@link #name()} and {@link #value()} are synonyms.
+	 * <p>
+	 * The value should be either <js>"*"</js> to represent multiple name/value pairs, or a label that defines the
+	 * 	path variable name.
+	 * <p>
+	 * A blank value (the default) has the following behavior:
+	 * <ul class='spaced-list'>
+	 * 	<li>If the data type is <code>NameValuePairs</code>, <code>Map</code>, or a bean,
+	 * 		then it's the equivalent to <js>"*"</js> which will cause the value to be treated as name/value pairs.
+	 * 		<h6 class='figure'>Example:</h6>
+	 * 		<p class='bcode'>
+	 * 	<jc>// When used on a remote method parameter</jc>
+	 * 	<ja>@Remoteable</ja>(path=<js>"/myproxy"</js>)
+	 * 	<jk>public interface</jk> MyProxy {
+	 *
+	 * 		<jc>// Equivalent to @Path("*")</jc>
+	 * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod/{foo}/{bar}"</js>)
+	 * 		String myProxyMethod1(<ja>@FormData</ja> Map&lt;String,Object&gt; pathVars);
+	 * 	}
+	 *
+	 * 	<jc>// When used on a request bean method</jc>
+	 * 	<jk>public interface</jk> MyRequestBean {
+	 *
+	 * 		<jc>// Equivalent to @Path("*")</jc>
+	 * 		<ja>@Path</ja>
+	 * 		Map&lt;String,Object&gt; getPathVars();
+	 * 	}
+	 * 		</p>
+	 *			<br>
+	 * 	<li>If used on a request bean method, uses the bean property name.
+	 * 		<h6 class='figure'>Example:</h6>
+	 * 		<p class='bcode'>
+	 * 	<jk>public interface</jk> MyRequestBean {
+	 *
+	 * 		<jc>// Equivalent to @Path("foo")</jc>
+	 * 		<ja>@Path</ja>
+	 * 		String getFoo();
+	 * 	}
 	 * </ul>
 	 */
-	String value() default "*";
+	String name() default "";
+
+	/**
+	 * A synonym for {@link #name()}.
+	 * <p>
+	 * Allows you to use shortened notation if you're only specifying the name.
+	 */
+	String value() default "";
 
 	/**
 	 * Specifies the {@link PartSerializer} class used for serializing values to strings.
 	 * <p>
-	 * The default serializer converters values to UON notation.
+	 * The default value defaults to the using the part serializer defined on the {@link RequestBean} annotation,
+	 * 	then on the client which by default is {@link UrlEncodingSerializer}.
 	 * <p>
 	 * This annotation is provided to allow values to be custom serialized.
 	 */
-	Class<? extends PartSerializer> serializer() default UrlEncodingSerializer.class;
+	Class<? extends PartSerializer> serializer() default PartSerializer.class;
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/remoteable/Query.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/Query.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/Query.java
index 7738468..35540e5 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/Query.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/Query.java
@@ -17,7 +17,6 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
-import org.apache.juneau.annotation.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.urlencoding.*;
 
@@ -29,28 +28,38 @@ import org.apache.juneau.urlencoding.*;
  * 	<ja>@Remoteable</ja>(path=<js>"/myproxy"</js>)
  * 	<jk>public interface</jk> MyProxy {
  *
+ * 		<jc>// Explicit names specified for query parameters.</jc>
+ * 		<jc>// pojo will be converted to UON notation (unless plain-text parts enabled).</jc>
  * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod1"</js>)
  * 		String myProxyMethod1(<ja>@Query</ja>(<js>"foo"</js>)</ja> String foo, <ja>@Query</ja>(<js>"bar"</js>)</ja> MyPojo pojo);
  *
+ * 		<jc>// Multiple values pulled from a NameValuePairs object.</jc>
+ * 		<jc>// Same as @Query("*").</jc>
  * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod2"</js>)
- * 		String myProxyMethod2(<ja>@Query</ja> Map&lt;String,Object&gt; query);
+ * 		String myProxyMethod2(<ja>@Query</ja> NameValuePairs nameValuePairs);
  *
+ * 		<jc>// Multiple values pulled from a Map.</jc>
+ * 		<jc>// Same as @Query("*").</jc>
  * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod3"</js>)
- * 		String myProxyMethod2(<ja>@Query</ja> String queryString);
+ * 		String myProxyMethod3(<ja>@Query</ja> Map&lt;String,Object&gt; map);
+ *
+ * 		<jc>// Multiple values pulled from a bean.</jc>
+ * 		<jc>// Same as @Query("*").</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod4"</js>)
+ * 		String myProxyMethod4(<ja>@Query</ja> MyBean myBean);
+ *
+ * 		<jc>// An entire query string as a String.</jc>
+ * 		<jc>// Same as @FQuery("*").</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod5"</js>)
+ * 		String myProxyMethod5(<ja>@Query</ja> String string);
+ *
+ * 		<jc>// An entire query string as a Reader.</jc>
+ * 		<jc>// Same as @Query("*").</jc>
+ * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod6"</js>)
+ * 		String myProxyMethod6(<ja>@Query</ja> Reader reader);
  * 	}
  * </p>
  * <p>
- * The argument can be any of the following types:
- * <ul class='spaced-list'>
- * 	<li><code>NameValuePairs</code> - Individual name-value pairs.
- * 	<li>Any serializable POJO - Converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * 	<li><code>Map&lt;String,Object&gt;</code> - Individual name-value pairs.
- * 		Values are converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * 	<li>A bean - Individual name-value pairs.
- * 		Values are converted to text using {@link UrlEncodingSerializer#serialize(PartType,Object)}.
- * 	<li>{@link String} - Treated as a query string.
- * </ul>
- * <p>
  * The annotation can also be applied to a bean property field or getter when the argument is annotated with
  *  {@link RequestBean @RequestBean}:
  * <p>
@@ -64,18 +73,52 @@ import org.apache.juneau.urlencoding.*;
  * 	}
  *
  * 	<jk>public interface</jk> MyRequestBean {
+ *
+ * 		<jc>// Name explicitly specified.</jc>
+ * 		<ja>@Query</ja>(<js>"foo"</js>)
+ * 		String getX();
+ *
+ * 		<jc>// Name inherited from bean property.</jc>
+ * 		<jc>// Same as @Query("bar")</jc>
+ * 		<ja>@Query</ja>
+ * 		String getBar();
+ *
+ * 		<jc>// Name inherited from bean property.</jc>
+ * 		<jc>// Same as @Query("baz")</jc>
+ * 		<ja>@Query</ja>
+ * 		<ja>@BeanProperty</ja>(<js>"baz"</js>)
+ * 		String getY();
+ *
+ * 		<jc>// Multiple values pulled from NameValuePairs object.</jc>
+ * 		<jc>// Same as @Query("*")</jc>
+ * 		<ja>@Query</ja>
+ * 		NameValuePairs getNameValuePairs();
+ *
+ * 		<jc>// Multiple values pulled from Map.</jc>
+ * 		<jc>// Same as @Query("*")</jc>
+ * 		<ja>@Query</ja>
+ * 	 	Map&lt;String,Object&gt; getMap();
+ *
+ * 		<jc>// Multiple values pulled from bean.</jc>
+ * 		<jc>// Same as @Query("*")</jc>
  * 		<ja>@Query</ja>
- * 		String getFoo();
+ * 	 	MyBean getMyBean();
  *
+ * 		<jc>// An entire query string as a Reader.</jc>
+ * 		<jc>// Same as @Query("*")</jc>
  * 		<ja>@Query</ja>
- * 		MyPojo getBar();
+ * 		Reader getReader();
  * 	}
  * </p>
  * <p>
- * When used in a request bean, the {@link #value()} can be used to override the query parameter name.
- * It can also be overridden via the {@link BeanProperty#name @BeanProperty.name()} annotation.
- * A name of <js>"*"</js> where the bean property value is a map or bean will cause the individual entries in the
- * map or bean to be expanded to query parameters.
+ * The {@link #name()} and {@link #value()} elements are synonyms for specifying the parameter name.  Only one should be used.
+ * <br>The following annotations are fully equivalent:
+ * <p>
+ * <p class='bcode'>
+ * 	<ja>@Query</ja>(name=<js>"foo"</js>)
+ *
+ * 	<ja>@Query</ja>(<js>"foo"</js>)
+ * </p>
  */
 @Documented
 @Target({PARAMETER,FIELD,METHOD})
@@ -86,23 +129,71 @@ public @interface Query {
 	/**
 	 * The query parameter name.
 	 * <p>
-	 * A value of <js>"*"</js> indicates the value should be serialized as name/value pairs and is applicable
-	 * for the following data types:
-	 * <ul>
-	 * 	<li><code>String</code> - A complete query string.
-	 * 	<li><code>NameValuePairs</code>
-	 * 	<li><code>Map&lt;String,Object&gt;</code>
-	 * 	<li>A bean
+	 * Note that {@link #name()} and {@link #value()} are synonyms.
+	 * <p>
+	 * The value should be either <js>"*"</js> to represent multiple name/value pairs, or a label that defines the
+	 * 	query parameter name.
+	 * <p>
+	 * A blank value (the default) has the following behavior:
+	 * <ul class='spaced-list'>
+	 * 	<li>If the data type is <code>NameValuePairs</code>, <code>Map</code>, or a bean,
+	 * 		then it's the equivalent to <js>"*"</js> which will cause the value to be serialized as name/value pairs.
+	 * 		<h6 class='figure'>Example:</h6>
+	 * 		<p class='bcode'>
+	 * 	<jc>// When used on a remote method parameter</jc>
+	 * 	<ja>@Remoteable</ja>(path=<js>"/myproxy"</js>)
+	 * 	<jk>public interface</jk> MyProxy {
+	 *
+	 * 		<jc>// Equivalent to @Query("*")</jc>
+	 * 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod"</js>)
+	 * 		String myProxyMethod1(<ja>@Query</ja> Map&lt;String,Object&gt; formData);
+	 * 	}
+	 *
+	 * 	<jc>// When used on a request bean method</jc>
+	 * 	<jk>public interface</jk> MyRequestBean {
+	 *
+	 * 		<jc>// Equivalent to @Query("*")</jc>
+	 * 		<ja>@Query</ja>
+	 * 		Map&lt;String,Object&gt; getFoo();
+	 * 	}
+	 * 		</p>
+	 *			<br>
+	 * 	<li>If used on a request bean method, uses the bean property name.
+	 * 		<h6 class='figure'>Example:</h6>
+	 * 		<p class='bcode'>
+	 * 	<jk>public interface</jk> MyRequestBean {
+	 *
+	 * 		<jc>// Equivalent to @Query("foo")</jc>
+	 * 		<ja>@Query</ja>
+	 * 		String getFoo();
+	 * 	}
+	 * 		</p>
+	 * 	</ul>
 	 * </ul>
 	 */
-	String value() default "*";
+	String name() default "";
+
+	/**
+	 * A synonym for {@link #name()}.
+	 * <p>
+	 * Allows you to use shortened notation if you're only specifying the name.
+	 */
+	String value() default "";
+
+	/**
+	 * Skips this value if it's an empty string or empty collection/array.
+	 * <p>
+	 * Note that <jk>null</jk> values are already ignored.
+	 */
+	boolean skipIfEmpty() default false;
 
 	/**
 	 * Specifies the {@link PartSerializer} class used for serializing values to strings.
 	 * <p>
-	 * The default serializer converters values to UON notation.
+	 * The default value defaults to the using the part serializer defined on the {@link RequestBean} annotation,
+	 * 	then on the client which by default is {@link UrlEncodingSerializer}.
 	 * <p>
 	 * This annotation is provided to allow values to be custom serialized.
 	 */
-	Class<? extends PartSerializer> serializer() default UrlEncodingSerializer.class;
+	Class<? extends PartSerializer> serializer() default PartSerializer.class;
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/remoteable/QueryIfNE.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/QueryIfNE.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/QueryIfNE.java
index 8d38510..968c974 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/QueryIfNE.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/QueryIfNE.java
@@ -31,24 +31,23 @@ public @interface QueryIfNE {
 
 	/**
 	 * The query parameter name.
-	 * <p>
-	 * A value of <js>"*"</js> indicates the value should be serialized as name/value pairs and is applicable
-	 * for the following data types:
-	 * <ul>
-	 * 	<li><code>String</code> - A complete query string.
-	 * 	<li><code>NameValuePairs</code>
-	 * 	<li><code>Map&lt;String,Object&gt;</code>
-	 * 	<li>A bean
-	 * </ul>
+	 * @see Query#name()
+	 */
+	String name() default "";
+
+	/**
+	 * A synonym for {@link #name()}.
+	 * @see Query#value()
 	 */
-	String value() default "*";
+	String value() default "";
 
 	/**
 	 * Specifies the {@link PartSerializer} class used for serializing values to strings.
 	 * <p>
-	 * The default serializer converters values to UON notation.
+	 * The default value defaults to the using the part serializer defined on the {@link RequestBean} annotation,
+	 * 	then on the client which by default is {@link UrlEncodingSerializer}.
 	 * <p>
 	 * This annotation is provided to allow values to be custom serialized.
 	 */
-	Class<? extends PartSerializer> serializer() default UrlEncodingSerializer.class;
+	Class<? extends PartSerializer> serializer() default PartSerializer.class;
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteMethodArg.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteMethodArg.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteMethodArg.java
index ab9a44c..97a4af3 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteMethodArg.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteMethodArg.java
@@ -35,19 +35,20 @@ public class RemoteMethodArg {
 	/**
 	 * Constructor.
 	 *
-	 * @param name The argument name.  Can be blank.
+	 * @param name The argument name pulled from name().
+	 * @param name2 The argument name pulled from value().
 	 * @param index The zero-based index of the argument on the Java method.
 	 * @param skipIfNE The value is skipped if it's null/empty.
 	 * @param serializer The class to use for serializing headers, query paramters, form-data parameters, and
 	 * 	path variables.
 	 * 	If {@link UrlEncodingSerializer}, then the url-encoding serializer defined on the client will be used.
 	 */
-	protected RemoteMethodArg(String name, int index, boolean skipIfNE, Class<? extends PartSerializer> serializer) {
-		this.name = name;
+	protected RemoteMethodArg(String name, String name2, int index, boolean skipIfNE, Class<? extends PartSerializer> serializer) {
+		this.name = name.isEmpty() ? name2 : name;
 		this.index = index;
 		this.skipIfNE = skipIfNE;
 		try {
-			this.serializer = (serializer == UrlEncodingSerializer.class ? null : serializer.newInstance());
+			this.serializer = (serializer == PartSerializer.class ? null : serializer.newInstance());
 		} catch (Exception e) {
 			throw new RuntimeException(e);
 		}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
index 13b96b4..772cb4f 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/RemoteableMethodMeta.java
@@ -29,8 +29,8 @@ public class RemoteableMethodMeta {
 
 	private final String httpMethod;
 	private final String url;
-	private final RemoteMethodArg[] pathArgs, queryArgs, headerArgs, formDataArgs;
-	private final Integer[] requestBeanArgs, otherArgs;
+	private final RemoteMethodArg[] pathArgs, queryArgs, headerArgs, formDataArgs, requestBeanArgs;
+	private final Integer[] otherArgs;
 	private final Integer bodyArg;
 
 	/**
@@ -47,7 +47,7 @@ public class RemoteableMethodMeta {
 		this.queryArgs = b.queryArgs.toArray(new RemoteMethodArg[b.queryArgs.size()]);
 		this.formDataArgs = b.formDataArgs.toArray(new RemoteMethodArg[b.formDataArgs.size()]);
 		this.headerArgs = b.headerArgs.toArray(new RemoteMethodArg[b.headerArgs.size()]);
-		this.requestBeanArgs = b.requestBeanArgs.toArray(new Integer[b.requestBeanArgs.size()]);
+		this.requestBeanArgs = b.requestBeanArgs.toArray(new RemoteMethodArg[b.requestBeanArgs.size()]);
 		this.otherArgs = b.otherArgs.toArray(new Integer[b.otherArgs.size()]);
 		this.bodyArg = b.bodyArg;
 	}
@@ -58,9 +58,9 @@ public class RemoteableMethodMeta {
 			pathArgs = new LinkedList<RemoteMethodArg>(),
 			queryArgs = new LinkedList<RemoteMethodArg>(),
 			headerArgs = new LinkedList<RemoteMethodArg>(),
-			formDataArgs = new LinkedList<RemoteMethodArg>();
+			formDataArgs = new LinkedList<RemoteMethodArg>(),
+			requestBeanArgs = new LinkedList<RemoteMethodArg>();
 		private List<Integer>
-			requestBeanArgs = new LinkedList<Integer>(),
 			otherArgs = new LinkedList<Integer>();
 		private Integer bodyArg;
 
@@ -90,28 +90,28 @@ public class RemoteableMethodMeta {
 					Class<?> ca = a.annotationType();
 					if (ca == Path.class) {
 						Path p = (Path)a;
-						annotated = pathArgs.add(new RemoteMethodArg(p.value(), index, false, p.serializer()));
+						annotated = pathArgs.add(new RemoteMethodArg(p.name(), p.value(), index, false, p.serializer()));
 					} else if (ca == Query.class) {
 						Query q = (Query)a;
-						annotated = queryArgs.add(new RemoteMethodArg(q.value(), index, false, q.serializer()));
+						annotated = queryArgs.add(new RemoteMethodArg(q.name(), q.value(), index, q.skipIfEmpty(), q.serializer()));
 					} else if (ca == QueryIfNE.class) {
 						QueryIfNE q = (QueryIfNE)a;
-						annotated = queryArgs.add(new RemoteMethodArg(q.value(), index, true, q.serializer()));
+						annotated = queryArgs.add(new RemoteMethodArg(q.name(), q.value(), index, true, q.serializer()));
 					} else if (ca == FormData.class) {
 						FormData f = (FormData)a;
-						annotated = formDataArgs.add(new RemoteMethodArg(f.value(), index, false, f.serializer()));
+						annotated = formDataArgs.add(new RemoteMethodArg(f.name(), f.value(), index, f.skipIfEmpty(), f.serializer()));
 					} else if (ca == FormDataIfNE.class) {
 						FormDataIfNE f = (FormDataIfNE)a;
-						annotated = formDataArgs.add(new RemoteMethodArg(f.value(), index, true, f.serializer()));
+						annotated = formDataArgs.add(new RemoteMethodArg(f.name(), f.value(), index, true, f.serializer()));
 					} else if (ca == Header.class) {
 						Header h = (Header)a;
-						annotated = headerArgs.add(new RemoteMethodArg(h.value(), index, false, h.serializer()));
+						annotated = headerArgs.add(new RemoteMethodArg(h.name(), h.value(), index, h.skipIfEmpty(), h.serializer()));
 					} else if (ca == HeaderIfNE.class) {
 						HeaderIfNE h = (HeaderIfNE)a;
-						annotated = headerArgs.add(new RemoteMethodArg(h.value(), index, true, h.serializer()));
+						annotated = headerArgs.add(new RemoteMethodArg(h.name(), h.value(), index, true, h.serializer()));
 					} else if (ca == RequestBean.class) {
-						annotated = true;
-						requestBeanArgs.add(index);
+						RequestBean rb = (RequestBean)a;
+						annotated = requestBeanArgs.add(new RemoteMethodArg("", "", index, false, rb.serializer()));
 					} else if (ca == Body.class) {
 						annotated = true;
 						if (bodyArg == null)
@@ -182,7 +182,7 @@ public class RemoteableMethodMeta {
 	 * Returns the {@link RequestBean @RequestBean} annotated arguments on this Java method.
 	 * @return A list of zero-indexed argument indices.
 	 */
-	public Integer[] getRequestBeanArgs() {
+	public RemoteMethodArg[] getRequestBeanArgs() {
 		return requestBeanArgs;
 	}
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/remoteable/RequestBean.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/remoteable/RequestBean.java b/juneau-core/src/main/java/org/apache/juneau/remoteable/RequestBean.java
index 3da7f6c..0c18874 100644
--- a/juneau-core/src/main/java/org/apache/juneau/remoteable/RequestBean.java
+++ b/juneau-core/src/main/java/org/apache/juneau/remoteable/RequestBean.java
@@ -17,6 +17,9 @@ import static java.lang.annotation.RetentionPolicy.*;
 
 import java.lang.annotation.*;
 
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.urlencoding.*;
+
 /**
  * Annotation applied to Java method arguments of interface proxies to denote a bean with remoteable annotations.
  * <p>
@@ -82,4 +85,15 @@ import java.lang.annotation.*;
 @Target(PARAMETER)
 @Retention(RUNTIME)
 @Inherited
-public @interface RequestBean {}
+public @interface RequestBean {
+
+	/**
+	 * Specifies the {@link PartSerializer} class used for serializing values to strings.
+	 * <p>
+	 * The default value defaults to the using the part serializer defined on the client which by default is
+	 * 	{@link UrlEncodingSerializer}.
+	 * <p>
+	 * This annotation is provided to allow values to be custom serialized.
+	 */
+	Class<? extends PartSerializer> serializer() default PartSerializer.class;
+}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/serializer/PartSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/serializer/PartSerializer.java b/juneau-core/src/main/java/org/apache/juneau/serializer/PartSerializer.java
index 0063b9e..37d0fc5 100644
--- a/juneau-core/src/main/java/org/apache/juneau/serializer/PartSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/serializer/PartSerializer.java
@@ -31,6 +31,7 @@ import org.apache.juneau.urlencoding.*;
  * 	<li>{@link Header#serializer()}
  * 	<li>{@link HeaderIfNE#serializer()}
  * 	<li>{@link Path#serializer()}
+ * 	<li>{@link RequestBean#serializer()}
  * 	<li><code>RestClientBuilder.partSerializer(Class)</code>
  * </ul>
  * <p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializer.java b/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializer.java
index b358920..8eed75b 100644
--- a/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializer.java
@@ -204,17 +204,16 @@ public class UonSerializer extends WriterSerializer {
 	 * @param eType The expected type of the object if this is a bean property.
 	 * @param attrName The bean property name if this is a bean property.  <jk>null</jk> if this isn't a bean property being serialized.
 	 * @param pMeta The bean property metadata.
-	 * @param plainTextParams <jk>true</jk> if this is a top level parameter key or value and paramFormat is PLAINTEXT.
 	 *
 	 * @return The same writer passed in.
 	 * @throws Exception
 	 */
 	@SuppressWarnings({ "rawtypes", "unchecked" })
 	protected SerializerWriter serializeAnything(UonSerializerSession session, UonWriter out, Object o, ClassMeta<?> eType,
-			String attrName, BeanPropertyMeta pMeta, boolean plainTextParams) throws Exception {
+			String attrName, BeanPropertyMeta pMeta) throws Exception {
 
 		if (o == null) {
-			out.appendObject(null, false, plainTextParams);
+			out.appendObject(null, false);
 			return out;
 		}
 
@@ -249,7 +248,7 @@ public class UonSerializer extends WriterSerializer {
 
 		// '\0' characters are considered null.
 		if (o == null || (sType.isChar() && ((Character)o).charValue() == 0))
-			out.appendObject(null, false, plainTextParams);
+			out.appendObject(null, false);
 		else if (sType.isBoolean())
 			out.appendBoolean(o);
 		else if (sType.isNumber())
@@ -271,7 +270,7 @@ public class UonSerializer extends WriterSerializer {
 			serializeCollection(session, out, toList(sType.getInnerClass(), o), eType);
 		}
 		else {
-			out.appendObject(o, false, plainTextParams);
+			out.appendObject(o, false);
 		}
 
 		if (! isRecursion)
@@ -287,7 +286,9 @@ public class UonSerializer extends WriterSerializer {
 		ClassMeta<?> keyType = type.getKeyType(), valueType = type.getValueType();
 
 		int depth = session.getIndent();
-		out.append('(');
+
+		if (! session.isPlainTextParams())
+			out.append('(');
 
 		Iterator mapEntries = m.entrySet().iterator();
 
@@ -295,15 +296,17 @@ public class UonSerializer extends WriterSerializer {
 			Map.Entry e = (Map.Entry) mapEntries.next();
 			Object value = e.getValue();
 			Object key = session.generalize(e.getKey(), keyType);
-			out.cr(depth).appendObject(key, false, false).append('=');
-			serializeAnything(session, out, value, valueType, (key == null ? null : session.toString(key)), null, false);
+			out.cr(depth).appendObject(key, false).append('=');
+			serializeAnything(session, out, value, valueType, (key == null ? null : session.toString(key)), null);
 			if (mapEntries.hasNext())
 				out.append(',');
 		}
 
 		if (m.size() > 0)
 			out.cr(depth-1);
-		out.append(')');
+
+		if (! session.isPlainTextParams())
+			out.append(')');
 
 		return out;
 	}
@@ -311,7 +314,8 @@ public class UonSerializer extends WriterSerializer {
 	private SerializerWriter serializeBeanMap(UonSerializerSession session, UonWriter out, BeanMap<?> m, String typeName) throws Exception {
 		int depth = session.getIndent();
 
-		out.append('(');
+		if (! session.isPlainTextParams())
+			out.append('(');
 
 		boolean addComma = false;
 
@@ -331,16 +335,17 @@ public class UonSerializer extends WriterSerializer {
 			if (addComma)
 				out.append(',');
 
-			out.cr(depth).appendObject(key, false, false).append('=');
+			out.cr(depth).appendObject(key, false).append('=');
 
-			serializeAnything(session, out, value, cMeta, key, pMeta, false);
+			serializeAnything(session, out, value, cMeta, key, pMeta);
 
 			addComma = true;
 		}
 
 		if (m.size() > 0)
 			out.cr(depth-1);
-		out.append(')');
+		if (! session.isPlainTextParams())
+			out.append(')');
 
 		return out;
 	}
@@ -352,20 +357,22 @@ public class UonSerializer extends WriterSerializer {
 
 		c = session.sort(c);
 
-		out.append('@').append('(');
+		if (! session.isPlainTextParams())
+			out.append('@').append('(');
 
 		int depth = session.getIndent();
 
 		for (Iterator i = c.iterator(); i.hasNext();) {
 			out.cr(depth);
-			serializeAnything(session, out, i.next(), elementType, "<iterator>", null, false);
+			serializeAnything(session, out, i.next(), elementType, "<iterator>", null);
 			if (i.hasNext())
 				out.append(',');
 		}
 
 		if (c.size() > 0)
 			out.cr(depth-1);
-		out.append(')');
+		if (! session.isPlainTextParams())
+			out.append(')');
 
 		return out;
 	}
@@ -383,6 +390,6 @@ public class UonSerializer extends WriterSerializer {
 	@Override /* Serializer */
 	protected void doSerialize(SerializerSession session, Object o) throws Exception {
 		UonSerializerSession s = (UonSerializerSession)session;
-		serializeAnything(s, s.getWriter(), o, s.getExpectedRootType(o), "root", null, false);
+		serializeAnything(s, s.getWriter(), o, s.getExpectedRootType(o), "root", null);
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerContext.java b/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerContext.java
index b9ce464..ab2f931 100644
--- a/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerContext.java
+++ b/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerContext.java
@@ -71,10 +71,38 @@ public class UonSerializerContext extends SerializerContext {
 	 */
 	public static final String UON_addBeanTypeProperties = "UonSerializer.addBeanTypeProperties";
 
+	/**
+	 * <b>Configuration property:</b>  Format to use for query/form-data/header values.
+	 * <p>
+	 * <ul>
+	 * 	<li><b>Name:</b> <js>"UrlEncodingSerializer.paramFormat"</js>
+	 * 	<li><b>Data type:</b> <code>String</code>
+	 * 	<li><b>Default:</b> <js>"UON"</js>
+	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
+	 * </ul>
+	 * <p>
+	 * Specifies the format to use for URL GET parameter keys and values.
+	 * <p>
+	 * The possible values are:
+	 * <ul>
+	 * 	<li><js>"UON"</js> (default) - Use UON notation for values.
+	 * 		<br>String values such as <js>"(foo='bar')"</js> will end up being quoted and escaped to <js>"'(foo=bar~'baz~')'"</js>.
+	 * 		<br>Boolean strings (<js>"true"</js>/<js>"false"</js>) and numeric values (<js>"123"</js>) will also end up
+	 * 			quoted (<js>"'true'"</js>, <js>"'false'"</js>, <js>"'123'"</js>.
+	 * 	<li><js>"PLAINTEXT"</js> (default) - Serialize as plain text.
+	 * 		<br>Strings will never be quoted or escaped.
+	 * 		<br>Note that this can cause errors during parsing if you're using the URL-encoding parser to parse
+	 * 		the results since UON constructs won't be differentiatable.
+	 * 		<br>However, this is not an issue if you're simply creating queries or form posts against 3rd-party interfaces.
+	 * </ul>
+	 */
+	public static final String UON_paramFormat = "UonSerializer.paramFormat";
+
 
 	final boolean
 		encodeChars,
-		addBeanTypeProperties;
+		addBeanTypeProperties,
+		plainTextParams;
 
 	/**
 	 * Constructor.
@@ -87,6 +115,7 @@ public class UonSerializerContext extends SerializerContext {
 		super(ps);
 		encodeChars = ps.getProperty(UON_encodeChars, boolean.class, false);
 		addBeanTypeProperties = ps.getProperty(UON_addBeanTypeProperties, boolean.class, ps.getProperty(SERIALIZER_addBeanTypeProperties, boolean.class, true));
+		plainTextParams = ps.getProperty(UON_paramFormat, String.class, "UON").equals("PLAINTEXT");
 	}
 
 	@Override /* Context */
@@ -95,6 +124,15 @@ public class UonSerializerContext extends SerializerContext {
 			.append("UonSerializerContext", new ObjectMap()
 				.append("encodeChars", encodeChars)
 				.append("addBeanTypeProperties", addBeanTypeProperties)
+				.append("plainTextParams", plainTextParams)
 			);
 	}
+
+	/**
+	 * Returns <jk>true</jk> if the {@link UonSerializerContext#UON_paramFormat} is <js>"PLAINTEXT"</js>.
+	 * @return <jk>true</jk> if the {@link UonSerializerContext#UON_paramFormat} is <js>"PLAINTEXT"</js>.
+	 */
+	public boolean plainTextParams() {
+		return plainTextParams;
+	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
index e9f9659..b7c6c66 100644
--- a/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/uon/UonSerializerSession.java
@@ -32,7 +32,8 @@ public class UonSerializerSession extends SerializerSession {
 
 	private final boolean
 		encodeChars,
-		addBeanTypeProperties;
+		addBeanTypeProperties,
+		plainTextParams;
 
 	/**
 	 * Create a new session using properties specified in the context.
@@ -57,9 +58,11 @@ public class UonSerializerSession extends SerializerSession {
 		if (op == null || op.isEmpty()) {
 			encodeChars = encode == null ? ctx.encodeChars : encode;
 			addBeanTypeProperties = ctx.addBeanTypeProperties;
+			plainTextParams = ctx.plainTextParams;
 		} else {
 			encodeChars = encode == null ? op.getBoolean(UON_encodeChars, ctx.encodeChars) : encode;
 			addBeanTypeProperties = op.getBoolean(MSGPACK_addBeanTypeProperties, ctx.addBeanTypeProperties);
+			plainTextParams = op.getString(UonSerializerContext.UON_paramFormat, "UON").equals("PLAINTEXT");
 		}
 	}
 
@@ -82,11 +85,19 @@ public class UonSerializerSession extends SerializerSession {
 		return addBeanTypeProperties;
 	}
 
+	/**
+	 * Returns <jk>true</jk> if the {@link UonSerializerContext#UON_paramFormat} is <js>"PLAINTEXT"</js>.
+	 * @return <jk>true</jk> if the {@link UonSerializerContext#UON_paramFormat} is <js>"PLAINTEXT"</js>.
+	 */
+	public boolean isPlainTextParams() {
+		return plainTextParams;
+	}
+
 	@Override /* SerializerSession */
 	public final UonWriter getWriter() throws Exception {
 		Object output = getOutput();
 		if (output instanceof UonWriter)
 			return (UonWriter)output;
-		return new UonWriter(this, super.getWriter(), isUseWhitespace(), isEncodeChars(), isTrimStrings(), getUriResolver());
+		return new UonWriter(this, super.getWriter(), isUseWhitespace(), isEncodeChars(), isTrimStrings(), isPlainTextParams(), getUriResolver());
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/uon/UonWriter.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/uon/UonWriter.java b/juneau-core/src/main/java/org/apache/juneau/uon/UonWriter.java
index 2844e62..1aafc74 100644
--- a/juneau-core/src/main/java/org/apache/juneau/uon/UonWriter.java
+++ b/juneau-core/src/main/java/org/apache/juneau/uon/UonWriter.java
@@ -29,7 +29,7 @@ import org.apache.juneau.serializer.*;
 public final class UonWriter extends SerializerWriter {
 
 	private final UonSerializerSession session;
-	private final boolean encodeChars;
+	private final boolean encodeChars, plainTextParams;
 
 	// Characters that do not need to be URL-encoded in strings.
 	private static final AsciiSet unencodedChars = new AsciiSet("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789;/?:@-_.!*'$(),~=");
@@ -53,12 +53,14 @@ public final class UonWriter extends SerializerWriter {
 	 * @param useWhitespace If <jk>true</jk>, tabs will be used in output.
 	 * @param encodeChars If <jk>true</jk>, special characters should be encoded.
 	 * @param trimStrings If <jk>true</jk>, strings should be trimmed before they're serialized.
+	 * @param plainTextParams If <jk>true</jk>, don't use UON notation for values.
 	 * @param uriResolver The URI resolver for resolving URIs to absolute or root-relative form.
 	 */
-	protected UonWriter(UonSerializerSession session, Writer out, boolean useWhitespace, boolean encodeChars, boolean trimStrings, UriResolver uriResolver) {
+	protected UonWriter(UonSerializerSession session, Writer out, boolean useWhitespace, boolean encodeChars, boolean trimStrings, boolean plainTextParams, UriResolver uriResolver) {
 		super(out, useWhitespace, trimStrings, '\'', uriResolver);
 		this.session = session;
 		this.encodeChars = encodeChars;
+		this.plainTextParams = plainTextParams;
 	}
 
 	/**
@@ -66,11 +68,10 @@ public final class UonWriter extends SerializerWriter {
 	 *
 	 * @param o The object being serialized.
 	 * @param isTopAttrName If this is a top-level attribute name we're serializing.
-	 * @param plainTextParams This is a top-level name or parameter we're serializing and the parameter format is PLAINTEXT.
 	 * @return This object (for method chaining).
 	 * @throws IOException Should never happen.
 	 */
-	public final UonWriter appendObject(Object o, boolean isTopAttrName, boolean plainTextParams) throws IOException {
+	public final UonWriter appendObject(Object o, boolean isTopAttrName) throws IOException {
 
 		if (o instanceof Boolean)
 			return appendBoolean(o);
@@ -164,7 +165,7 @@ public final class UonWriter extends SerializerWriter {
 	 */
 	@Override
 	public SerializerWriter appendUri(Object uri) throws IOException {
-		return appendObject(uriResolver.resolve(uri), false, false);
+		return appendObject(uriResolver.resolve(uri), false);
 	}
 
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/uon/package.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/uon/package.html b/juneau-core/src/main/java/org/apache/juneau/uon/package.html
index 1794466..440f5b2 100644
--- a/juneau-core/src/main/java/org/apache/juneau/uon/package.html
+++ b/juneau-core/src/main/java/org/apache/juneau/uon/package.html
@@ -467,12 +467,12 @@
 		<p>
 			Another useful feature is the {@link org.apache.juneau.annotation.Bean#propertyNamer()} annotation that allows you to plug in your own
 				logic for determining bean property names.<br>
-			The {@link org.apache.juneau.PropertyNamerDashedLC} is an example of an alternate property namer.
+			The {@link org.apache.juneau.PropertyNamerDLC} is an example of an alternate property namer.
 			It converts bean property names to lowercase-dashed format.
 		</p>
 		<h6 class='figure'>Example:</h6>
 		<p class='bcode'>	
-	<ja>@Bean</ja>(propertyNamer=PropertyNamerDashedLC.<jk>class</jk>)
+	<ja>@Bean</ja>(propertyNamer=PropertyNamerDLC.<jk>class</jk>)
 	<jk>public class</jk> Person {
 		...
 		</p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
index 2ab697a..df35f9a 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
@@ -137,6 +137,9 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 	/** Reusable instance of {@link UrlEncodingSerializer}, all default settings. */
 	public static final UrlEncodingSerializer DEFAULT = new UrlEncodingSerializer(PropertyStore.create());
 
+	/** Reusable instance of {@link UrlEncodingSerializer.PlainText}. */
+	public static final UrlEncodingSerializer DEFAULT_PLAINTEXT = new PlainText(PropertyStore.create());
+
 	/** Reusable instance of {@link UrlEncodingSerializer.Expanded}. */
 	public static final UrlEncodingSerializer DEFAULT_EXPANDED = new Expanded(PropertyStore.create());
 
@@ -182,6 +185,24 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 		}
 	}
 
+	/**
+	 * Equivalent to <code><jk>new</jk> UrlEncodingSerializerBuilder().plainTextParts().build();</code>.
+	 */
+	public static class PlainText extends UrlEncodingSerializer {
+
+		/**
+		 * Constructor.
+		 * @param propertyStore The property store containing all the settings for this object.
+		 */
+		public PlainText(PropertyStore propertyStore) {
+			super(propertyStore);
+		}
+
+		@Override /* CoreObject */
+		protected ObjectMap getOverrideProperties() {
+			return super.getOverrideProperties().append(UonSerializerContext.UON_paramFormat, "PLAINTEXT");
+		}
+	}
 
 	private final UrlEncodingSerializerContext ctx;
 
@@ -247,7 +268,7 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 			// All other types can't be serialized as key/value pairs, so we create a
 			// mock key/value pair with a "_value" key.
 			out.append("_value=");
-			super.serializeAnything(session, out, o, null, null, null, session.plainTextParams());
+			super.serializeAnything(session, out, o, null, null, null);
 		}
 
 		session.pop();
@@ -278,7 +299,6 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 	@SuppressWarnings({ "rawtypes", "unchecked" })
 	private SerializerWriter serializeMap(UrlEncodingSerializerSession session, UonWriter out, Map m, ClassMeta<?> type) throws Exception {
 
-		boolean plainTextParams = session.plainTextParams();
 		m = session.sort(m);
 
 		ClassMeta<?> keyType = type.getKeyType(), valueType = type.getValueType();
@@ -295,15 +315,15 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 				while (i.hasNext()) {
 					if (addAmp)
 						out.cr(depth).append('&');
-					out.appendObject(key, true, plainTextParams).append('=');
-					super.serializeAnything(session, out, i.next(), null, (key == null ? null : key.toString()), null, plainTextParams);
+					out.appendObject(key, true).append('=');
+					super.serializeAnything(session, out, i.next(), null, (key == null ? null : key.toString()), null);
 					addAmp = true;
 				}
 			} else {
 				if (addAmp)
 					out.cr(depth).append('&');
-				out.appendObject(key, true, plainTextParams).append('=');
-				super.serializeAnything(session, out, value, valueType, (key == null ? null : key.toString()), null, plainTextParams);
+				out.appendObject(key, true).append('=');
+				super.serializeAnything(session, out, value, valueType, (key == null ? null : key.toString()), null);
 				addAmp = true;
 			}
 		}
@@ -323,7 +343,7 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 			if (addAmp)
 				out.cr(depth).append('&');
 			out.append(e.getKey()).append('=');
-			super.serializeAnything(session, out, e.getValue(), valueType, null, null, session.plainTextParams());
+			super.serializeAnything(session, out, e.getValue(), valueType, null, null);
 			addAmp = true;
 		}
 
@@ -333,7 +353,6 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 	@SuppressWarnings({ "rawtypes" })
 	private SerializerWriter serializeBeanMap(UrlEncodingSerializerSession session, UonWriter out, BeanMap<?> m, String typeName) throws Exception {
 		int depth = session.getIndent();
-		boolean plainTextParams = session.plainTextParams();
 
 		boolean addAmp = false;
 
@@ -358,9 +377,9 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 					if (addAmp)
 						out.cr(depth).append('&');
 
-					out.appendObject(key, true, plainTextParams).append('=');
+					out.appendObject(key, true).append('=');
 
-					super.serializeAnything(session, out, i.next(), cMeta.getElementType(), key, pMeta, plainTextParams);
+					super.serializeAnything(session, out, i.next(), cMeta.getElementType(), key, pMeta);
 
 					addAmp = true;
 				}
@@ -368,9 +387,9 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 				if (addAmp)
 					out.cr(depth).append('&');
 
-				out.appendObject(key, true, plainTextParams).append('=');
+				out.appendObject(key, true).append('=');
 
-				super.serializeAnything(session, out, value, cMeta, key, pMeta, plainTextParams);
+				super.serializeAnything(session, out, value, cMeta, key, pMeta);
 
 				addAmp = true;
 			}
@@ -405,8 +424,8 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ
 					return o.toString();
 				if (cm.isCharSequence()) {
 					String s = o.toString();
-					boolean ptt = (plainTextParams != null ? plainTextParams : ctx.plainTextParams);
-					if (ptt || ! UonUtils.needsQuotes(s))
+					boolean ptt = (plainTextParams != null ? plainTextParams : ctx.plainTextParams());
+					if (ptt || s.isEmpty() || ! UonUtils.needsQuotes(s))
 						return (urlEncode ? StringUtils.urlEncode(s) : s);
 				}
 			}

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerBuilder.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerBuilder.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerBuilder.java
index 7c79631..e7ff61e 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerBuilder.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerBuilder.java
@@ -124,17 +124,17 @@ public class UrlEncodingSerializerBuilder extends UonSerializerBuilder {
 	 *
 	 * @param paramFormat The new value for this property.
 	 * @return This object (for method chaining).
-	 * @see UrlEncodingSerializerContext#URLENC_paramFormat
+	 * @see UonSerializerContext#UON_paramFormat
 	 */
 	public UrlEncodingSerializerBuilder paramFormat(String paramFormat) {
-		return property(UrlEncodingSerializerContext.URLENC_paramFormat, paramFormat);
+		return property(UonSerializerContext.UON_paramFormat, paramFormat);
 	}
 
 	/**
 	 * Shortcut for calling <code>paramFormat(<js>"PLAINTEXT"</js>)</code>.
 	 *
 	 * @return This object (for method chaining).
-	 * @see UrlEncodingSerializerContext#URLENC_paramFormat
+	 * @see UonSerializerContext#UON_paramFormat
 	 */
 	public UrlEncodingSerializerBuilder plainTextParams() {
 		return paramFormat("PLAINTEXT");

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerContext.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerContext.java
index 1894b0a..d7ff160 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerContext.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerContext.java
@@ -25,36 +25,9 @@ import org.apache.juneau.uon.*;
  */
 public class UrlEncodingSerializerContext extends UonSerializerContext {
 
-	/**
-	 * <b>Configuration property:</b>  Format to use for top-level query names and simple parameters.
-	 * <p>
-	 * <ul>
-	 * 	<li><b>Name:</b> <js>"UrlEncodingSerializer.paramFormat"</js>
-	 * 	<li><b>Data type:</b> <code>String</code>
-	 * 	<li><b>Default:</b> <js>"UON"</js>
-	 * 	<li><b>Session-overridable:</b> <jk>true</jk>
-	 * </ul>
-	 * <p>
-	 * Specifies the format to use for URL GET parameter keys and values.
-	 * <p>
-	 * The possible values are:
-	 * <ul>
-	 * 	<li><js>"UON"</js> (default) - Use UON notation for values.
-	 * 		<br>String values such as <js>"(foo='bar')"</js> will end up being quoted and escaped to <js>"'(foo=bar~'baz~')'"</js>.
-	 * 		<br>Similarly, boolean and numeric values will also end up quoted.
-	 * 	<li><js>"PLAINTEXT"</js> (default) - Serialize as plain text.
-	 * 		<br>Strings will never be quoted or escaped.
-	 * 		<br>Note that this can cause errors during parsing if you're using the URL-encoding parser to parse
-	 * 		the results since UON constructs won't be differentiatable.
-	 * 		<br>However, this is not an issue if you're simply creating queries or form posts against 3rd-party interfaces.
-	 * </ul>
-	 */
-	public static final String URLENC_paramFormat = "UrlEncodingSerializer.paramFormat";
-
 
 	final boolean
-		expandedParams,
-		plainTextParams;
+		expandedParams;
 
 	/**
 	 * Constructor.
@@ -66,7 +39,6 @@ public class UrlEncodingSerializerContext extends UonSerializerContext {
 	public UrlEncodingSerializerContext(PropertyStore ps) {
 		super(ps);
 		this.expandedParams = ps.getProperty(UrlEncodingContext.URLENC_expandedParams, boolean.class, false);
-		this.plainTextParams = ps.getProperty(UrlEncodingSerializerContext.URLENC_paramFormat, String.class, "UON").equals("PLAINTEXT");
 	}
 
 	@Override /* Context */
@@ -74,7 +46,6 @@ public class UrlEncodingSerializerContext extends UonSerializerContext {
 		return super.asMap()
 			.append("UrlEncodingSerializerContext", new ObjectMap()
 				.append("expandedParams", expandedParams)
-				.append("plainTextParams", plainTextParams)
 			);
 	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
index a7a93e3..d9c39d9 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
@@ -27,7 +27,7 @@ import org.apache.juneau.uon.*;
  */
 public class UrlEncodingSerializerSession extends UonSerializerSession {
 
-	private final boolean expandedParams, plainTextParams;
+	private final boolean expandedParams;
 
 	/**
 	 * Create a new session using properties specified in the context.
@@ -51,10 +51,8 @@ public class UrlEncodingSerializerSession extends UonSerializerSession {
 		super(ctx, encode, op, output, javaMethod, locale, timeZone, mediaType, uriContext);
 		if (op == null || op.isEmpty()) {
 			expandedParams = ctx.expandedParams;
-			plainTextParams = ctx.plainTextParams;
 		} else {
 			expandedParams = op.getBoolean(UrlEncodingContext.URLENC_expandedParams, false);
-			plainTextParams = op.getString(UrlEncodingSerializerContext.URLENC_paramFormat, "UON").equals("PLAINTEXT");
 		}
 	}
 
@@ -91,12 +89,4 @@ public class UrlEncodingSerializerSession extends UonSerializerSession {
 		}
 		return false;
 	}
-
-	/**
-	 * Returns <jk>true</jk> if the {@link UrlEncodingSerializerContext#URLENC_paramFormat} is <js>"PLAINTEXT"</js>.
-	 * @return <jk>true</jk> if the {@link UrlEncodingSerializerContext#URLENC_paramFormat} is <js>"PLAINTEXT"</js>.
-	 */
-	protected boolean plainTextParams() {
-		return plainTextParams;
-	}
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/urlencoding/package.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/package.html b/juneau-core/src/main/java/org/apache/juneau/urlencoding/package.html
index ce7f90e..88349fc 100644
--- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/package.html
+++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/package.html
@@ -467,12 +467,12 @@
 		<p>
 			Another useful feature is the {@link org.apache.juneau.annotation.Bean#propertyNamer()} annotation that allows you to plug in your own
 				logic for determining bean property names.<br>
-			The {@link org.apache.juneau.PropertyNamerDashedLC} is an example of an alternate property namer.
+			The {@link org.apache.juneau.PropertyNamerDLC} is an example of an alternate property namer.
 			It converts bean property names to lowercase-dashed format.
 		</p>
 		<h6 class='figure'>Example:</h6>
 		<p class='bcode'>	
-	<ja>@Bean</ja>(propertyNamer=PropertyNamerDashedLC.<jk>class</jk>)
+	<ja>@Bean</ja>(propertyNamer=PropertyNamerDLC.<jk>class</jk>)
 	<jk>public class</jk> Person {
 		...
 		</p>

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/93aadae1/juneau-core/src/main/java/org/apache/juneau/xml/package.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/package.html b/juneau-core/src/main/java/org/apache/juneau/xml/package.html
index 3b2647e..68257e9 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/package.html
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/package.html
@@ -2178,13 +2178,13 @@
 		<p>
 			Another useful feature is the {@link org.apache.juneau.annotation.Bean#propertyNamer()} annotation that allows you to plug in your own
 				logic for determining bean property names.<br>
-			The {@link org.apache.juneau.PropertyNamerDashedLC} is an example of an alternate property namer.
+			The {@link org.apache.juneau.PropertyNamerDLC} is an example of an alternate property namer.
 			It converts bean property names to lowercase-dashed format.
 		</p>
 		<h6 class='figure'>Example</h6>
 		<p class='bcode'>	
 	<ja>@Xml</ja>(prefix=<js>"per"</js>)
-	<ja>@Bean</ja>(typeName=<js>"person"</js>,propertyNamer=PropertyNamerDashedLC.<jk>class</jk>)
+	<ja>@Bean</ja>(typeName=<js>"person"</js>,propertyNamer=PropertyNamerDLC.<jk>class</jk>)
 	<jk>public class</jk> Person {
 		...
 		</p>