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 2020/07/06 21:44:01 UTC

[juneau] branch master updated: Docs and tests.

This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new fa12ed5  Docs and tests.
fa12ed5 is described below

commit fa12ed568d5cf68e8f4087320352868fdd901eaf
Author: JamesBognar <ja...@salesforce.com>
AuthorDate: Mon Jul 6 17:43:49 2020 -0400

    Docs and tests.
---
 .../test/java/org/apache/juneau/MaxIndentTest.java |   4 +-
 .../rttests/RoundTripPrimitiveObjectBeansTest.java |   4 +-
 .../apache/juneau/config/ConfigInterfaceTest.java  |  32 +-
 .../org/apache/juneau}/testutils/Constants.java    |   2 +-
 .../apache/juneau}/testutils/XPartSerializer.java  |   2 +-
 .../org/apache/juneau/testutils/pojos/ABean.java   |   9 +-
 .../apache/juneau/testutils/pojos/LargePojo.java   |   2 +-
 .../pojos/PrimitiveAtomicObjectsBean.java          |   6 +-
 .../testutils/pojos/PrimitiveObjectsBean.java      |   6 +-
 .../juneau/testutils/pojos/TypedBeanImpl.java      |   6 +-
 .../org/apache/juneau/testutils/pojos/XBeans.java  | 263 ++++++
 .../org/apache/juneau/http/HeaderSupplier.java     |  66 +-
 .../apache/juneau/http/NameValuePairSupplier.java  |  66 +-
 .../org/apache/juneau/http/header/BasicHeader.java |   4 +-
 .../java/org/apache/juneau/http/remote/Remote.java |  27 +-
 .../juneau/jsonschema/annotation/Schema.java       |   7 +-
 .../java/org/apache/juneau/svl/VarResolver.java    |  11 +
 juneau-doc/docs/Topics/09.juneau-rest-client.html  |  47 +-
 .../09.juneau-rest-client/01.PojoMarshalling.html  |   8 +-
 .../09.juneau-rest-client/02.RequestHeaders.html   |  42 +-
 .../03.RequestQueryParameters.html                 |  41 +-
 .../09.juneau-rest-client/04.RequestFormData.html  |  49 ++
 .../09.juneau-rest-client/05.RequestBody.html      |  27 +
 .../09.juneau-rest-client/08.ResponseBody.html     |  10 +-
 .../09.CustomCallHandlers.html                     |  29 +
 .../09.juneau-rest-client/10.Interceptors.html     |  49 +-
 .../09.juneau-rest-client/11.RestProxies.html      |  87 +-
 .../11.RestProxies/01.Remote.html                  | 136 +++-
 .../11.RestProxies/02.RemoteMethod.html            |   2 +-
 .../11.RestProxies/03.Body.html                    |  23 +-
 .../11.RestProxies/04.FormData.html                |  18 +-
 .../11.RestProxies/05.Query.html                   |  18 +-
 .../11.RestProxies/06.Header.html                  |  14 +-
 .../11.RestProxies/07.Path.html                    |  12 +-
 .../11.RestProxies/08.Request.html                 |  17 +-
 .../11.RestProxies/09.Response.html                |  13 +-
 .../11.RestProxies/10.DualPurposeInterfaces.html   |  19 +-
 .../12.LoggingAndDebugging.html                    |   9 +-
 .../13.CustomizingHttpClient.html                  |   2 +-
 .../15.Authentication/01.BASIC.html                |  14 +-
 .../15.Authentication/02.FORM.html                 |  63 +-
 .../15.Authentication/03.OIDC.html                 | 110 +--
 juneau-doc/src/main/javadoc/overview.html          | 882 ++++++++++++++-------
 .../src/main/javadoc/resources/fragments/toc.html  |   4 +-
 .../juneau/rest/test/LargePojosResource.java       |   2 +-
 .../rest/test/client/ThirdPartyProxyResource.java  |   5 +-
 .../rest/test/client/ThirdPartyProxyTest.java      |   4 +-
 .../client2/Remote_FormDataAnnotation_Test.java    |   2 +-
 .../rest/client2/Remote_HeaderAnnotation_Test.java |   2 +-
 .../rest/client2/Remote_PathAnnotation_Test.java   |   2 +-
 .../rest/client2/Remote_QueryAnnotation_Test.java  |   2 +-
 .../client2/Remote_RequestAnnotation_Test.java     |   2 +-
 .../juneau/rest/client2/RrpcInterfaceTest.java     |   4 +-
 .../juneau/rest/client/remote/RemoteMeta.java      |  25 +-
 .../org/apache/juneau/rest/client2/RestClient.java |   2 +-
 .../juneau/rest/client2/RestClientBuilder.java     |   2 +-
 .../org/apache/juneau/rest/testutils/ABean.java    |  32 -
 .../org/apache/juneau/rest/testutils/DTOs.java     | 142 ----
 .../org/apache/juneau/rest/testutils/DTOs2.java    | 143 ----
 .../juneau/rest/testutils/ImplicitSwappedPojo.java |  35 -
 .../apache/juneau/rest/testutils/SwappedPojo.java  |  20 -
 .../juneau/rest/testutils/SwappedPojoSwap.java     |  35 -
 .../org/apache/juneau/rest/testutils/TestEnum.java |  17 -
 .../apache/juneau/rest/testutils/TypedBean.java    |  17 -
 .../juneau/rest/testutils/TypedBeanImpl.java       |  26 -
 .../rest/annotation2/BodyAnnotationTest.java       |  38 +-
 .../rest/annotation2/FormDataAnnotationTest.java   |   2 +-
 .../rest/annotation2/HeaderAnnotationTest.java     |   2 +-
 .../rest/annotation2/PathAnnotationTest.java       |   2 +-
 .../annotation2/PathRemainderAnnotationTest.java   |   2 +-
 .../rest/annotation2/QueryAnnotationTest.java      |   2 +-
 .../apache/juneau/rest/testutils/TestUtils.java    |   0
 72 files changed, 1676 insertions(+), 1155 deletions(-)

diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/MaxIndentTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/MaxIndentTest.java
index 94d25fb..c8e70b6 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/MaxIndentTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/MaxIndentTest.java
@@ -236,7 +236,7 @@ public class MaxIndentTest {
 
 	public static class List1dOfBeans extends LinkedList<ABean> {
 		public List1dOfBeans init1() {
-			add(new ABean().init());
+			add(ABean.get());
 			return this;
 		}
 	}
@@ -250,7 +250,7 @@ public class MaxIndentTest {
 
 	public static class Map1dOfBeans extends LinkedHashMap<String,ABean> {
 		public Map1dOfBeans init1() {
-			put("a", new ABean().init());
+			put("a", ABean.get());
 			return this;
 		}
 	}
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/a/rttests/RoundTripPrimitiveObjectBeansTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/a/rttests/RoundTripPrimitiveObjectBeansTest.java
index 2052b21..01d7364 100755
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/a/rttests/RoundTripPrimitiveObjectBeansTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/a/rttests/RoundTripPrimitiveObjectBeansTest.java
@@ -37,7 +37,7 @@ public class RoundTripPrimitiveObjectBeansTest extends RoundTripTest {
 	//====================================================================================================
 	@Test
 	public void testPrimitiveObjectsBean() throws Exception {
-		PrimitiveObjectsBean t = new PrimitiveObjectsBean().init();
+		PrimitiveObjectsBean t = PrimitiveObjectsBean.get();
 		t = roundTrip(t, PrimitiveObjectsBean.class);
 		t = roundTrip(t, PrimitiveObjectsBean.class);
 
@@ -161,7 +161,7 @@ public class RoundTripPrimitiveObjectBeansTest extends RoundTripTest {
 		if (getSerializer() instanceof RdfSerializer)
 			return;
 
-		PrimitiveAtomicObjectsBean t = new PrimitiveAtomicObjectsBean().init();
+		PrimitiveAtomicObjectsBean t = PrimitiveAtomicObjectsBean.get();
 		t = roundTrip(t, PrimitiveAtomicObjectsBean.class);
 		t = roundTrip(t, PrimitiveAtomicObjectsBean.class);
 
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/config/ConfigInterfaceTest.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/config/ConfigInterfaceTest.java
index 12a1b4c..2b8a1a0 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/config/ConfigInterfaceTest.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/config/ConfigInterfaceTest.java
@@ -157,7 +157,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testBean() throws Exception {
-		proxy.setBean(new ABean().init());
+		proxy.setBean(ABean.get());
 		assertObject(proxy.getBean()).json().is("{a:1,b:'foo'}");
 		assertEquals("{a:1,b:'foo'}", cf.get("A/bean"));
 		assertObject(proxy.getBean()).isType(ABean.class);
@@ -165,7 +165,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testBean3dArray() throws Exception {
-		proxy.setBean3dArray(new ABean[][][]{{{new ABean().init(),null},null},null});
+		proxy.setBean3dArray(new ABean[][][]{{{ABean.get(),null},null},null});
 		assertObject(proxy.getBean3dArray()).json().is("[[[{a:1,b:'foo'},null],null],null]");
 		assertEquals("[[[{a:1,b:'foo'},null],null],null]", cf.get("A/bean3dArray"));
 		assertObject(proxy.getBean3dArray()[0][0][0]).isType(ABean.class);
@@ -173,7 +173,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testBeanList() throws Exception {
-		proxy.setBeanList(Arrays.asList(new ABean().init()));
+		proxy.setBeanList(Arrays.asList(ABean.get()));
 		assertObject(proxy.getBeanList()).json().is("[{a:1,b:'foo'}]");
 		assertEquals("[{a:1,b:'foo'}]", cf.get("A/beanList"));
 		assertObject(proxy.getBeanList().get(0)).isType(ABean.class);
@@ -181,7 +181,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testBean1d3dList() throws Exception {
-		proxy.setBean1d3dList(AList.of(new ABean[][][]{{{new ABean().init(),null},null},null},null));
+		proxy.setBean1d3dList(AList.of(new ABean[][][]{{{ABean.get(),null},null},null},null));
 		assertObject(proxy.getBean1d3dList()).json().is("[[[[{a:1,b:'foo'},null],null],null],null]");
 		assertEquals("[[[[{a:1,b:'foo'},null],null],null],null]", cf.get("A/bean1d3dList"));
 		assertObject(proxy.getBean1d3dList().get(0)[0][0][0]).isType(ABean.class);
@@ -189,7 +189,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testBeanMap() throws Exception {
-		proxy.setBeanMap(AMap.of("foo",new ABean().init()));
+		proxy.setBeanMap(AMap.of("foo",ABean.get()));
 		assertObject(proxy.getBeanMap()).json().is("{foo:{a:1,b:'foo'}}");
 		assertEquals("{foo:{a:1,b:'foo'}}", cf.get("A/beanMap"));
 		assertObject(proxy.getBeanMap().get("foo")).isType(ABean.class);
@@ -197,7 +197,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testBeanListMap() throws Exception {
-		proxy.setBeanListMap(AMap.of("foo",Arrays.asList(new ABean().init())));
+		proxy.setBeanListMap(AMap.of("foo",Arrays.asList(ABean.get())));
 		assertObject(proxy.getBeanListMap()).json().is("{foo:[{a:1,b:'foo'}]}");
 		assertEquals("{foo:[{a:1,b:'foo'}]}", cf.get("A/beanListMap"));
 		assertObject(proxy.getBeanListMap().get("foo").get(0)).isType(ABean.class);
@@ -205,7 +205,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testBean1d3dListMap() throws Exception {
-		proxy.setBean1d3dListMap(AMap.of("foo",AList.of(new ABean[][][]{{{new ABean().init(),null},null},null},null)));
+		proxy.setBean1d3dListMap(AMap.of("foo",AList.of(new ABean[][][]{{{ABean.get(),null},null},null},null)));
 		assertObject(proxy.getBean1d3dListMap()).json().is("{foo:[[[[{a:1,b:'foo'},null],null],null],null]}");
 		assertEquals("{foo:[[[[{a:1,b:'foo'},null],null],null],null]}", cf.get("A/bean1d3dListMap"));
 		assertObject(proxy.getBean1d3dListMap().get("foo").get(0)[0][0][0]).isType(ABean.class);
@@ -213,7 +213,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testBeanListMapIntegerKeys() throws Exception {
-		proxy.setBeanListMapIntegerKeys(AMap.of(1,Arrays.asList(new ABean().init())));
+		proxy.setBeanListMapIntegerKeys(AMap.of(1,Arrays.asList(ABean.get())));
 		assertObject(proxy.getBeanListMapIntegerKeys()).json().is("{'1':[{a:1,b:'foo'}]}");
 		assertEquals("{'1':[{a:1,b:'foo'}]}", cf.get("A/beanListMapIntegerKeys"));
 		assertObject(proxy.getBeanListMapIntegerKeys().get(1).get(0)).isType(ABean.class);
@@ -223,7 +223,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testTypedBean() throws Exception {
-		proxy.setTypedBean(new TypedBeanImpl().init());
+		proxy.setTypedBean(TypedBeanImpl.get());
 		assertObject(proxy.getTypedBean()).json().is("{_type:'TypedBeanImpl',a:1,b:'foo'}");
 		assertEquals("{_type:'TypedBeanImpl',a:1,b:'foo'}", cf.get("A/typedBean"));
 		assertObject(proxy.getTypedBean()).isType(TypedBeanImpl.class);
@@ -231,7 +231,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testTypedBean3dArray() throws Exception {
-		proxy.setTypedBean3dArray(new TypedBean[][][]{{{new TypedBeanImpl().init(),null},null},null});
+		proxy.setTypedBean3dArray(new TypedBean[][][]{{{TypedBeanImpl.get(),null},null},null});
 		assertObject(proxy.getTypedBean3dArray()).json().is("[[[{_type:'TypedBeanImpl',a:1,b:'foo'},null],null],null]");
 		assertEquals("[[[{_type:'TypedBeanImpl',a:1,b:'foo'},null],null],null]", cf.get("A/typedBean3dArray"));
 		assertObject(proxy.getTypedBean3dArray()[0][0][0]).isType(TypedBeanImpl.class);
@@ -239,7 +239,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testTypedBeanList() throws Exception {
-		proxy.setTypedBeanList(Arrays.asList((TypedBean)new TypedBeanImpl().init()));
+		proxy.setTypedBeanList(Arrays.asList((TypedBean)TypedBeanImpl.get()));
 		assertObject(proxy.getTypedBeanList()).json().is("[{_type:'TypedBeanImpl',a:1,b:'foo'}]");
 		assertEquals("[{_type:'TypedBeanImpl',a:1,b:'foo'}]", cf.get("A/typedBeanList"));
 		assertObject(proxy.getTypedBeanList().get(0)).isType(TypedBeanImpl.class);
@@ -247,7 +247,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testTypedBean1d3dList() throws Exception {
-		proxy.setTypedBean1d3dList(AList.of(new TypedBean[][][]{{{new TypedBeanImpl().init(),null},null},null},null));
+		proxy.setTypedBean1d3dList(AList.of(new TypedBean[][][]{{{TypedBeanImpl.get(),null},null},null},null));
 		assertObject(proxy.getTypedBean1d3dList()).json().is("[[[[{_type:'TypedBeanImpl',a:1,b:'foo'},null],null],null],null]");
 		assertEquals("[[[[{_type:'TypedBeanImpl',a:1,b:'foo'},null],null],null],null]", cf.get("A/typedBean1d3dList"));
 		assertObject(proxy.getTypedBean1d3dList().get(0)[0][0][0]).isType(TypedBeanImpl.class);
@@ -255,7 +255,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testTypedBeanMap() throws Exception {
-		proxy.setTypedBeanMap(AMap.of("foo",new TypedBeanImpl().init()));
+		proxy.setTypedBeanMap(AMap.of("foo",TypedBeanImpl.get()));
 		assertObject(proxy.getTypedBeanMap()).json().is("{foo:{_type:'TypedBeanImpl',a:1,b:'foo'}}");
 		assertEquals("{foo:{_type:'TypedBeanImpl',a:1,b:'foo'}}", cf.get("A/typedBeanMap"));
 		assertObject(proxy.getTypedBeanMap().get("foo")).isType(TypedBeanImpl.class);
@@ -263,7 +263,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testTypedBeanListMap() throws Exception {
-		proxy.setTypedBeanListMap(AMap.of("foo",Arrays.asList((TypedBean)new TypedBeanImpl().init())));
+		proxy.setTypedBeanListMap(AMap.of("foo",Arrays.asList((TypedBean)TypedBeanImpl.get())));
 		assertObject(proxy.getTypedBeanListMap()).json().is("{foo:[{_type:'TypedBeanImpl',a:1,b:'foo'}]}");
 		assertEquals("{foo:[{_type:'TypedBeanImpl',a:1,b:'foo'}]}", cf.get("A/typedBeanListMap"));
 		assertObject(proxy.getTypedBeanListMap().get("foo").get(0)).isType(TypedBeanImpl.class);
@@ -271,7 +271,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testTypedBean1d3dListMap() throws Exception {
-		proxy.setTypedBean1d3dListMap(AMap.of("foo",AList.of(new TypedBean[][][]{{{new TypedBeanImpl().init(),null},null},null},null)));
+		proxy.setTypedBean1d3dListMap(AMap.of("foo",AList.of(new TypedBean[][][]{{{TypedBeanImpl.get(),null},null},null},null)));
 		assertObject(proxy.getTypedBean1d3dListMap()).json().is("{foo:[[[[{_type:'TypedBeanImpl',a:1,b:'foo'},null],null],null],null]}");
 		assertEquals("{foo:[[[[{_type:'TypedBeanImpl',a:1,b:'foo'},null],null],null],null]}", cf.get("A/typedBean1d3dListMap"));
 		assertObject(proxy.getTypedBean1d3dListMap().get("foo").get(0)[0][0][0]).isType(TypedBeanImpl.class);
@@ -279,7 +279,7 @@ public class ConfigInterfaceTest {
 
 	@Test
 	public void testTypedBeanListMapIntegerKeys() throws Exception {
-		proxy.setTypedBeanListMapIntegerKeys(AMap.of(1,Arrays.asList((TypedBean)new TypedBeanImpl().init())));
+		proxy.setTypedBeanListMapIntegerKeys(AMap.of(1,Arrays.asList((TypedBean)TypedBeanImpl.get())));
 		assertObject(proxy.getTypedBeanListMapIntegerKeys()).json().is("{'1':[{_type:'TypedBeanImpl',a:1,b:'foo'}]}");
 		assertEquals("{'1':[{_type:'TypedBeanImpl',a:1,b:'foo'}]}", cf.get("A/typedBeanListMapIntegerKeys"));
 		assertObject(proxy.getTypedBeanListMapIntegerKeys().get(1).get(0)).isType(TypedBeanImpl.class);
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/Constants.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/Constants.java
similarity index 97%
rename from juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/Constants.java
rename to juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/Constants.java
index a0b96a7..b727ffc 100644
--- a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/Constants.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/Constants.java
@@ -10,7 +10,7 @@
 // * "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.testutils;
+package org.apache.juneau.testutils;
 
 public class Constants {
 
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/XPartSerializer.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/XPartSerializer.java
similarity index 98%
rename from juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/XPartSerializer.java
rename to juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/XPartSerializer.java
index 8290df2..1373fc5 100644
--- a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/XPartSerializer.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/XPartSerializer.java
@@ -10,7 +10,7 @@
 // * "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.testutils;
+package org.apache.juneau.testutils;
 
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.serializer.*;
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/ABean.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/ABean.java
index ad0c44e..c55143c 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/ABean.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/ABean.java
@@ -16,9 +16,10 @@ public class ABean {
 	public int a;
 	public String b;
 
-	public ABean init() {
-		this.a = 1;
-		this.b = "foo";
-		return this;
+	public static ABean get() {
+		ABean x = new ABean();
+		x.a = 1;
+		x.b = "foo";
+		return x;
 	}
 }
\ No newline at end of file
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/LargePojo.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/LargePojo.java
index 9e1ddd2..efa7a28 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/LargePojo.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/LargePojo.java
@@ -23,7 +23,7 @@ public class LargePojo {
 	public A1List a1List;
 	public A1[] a1Array;
 
-	public static LargePojo create() {
+	public static LargePojo get() {
 		LargePojo a = new LargePojo();
 		a.a1Map = new A1Map();
 		a.a1List = new A1List();
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/PrimitiveAtomicObjectsBean.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/PrimitiveAtomicObjectsBean.java
index 208c723..e3625b3 100755
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/PrimitiveAtomicObjectsBean.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/PrimitiveAtomicObjectsBean.java
@@ -48,7 +48,7 @@ public class PrimitiveAtomicObjectsBean {
 	public List<AtomicInteger[]> polAtomicInteger;
 	public List<AtomicLong[]> polAtomicLong;
 
-	public PrimitiveAtomicObjectsBean init() {
+	private PrimitiveAtomicObjectsBean init() {
 		// primitive objects
 		poAtomicInteger = new AtomicInteger(1);
 		poAtomicLong = new AtomicLong(2);
@@ -71,4 +71,8 @@ public class PrimitiveAtomicObjectsBean {
 
 		return this;
 	}
+
+	public static PrimitiveAtomicObjectsBean get() {
+		return new PrimitiveAtomicObjectsBean().init();
+	}
 }
\ No newline at end of file
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/PrimitiveObjectsBean.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/PrimitiveObjectsBean.java
index 77f1c22..3c4a07e 100755
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/PrimitiveObjectsBean.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/PrimitiveObjectsBean.java
@@ -98,7 +98,7 @@ public class PrimitiveObjectsBean {
 	public List<BigInteger[]> polBigInteger;
 	public List<BigDecimal[]> polBigDecimal;
 
-	public PrimitiveObjectsBean init() {
+	private PrimitiveObjectsBean init() {
 		// primitive objects
 		poBoolean = true;
 		poByte = 1;
@@ -175,4 +175,8 @@ public class PrimitiveObjectsBean {
 
 		return this;
 	}
+
+	public static PrimitiveObjectsBean get() {
+		return new PrimitiveObjectsBean().init();
+	}
 }
\ No newline at end of file
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/TypedBeanImpl.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/TypedBeanImpl.java
index a78a874..882e602 100644
--- a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/TypedBeanImpl.java
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/TypedBeanImpl.java
@@ -17,9 +17,13 @@ public class TypedBeanImpl implements TypedBean {
 	public int a;
 	public String b;
 
-	public TypedBeanImpl init() {
+	private TypedBeanImpl init() {
 		this.a = 1;
 		this.b = "foo";
 		return this;
 	}
+
+	public static TypedBeanImpl get() {
+		return new TypedBeanImpl().init();
+	}
 }
\ No newline at end of file
diff --git a/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/XBeans.java b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/XBeans.java
new file mode 100644
index 0000000..9c507a3
--- /dev/null
+++ b/juneau-core/juneau-core-utest/src/test/java/org/apache/juneau/testutils/pojos/XBeans.java
@@ -0,0 +1,263 @@
+// ***************************************************************************************************************************
+// * 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.testutils.pojos;
+
+import java.util.*;
+
+import org.apache.juneau.annotation.*;
+import org.apache.juneau.collections.*;
+import org.apache.juneau.urlencoding.annotation.*;
+
+public class XBeans {
+
+	@Bean(sort=true)
+	public static class XA {
+		public String a;
+		public int b;
+		public boolean c;
+
+		public static XA get() {
+			XA t = new XA();
+			t.a = "a";
+			t.b = 1;
+			t.c = true;
+			return t;
+		}
+
+	}
+
+	@Bean(sort=true)
+	public static class XB {
+		public String[] f01;
+		public List<String> f02;
+		public int[] f03;
+		public List<Integer> f04;
+		public String[][] f05;
+		public List<String[]> f06;
+		public XA[] f07;
+		public List<XA> f08;
+		public XA[][] f09;
+		public List<List<XA>> f10;
+
+		private String[] f11;
+		private List<String> f12;
+		private int[] f13;
+		private List<Integer> f14;
+		private String[][] f15;
+		private List<String[]> f16;
+		private XA[] f17;
+		private List<XA> f18;
+		private XA[][] f19;
+		private List<List<XA>> f20;
+
+		public String[] getF11() { return f11; }
+		public List<String> getF12() { return f12; }
+		public int[] getF13() { return f13; }
+		public List<Integer> getF14() { return f14; }
+		public String[][] getF15() { return f15; }
+		public List<String[]> getF16() { return f16; }
+		public XA[] getF17() { return f17; }
+		public List<XA> getF18() { return f18; }
+		public XA[][] getF19() { return f19; }
+		public List<List<XA>> getF20() { return f20; }
+
+		public void setF11(String[] f11) { this.f11 = f11; }
+		public void setF12(List<String> f12) { this.f12 = f12; }
+		public void setF13(int[] f13) { this.f13 = f13; }
+		public void setF14(List<Integer> f14) { this.f14 = f14; }
+		public void setF15(String[][] f15) { this.f15 = f15; }
+		public void setF16(List<String[]> f16) { this.f16 = f16; }
+		public void setF17(XA[] f17) { this.f17 = f17; }
+		public void setF18(List<XA> f18) { this.f18 = f18; }
+		public void setF19(XA[][] f19) { this.f19 = f19; }
+		public void setF20(List<List<XA>> f20) { this.f20 = f20; }
+
+		public static XB get() {
+			XB t = new XB();
+			t.f01 = new String[]{"a","b"};
+			t.f02 = AList.of("c","d");
+			t.f03 = new int[]{1,2};
+			t.f04 = AList.of(3,4);
+			t.f05 = new String[][]{{"e","f"},{"g","h"}};
+			t.f06 = AList.of(new String[]{"i","j"},new String[]{"k","l"});
+			t.f07 = new XA[]{XA.get(),XA.get()};
+			t.f08 = AList.of(XA.get(),XA.get());
+			t.f09 = new XA[][]{{XA.get()},{XA.get()}};
+			t.f10 = AList.of(Arrays.asList(XA.get()),Arrays.asList(XA.get()));
+			t.setF11(new String[]{"a","b"});
+			t.setF12(AList.of("c","d"));
+			t.setF13(new int[]{1,2});
+			t.setF14(AList.of(3,4));
+			t.setF15(new String[][]{{"e","f"},{"g","h"}});
+			t.setF16(AList.of(new String[]{"i","j"},new String[]{"k","l"}));
+			t.setF17(new XA[]{XA.get(),XA.get()});
+			t.setF18(AList.of(XA.get(),XA.get()));
+			t.setF19(new XA[][]{{XA.get()},{XA.get()}});
+			t.setF20(AList.of(Arrays.asList(XA.get()),Arrays.asList(XA.get())));
+			return t;
+		}
+
+		public static XB INSTANCE = get();
+	}
+
+	@UrlEncoding(expandedParams=true)
+	public static class XC extends XB {
+		public static XC get() {
+			XC t = new XC();
+			t.f01 = new String[]{"a","b"};
+			t.f02 = AList.of("c","d");
+			t.f03 = new int[]{1,2};
+			t.f04 = AList.of(3, 4);
+			t.f05 = new String[][]{{"e","f"},{"g","h"}};
+			t.f06 = AList.of(new String[]{"i","j"}, new String[]{"k","l"});
+			t.f07 = new XA[]{XA.get(),XA.get()};
+			t.f08 = AList.of(XA.get(), XA.get());
+			t.f09 = new XA[][]{{XA.get()},{XA.get()}};
+			t.f10 = AList.of(Arrays.asList(XA.get()), Arrays.asList(XA.get()));
+			t.setF11(new String[]{"a","b"});
+			t.setF12(AList.of("c","d"));
+			t.setF13(new int[]{1,2});
+			t.setF14(AList.of(3,4));
+			t.setF15(new String[][]{{"e","f"},{"g","h"}});
+			t.setF16(AList.of(new String[]{"i","j"},new String[]{"k","l"}));
+			t.setF17(new XA[]{XA.get(),XA.get()});
+			t.setF18(AList.of(XA.get(), XA.get()));
+			t.setF19(new XA[][]{{XA.get()},{XA.get()}});
+			t.setF20(AList.of(Arrays.asList(XA.get()), Arrays.asList(XA.get())));
+			return t;
+		}
+
+		public static XC INSTANCE = get();
+	}
+
+	@BeanConfig(applyBean={@Bean(on="XD,XE,XF",sort=true)})
+	@UrlEncodingConfig(applyUrlEncoding={@UrlEncoding(on="C",expandedParams=true)})
+	public static class Annotations {}
+
+	public static class XD {
+		public String a;
+		public int b;
+		public boolean c;
+
+		public static XD get() {
+			XD t = new XD();
+			t.a = "a";
+			t.b = 1;
+			t.c = true;
+			return t;
+		}
+
+	}
+
+	public static class XE {
+		public String[] f01;
+		public List<String> f02;
+		public int[] f03;
+		public List<Integer> f04;
+		public String[][] f05;
+		public List<String[]> f06;
+		public XD[] f07;
+		public List<XD> f08;
+		public XD[][] f09;
+		public List<List<XD>> f10;
+
+		private String[] f11;
+		private List<String> f12;
+		private int[] f13;
+		private List<Integer> f14;
+		private String[][] f15;
+		private List<String[]> f16;
+		private XD[] f17;
+		private List<XD> f18;
+		private XD[][] f19;
+		private List<List<XD>> f20;
+
+		public String[] getF11() { return f11; }
+		public List<String> getF12() { return f12; }
+		public int[] getF13() { return f13; }
+		public List<Integer> getF14() { return f14; }
+		public String[][] getF15() { return f15; }
+		public List<String[]> getF16() { return f16; }
+		public XD[] getF17() { return f17; }
+		public List<XD> getF18() { return f18; }
+		public XD[][] getF19() { return f19; }
+		public List<List<XD>> getF20() { return f20; }
+
+		public void setF11(String[] f11) { this.f11 = f11; }
+		public void setF12(List<String> f12) { this.f12 = f12; }
+		public void setF13(int[] f13) { this.f13 = f13; }
+		public void setF14(List<Integer> f14) { this.f14 = f14; }
+		public void setF15(String[][] f15) { this.f15 = f15; }
+		public void setF16(List<String[]> f16) { this.f16 = f16; }
+		public void setF17(XD[] f17) { this.f17 = f17; }
+		public void setF18(List<XD> f18) { this.f18 = f18; }
+		public void setF19(XD[][] f19) { this.f19 = f19; }
+		public void setF20(List<List<XD>> f20) { this.f20 = f20; }
+
+		public static XE get() {
+			XE t = new XE();
+			t.f01 = new String[]{"a","b"};
+			t.f02 = AList.of("c","d");
+			t.f03 = new int[]{1,2};
+			t.f04 = AList.of(3,4);
+			t.f05 = new String[][]{{"e","f"},{"g","h"}};
+			t.f06 = AList.of(new String[]{"i","j"},new String[]{"k","l"});
+			t.f07 = new XD[]{XD.get(),XD.get()};
+			t.f08 = AList.of(XD.get(),XD.get());
+			t.f09 = new XD[][]{{XD.get()},{XD.get()}};
+			t.f10 = AList.of(Arrays.asList(XD.get()),Arrays.asList(XD.get()));
+			t.setF11(new String[]{"a","b"});
+			t.setF12(AList.of("c","d"));
+			t.setF13(new int[]{1,2});
+			t.setF14(AList.of(3,4));
+			t.setF15(new String[][]{{"e","f"},{"g","h"}});
+			t.setF16(AList.of(new String[]{"i","j"},new String[]{"k","l"}));
+			t.setF17(new XD[]{XD.get(),XD.get()});
+			t.setF18(AList.of(XD.get(),XD.get()));
+			t.setF19(new XD[][]{{XD.get()},{XD.get()}});
+			t.setF20(AList.of(Arrays.asList(XD.get()),Arrays.asList(XD.get())));
+			return t;
+		}
+
+		public static XE INSTANCE = get();
+	}
+
+	public static class XF extends XE {
+		public static XF get() {
+			XF t = new XF();
+			t.f01 = new String[]{"a","b"};
+			t.f02 = AList.of("c","d");
+			t.f03 = new int[]{1,2};
+			t.f04 = AList.of(3, 4);
+			t.f05 = new String[][]{{"e","f"},{"g","h"}};
+			t.f06 = AList.of(new String[]{"i","j"}, new String[]{"k","l"});
+			t.f07 = new XD[]{XD.get(),XD.get()};
+			t.f08 = AList.of(XD.get(), XD.get());
+			t.f09 = new XD[][]{{XD.get()},{XD.get()}};
+			t.f10 = AList.of(Arrays.asList(XD.get()), Arrays.asList(XD.get()));
+			t.setF11(new String[]{"a","b"});
+			t.setF12(AList.of("c","d"));
+			t.setF13(new int[]{1,2});
+			t.setF14(AList.of(3,4));
+			t.setF15(new String[][]{{"e","f"},{"g","h"}});
+			t.setF16(AList.of(new String[]{"i","j"},new String[]{"k","l"}));
+			t.setF17(new XD[]{XD.get(),XD.get()});
+			t.setF18(AList.of(XD.get(), XD.get()));
+			t.setF19(new XD[][]{{XD.get()},{XD.get()}});
+			t.setF20(AList.of(Arrays.asList(XD.get()), Arrays.asList(XD.get())));
+			return t;
+		}
+
+		public static XF INSTANCE = get();
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderSupplier.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderSupplier.java
index 3094642..94826c3 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderSupplier.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/HeaderSupplier.java
@@ -25,6 +25,7 @@ import org.apache.juneau.http.header.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.oapi.*;
+import org.apache.juneau.svl.*;
 
 /**
  * Specifies a dynamic supplier of {@link Header} objects.
@@ -38,6 +39,8 @@ public class HeaderSupplier implements Iterable<Header> {
 
 	private final List<Iterable<Header>> headers = new CopyOnWriteArrayList<>();
 
+	private volatile VarResolver varResolver;
+
 	/**
 	 * Convenience creator.
 	 *
@@ -76,12 +79,12 @@ public class HeaderSupplier implements Iterable<Header> {
 	 * @return A new instance.
 	 */
 	public static HeaderSupplier ofPairs(Object...parameters) {
-		List<Header> l = new ArrayList<>();
+		HeaderSupplier s = HeaderSupplier.create();
 		if (parameters.length % 2 != 0)
 			throw new BasicRuntimeException("Odd number of parameters passed into HeaderSupplier.ofPairs()");
 		for (int i = 0; i < parameters.length; i+=2)
-			l.add(new BasicHeader(stringify(parameters[i]), parameters[i+1]));
-		return HeaderSupplier.of(l);
+			s.add(stringify(parameters[i]), parameters[i+1]);
+		return s;
 	}
 
 	/**
@@ -110,6 +113,47 @@ public class HeaderSupplier implements Iterable<Header> {
 	}
 
 	/**
+	 * Allows header values to contain SVL variables.
+	 *
+	 * <p>
+	 * Resolves variables in header values when using the following methods:
+	 * <ul>
+	 * 	<li class='jm'>{@link #ofPairs(Object...) ofPairs(Object...)}
+	 * 	<li class='jm'>{@link #add(String, Object) add(String,Object)}
+	 * 	<li class='jm'>{@link #add(String, Supplier) add(String,Supplier&lt;?&gt;)}
+	 * 	<li class='jm'>{@link #add(String, Object, HttpPartSerializerSession, HttpPartSchema, boolean) add(String,Object,HttpPartSerializerSession,HttpPartSchema,boolean)}
+	 * </ul>
+	 *
+	 * <p>
+	 * Uses {@link VarResolver#DEFAULT} to resolve variables.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public HeaderSupplier resolving() {
+		return resolving(VarResolver.DEFAULT);
+	}
+
+	/**
+	 * Allows header values to contain SVL variables.
+	 *
+	 * <p>
+	 * Resolves variables in header values when using the following methods:
+	 * <ul>
+	 * 	<li class='jm'>{@link #ofPairs(Object...) ofPairs(Object...)}
+	 * 	<li class='jm'>{@link #add(String, Object) add(String,Object)}
+	 * 	<li class='jm'>{@link #add(String, Supplier) add(String,Supplier&lt;?&gt;)}
+	 * 	<li class='jm'>{@link #add(String, Object, HttpPartSerializerSession, HttpPartSchema, boolean) add(String,Object,HttpPartSerializerSession,HttpPartSchema,boolean)}
+	 * </ul>
+	 *
+	 * @param varResolver The variable resolver to use for resolving variables.
+	 * @return This object (for method chaining).
+	 */
+	public HeaderSupplier resolving(VarResolver varResolver) {
+		this.varResolver = varResolver;
+		return this;
+	}
+
+	/**
 	 * Add a header to this supplier.
 	 *
 	 * @param h The header to add. <jk>null</jk> values are ignored.
@@ -159,7 +203,7 @@ public class HeaderSupplier implements Iterable<Header> {
 	 * @return This object (for method chaining).
 	 */
 	public HeaderSupplier add(String name, Object value) {
-		return add(new BasicHeader(name, value));
+		return add(new BasicHeader(name, resolver(value)));
 	}
 
 	/**
@@ -176,7 +220,7 @@ public class HeaderSupplier implements Iterable<Header> {
 	 * @return This object (for method chaining).
 	 */
 	public HeaderSupplier add(String name, Supplier<?> value) {
-		return add(new BasicHeader(name, value));
+		return add(new BasicHeader(name, resolver(value)));
 	}
 
 	/**
@@ -195,7 +239,7 @@ public class HeaderSupplier implements Iterable<Header> {
 	 * @return This object (for method chaining).
 	 */
 	public HeaderSupplier add(String name, Object value, HttpPartSerializerSession serializer, HttpPartSchema schema, boolean skipIfEmpty) {
-		return add(new SerializedHeader(name, value, serializer, schema, skipIfEmpty));
+		return add(new SerializedHeader(name, resolver(value), serializer, schema, skipIfEmpty));
 	}
 
 	/**
@@ -244,4 +288,14 @@ public class HeaderSupplier implements Iterable<Header> {
 			l.add(p);
 		return l.toArray(array);
 	}
+
+	private Supplier<Object> resolver(Object input) {
+		return ()->(varResolver == null ? unwrap(input) : varResolver.resolve(stringify(unwrap(input))));
+	}
+
+	private Object unwrap(Object o) {
+		while (o instanceof Supplier)
+			o = ((Supplier<?>)o).get();
+		return o;
+	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/NameValuePairSupplier.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/NameValuePairSupplier.java
index 21be3a5..2367edd 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/NameValuePairSupplier.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/NameValuePairSupplier.java
@@ -24,6 +24,7 @@ import org.apache.juneau.*;
 import org.apache.juneau.httppart.*;
 import org.apache.juneau.internal.*;
 import org.apache.juneau.oapi.*;
+import org.apache.juneau.svl.*;
 import org.apache.juneau.urlencoding.*;
 
 /**
@@ -38,6 +39,8 @@ public class NameValuePairSupplier implements Iterable<NameValuePair> {
 
 	private final List<Iterable<NameValuePair>> pairs = new CopyOnWriteArrayList<>();
 
+	private volatile VarResolver varResolver;
+
 	/**
 	 * Convenience creator.
 	 *
@@ -76,12 +79,12 @@ public class NameValuePairSupplier implements Iterable<NameValuePair> {
 	 * @return A new instance.
 	 */
 	public static NameValuePairSupplier ofPairs(Object...parameters) {
-		List<NameValuePair> l = new ArrayList<>();
+		NameValuePairSupplier s = NameValuePairSupplier.create();
 		if (parameters.length % 2 != 0)
 			throw new BasicRuntimeException("Odd number of parameters passed into NameValuePairSupplier.ofPairs()");
 		for (int i = 0; i < parameters.length; i+=2)
-			l.add(new BasicNameValuePair(stringify(parameters[i]), parameters[i+1]));
-		return NameValuePairSupplier.of(l);
+			s.add(stringify(parameters[i]), parameters[i+1]);
+		return s;
 	}
 
 	/**
@@ -110,6 +113,47 @@ public class NameValuePairSupplier implements Iterable<NameValuePair> {
 	}
 
 	/**
+	 * Allows values to contain SVL variables.
+	 *
+	 * <p>
+	 * Resolves variables in values when using the following methods:
+	 * <ul>
+	 * 	<li class='jm'>{@link #ofPairs(Object...) ofPairs(Object...)}
+	 * 	<li class='jm'>{@link #add(String, Object) add(String,Object)}
+	 * 	<li class='jm'>{@link #add(String, Supplier) add(String,Supplier&lt;?&gt;)}
+	 * 	<li class='jm'>{@link #add(String, Object, HttpPartType, HttpPartSerializerSession, HttpPartSchema, boolean) add(String,Object,HttpPartType,HttpPartSerializerSession,HttpPartSchema,boolean)}
+	 * </ul>
+	 *
+	 * <p>
+	 * Uses {@link VarResolver#DEFAULT} to resolve variables.
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public NameValuePairSupplier resolving() {
+		return resolving(VarResolver.DEFAULT);
+	}
+
+	/**
+	 * Allows values to contain SVL variables.
+	 *
+	 * <p>
+	 * Resolves variables in values when using the following methods:
+	 * <ul>
+	 * 	<li class='jm'>{@link #ofPairs(Object...) ofPairs(Object...)}
+	 * 	<li class='jm'>{@link #add(String, Object) add(String,Object)}
+	 * 	<li class='jm'>{@link #add(String, Supplier) add(String,Supplier&lt;?&gt;)}
+	 * 	<li class='jm'>{@link #add(String, Object, HttpPartType, HttpPartSerializerSession, HttpPartSchema, boolean) add(String,Object,HttpPartType,HttpPartSerializerSession,HttpPartSchema,boolean)}
+	 * </ul>
+	 *
+	 * @param varResolver The variable resolver to use for resolving variables.
+	 * @return This object (for method chaining).
+	 */
+	public NameValuePairSupplier resolving(VarResolver varResolver) {
+		this.varResolver = varResolver;
+		return this;
+	}
+
+	/**
 	 * Add a name-value pair to this supplier.
 	 *
 	 * @param h The name-value pair to add. <jk>null</jk> values are ignored.
@@ -159,7 +203,7 @@ public class NameValuePairSupplier implements Iterable<NameValuePair> {
 	 * @return This object (for method chaining).
 	 */
 	public NameValuePairSupplier add(String name, Object value) {
-		return add(new BasicNameValuePair(name, value));
+		return add(new BasicNameValuePair(name, resolver(value)));
 	}
 
 	/**
@@ -176,7 +220,7 @@ public class NameValuePairSupplier implements Iterable<NameValuePair> {
 	 * @return This object (for method chaining).
 	 */
 	public NameValuePairSupplier add(String name, Supplier<?> value) {
-		return add(new BasicNameValuePair(name, value));
+		return add(new BasicNameValuePair(name, resolver(value)));
 	}
 
 	/**
@@ -199,7 +243,7 @@ public class NameValuePairSupplier implements Iterable<NameValuePair> {
 	 * @return This object (for method chaining).
 	 */
 	public NameValuePairSupplier add(String name, Object value, HttpPartType partType, HttpPartSerializerSession serializer, HttpPartSchema schema, boolean skipIfEmpty) {
-		return add(new SerializedNameValuePair(name, value, partType, serializer, schema, skipIfEmpty));
+		return add(new SerializedNameValuePair(name, resolver(value), partType, serializer, schema, skipIfEmpty));
 	}
 
 	/**
@@ -248,4 +292,14 @@ public class NameValuePairSupplier implements Iterable<NameValuePair> {
 			l.add(p);
 		return l.toArray(array);
 	}
+
+	private Supplier<Object> resolver(Object input) {
+		return ()->(varResolver == null ? unwrap(input) : varResolver.resolve(stringify(unwrap(input))));
+	}
+
+	private Object unwrap(Object o) {
+		while (o instanceof Supplier)
+			o = ((Supplier<?>)o).get();
+		return o;
+	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicHeader.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicHeader.java
index b93158b..33fed34 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicHeader.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/header/BasicHeader.java
@@ -221,8 +221,8 @@ public class BasicHeader implements Header, Cloneable, Serializable {
 	 * @return The unwrapped object.
 	 */
 	protected Object unwrap(Object o) {
-		if (o instanceof Supplier)
-			return ((Supplier<?>)o).get();
+		while (o instanceof Supplier)
+			o = ((Supplier<?>)o).get();
 		return o;
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/remote/Remote.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/remote/Remote.java
index 2df756c..8e99965 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/remote/Remote.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/http/remote/Remote.java
@@ -42,6 +42,12 @@ public @interface Remote {
 	 * 	<li>A relative URL interpreted as relative to the root URL defined on the <c>RestClient</c>
 	 * 	<li>No path interpreted as the class name (e.g. <js>"http://localhost/root-url/org.foo.MyInterface"</js>)
 	 * </ul>
+	 *
+	 * <ul class='notes'>
+	 * 	<li>
+	 * 		Supports {@doc DefaultSvlVariables}
+	 * 		(e.g. <js>"$P{mySystemProperty}"</js>).
+	 * </ul>
 	 */
 	String path() default "";
 
@@ -81,9 +87,9 @@ public @interface Remote {
 	 *
 	 * <p>
 	 * The format of this is a string of the format <c>#[.#[.#[...]]</c> (e.g. <js>"1.2.3"</js>).
-	 * 
+	 *
 	 * <p>
-	 * The server side then uses an OSGi-version matching pattern to identify which methods to call: 
+	 * The server side then uses an OSGi-version matching pattern to identify which methods to call:
 	 * <p class='bcode w800'>
 	 * 	<jc>// Call this method if X-Client-Version is at least 2.0.
 	 * 	// Note that this also matches 2.0.1.</jc>
@@ -98,11 +104,26 @@ public @interface Remote {
 	 * 	<ja>@RestMethod</ja>(name=<jsf>GET</jsf>, path=<js>"/foobar"</js>, clientVersion=<js>"[0,1.1)"</js>)
 	 * 	<jk>public</jk> Object method3()  {...}
 	 * </p>
+	 *
+	 * <ul class='notes'>
+	 * 	<li>
+	 * 		Supports {@doc DefaultSvlVariables}
+	 * 		(e.g. <js>"$P{mySystemProperty}"</js>).
+	 * </ul>
 	 */
 	String version() default "";
 
 	/**
 	 * Specifies the client version header name.
+	 *
+	 * <p>
+	 * The default value is <js>"X-Client-Version"</js>.
+	 *
+	 * <ul class='notes'>
+	 * 	<li>
+	 * 		Supports {@doc DefaultSvlVariables}
+	 * 		(e.g. <js>"$P{mySystemProperty}"</js>).
+	 * </ul>
 	 */
-	String versionHeader() default "X-Client-Version";
+	String versionHeader() default "";
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/Schema.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/Schema.java
index cf7da9b..c50c859 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/Schema.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/annotation/Schema.java
@@ -787,12 +787,7 @@ public @interface Schema {
 	 * </p>
 	 * <p class='bcode w800'>
 	 * 	<jc>// Free-form</jc>
-	 * 	<ja>@Schema</ja>(
-	 * 		<js>"type: 'array',"</js>,
-	 * 		<js>"items: {"</js>,
-	 * 			<js>"$ref: '#/definitions/Pet'"</js>,
-	 * 		<js>"}"</js>
-	 * 	)
+	 * 	<ja>@Schema</ja>(<js>"type:'array',items:{$ref:'#/definitions/Pet'}"</js>)
 	 * </p>
 	 * <p class='bcode w800'>
 	 * 	<jc>// Free-form using variables</jc>
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/svl/VarResolver.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/svl/VarResolver.java
index 675e5a2..f76b743 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/svl/VarResolver.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/svl/VarResolver.java
@@ -14,6 +14,7 @@ package org.apache.juneau.svl;
 
 import java.io.*;
 import java.util.*;
+import java.util.function.*;
 
 import org.apache.juneau.svl.vars.*;
 
@@ -178,4 +179,14 @@ public class VarResolver {
 	public void resolveTo(String s, Writer w) throws IOException {
 		createSession(null).resolveTo(s, w);
 	}
+
+	/**
+	 * Returns a supplier for the specified string.
+	 *
+	 * @param s The string to resolve.
+	 * @return A supplier for the specified string.
+	 */
+	public Supplier<String> resolver(String s) {
+		return ()->resolve(s);
+	}
 }
\ No newline at end of file
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client.html b/juneau-doc/docs/Topics/09.juneau-rest-client.html
index 87dba6f..9e2ed4a 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client.html
@@ -43,7 +43,7 @@ juneau-rest-client
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a basic REST client with JSON support and download a bean.</jc>
-	MyBean bean = RestClient.<jsm>create</jsm>()
+	MyBean <jv>bean</jv> = RestClient.<jsm>create</jsm>()
 		.simpleJson()
 		.build()
 		.get(<jsf>URI</jsf>)
@@ -58,17 +58,17 @@ juneau-rest-client
 </p>
 
 <p class='bpcode w800'>
-	RestClientBuilder builder = RestClient.<jsm>create</jsm>().simpleJson();
-	RestClient client = builder.build();
-	RestRequest req = client.get(<jsf>URI</jsf>);
-	RestResponse res = req.run();
-	RestResponseStatusLineAssertion statusLineAssertion = res.assertStatus();
-	FluentIntegerAssertion&lt;RestResponse&gt; codeAssertion = statusLineAssertion.code();
-	res = codeAssertion.is(200);
-	FluentStringAssertion&lt;RestResponse&gt; headerAssertion = res.assertHeader(<js>"Content-Type"</js>);
-	res = headerAssertion.matchesSimple(<js>"application/json*"</js>);
-	RestResponseBody body = res.getBody();
-	MyBean bean = body.as(MyBean.<jk>class</jk>);
+	RestClientBuilder <jv>builder</jv> = RestClient.<jsm>create</jsm>().simpleJson();
+	RestClient <jv>client</jv> = <jv>builder</jv>.build();
+	RestRequest <jv>req</jv> = <jv>client</jv>.get(<jsf>URI</jsf>);
+	RestResponse <jv>res</jv> = <jv>req</jv>.run();
+	RestResponseStatusLineAssertion <jv>statusLineAssertion</jv> = <jv>res</jv>.assertStatus();
+	FluentIntegerAssertion&lt;RestResponse&gt; <jv>codeAssertion</jv> = <jv>statusLineAssertion</jv>.code();
+	<jv>res</jv> = <jv>codeAssertion</jv>.is(200);
+	FluentStringAssertion&lt;RestResponse&gt; <jv>headerAssertion</jv> = <jv>res</jv>.assertHeader(<js>"Content-Type"</js>);
+	<jv>res</jv> = <jv>headerAssertion</jv>.matchesSimple(<js>"application/json*"</js>);
+	RestResponseBody <jv>body</jv> = <jv>res</jv>.getBody();
+	MyBean <jv>bean</jv> = <jv>body</jv>.as(MyBean.<jk>class</jk>);
 </p>
 
 <p>
@@ -83,17 +83,18 @@ juneau-rest-client
 	
 		<ja>@RemoteMethod</ja>(httpMethod=<jsf>POST</jsf>, path=<js>"/pets"</js>)
 		Pet addPet(
-			<ja>@Body</ja> CreatePet pet,
-			<ja>@Header</ja>(<js>"E-Tag"</js>) UUID etag,
-			<ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> debug
+			<ja>@Body</ja> CreatePet <jv>pet</jv>,
+			<ja>@Header</ja>(<js>"E-Tag"</js>) UUID <jv>etag</jv>,
+			<ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> <jv>debug</jv>
 		);
 	}
  
 	<jc>// Use a RestClient with default Simple JSON support.</jc>
-	RestClient client = RestClient.<jsm>create</jsm>().simpleJson().build();
-	PetStore store = client.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
-	CreatePet cp = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99);
-	Pet p = store.addPet(cp, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>);
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build();
+	
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
+	CreatePet <jv>createPet</jv> = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99);
+	Pet <jv>pet</jv> = <jv>store</jv>.addPet(<jv>createPet</jv>, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>);
 </p>
 
 <p>
@@ -119,10 +120,10 @@ juneau-rest-client
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a client where all URIs are relative to localhost.</jc>
-	RestClient client = RestClient.<jsm>create</jsm>().json().rootUri(<js>"http://localhost:10000"</js>).build();
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json().rootUri(<js>"http://localhost:10000"</js>).build();
 
 	<jc>// Use relative paths.</jc>
-	String body = client.get(<js>"/subpath"</js>).run().getBody().asString();
+	String <jv>body</jv> = <jv>client</jv>.get(<js>"/subpath"</js>).run().getBody().asString();
 </p>
 
 <p>
@@ -170,8 +171,8 @@ juneau-rest-client
 
 <p class='bpcode w800'>
 	<jc>// Consuming the response, so use run().</jc>
-	String body = client.get(<jsf>URI</jsf>).run().getBody().asString();
+	String <jv>body</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().asString();
 
 	<jc>// Only interested in response status code, so use complete().</jc>
-	<jk>int</jk> status = client.get(<jsf>URI</jsf>).complete().getStatusCode();
+	<jk>int</jk> <jv>status</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).complete().getStatusCode();
 </p>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/01.PojoMarshalling.html b/juneau-doc/docs/Topics/09.juneau-rest-client/01.PojoMarshalling.html
index d7d5afc..aae0540 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/01.PojoMarshalling.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/01.PojoMarshalling.html
@@ -55,8 +55,8 @@ POJO Marshalling
 </p>
 
 <p>
-	When using clients with multiple language support, you must specify the <c>Content-Type</c> header on requests
-	with bodies to specify which serializer should be selected.
+	When using clients with multiple language support, the request language is selected by setting the <c>Content-Type</c> 
+	request header.
 </p>
 <p class='bpcode w800'>
 	<jc>// Create a REST client with support for multiple languages.</jc>
@@ -87,8 +87,8 @@ POJO Marshalling
 	RestClient <jv>client1</jv> = RestClient.<jsm>create</jsm>().json().sq().ws().build();
 
 	<jc>// Same, but using properties.</jc>
-	RestClient <jv>client</jv> = RestClient
-		.<jsm>create2</jsm>()
+	RestClient <jv>client2</jv> = RestClient
+		.<jsm>create</jsm>()
 		.json()
 		.set(<jsf>WSERIALIZER_quoteChar</jsf>, <js>'\''</js>)
 		.set(<jsf>WSERIALIZER_useWhitespace</jsf>, <jk>true</jk>)
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/02.RequestHeaders.html b/juneau-doc/docs/Topics/09.juneau-rest-client/02.RequestHeaders.html
index e4f9307..8090309 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/02.RequestHeaders.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/02.RequestHeaders.html
@@ -43,6 +43,38 @@ Request Headers
 	</ul>
 </ul>
 
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a "Foo: bar" header to every request.</jc>
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().header(<js>"Foo"</js>, <js>"bar"</js>).build();
+
+	<jc>// Or do it on every request.</jc>
+	String <jv>response</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).header(<js>"Foo"</js>, <js>"bar"</js>).run().getBody().asString();
+</p>
+
+<p>
+	{@link oajr.client2.RestClientBuilder#headers(Object...) headers(Object...)} allows you to pass in a variety
+	of header objects, and {@link oajr.client2.RestClientBuilder#headerPairs(Object...) headerPairs(Object...)} allows
+	you to specify several headers in a compact fashion.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a bunch of headers to every request.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.headers(
+			AMap.<jsm>of</jsm>(<js>"Foo"</js>,<js>"bar"</js>,<js>"Baz"</js>,<js>"qux"</js>)  <jc>// Arbitrary key/value pairs.</jc>
+			BasicStringHeader.<jsm>of</jsm>(<js>"Foo"</js>,<js>"bar"</js>)  <jc>// A Header object.</jc>
+			BasicStringHeader.<jsm>of</jsm>(<js>"Foo"</js>,()->getBar())  <jc>// A dynamic Header object.</jc>
+			Accept.<jsm>of</jsm>(<js>"application/json"</js>)  <jc>// Predefined Header objects.</jc>
+			HeaderSupplier.<jsm>ofPairs</jsm>(<js>"Foo"</js>,<js>"bar"</js>)  <jc>// A dynamically changing list of Header objects.</jc>
+			AList.<jsm>of</jsm>(ContentType.<jsm>of</jsm>(<js>"application/json"</js>))  <jc>// A list of anything else on this list.</jc>
+		)
+		.headerPairs(<js>"Foo"</js>,<js>"bar"</js>,<js>"Baz"</js>,<js>"qux"</js>)
+		.build();
+</p>
+
 <p>
 	Additionally, methods are provided on the client builder and per request for all standard HTTP headers
 	such as {@link oajr.client2.RestClientBuilder#authorization(Object) authorization(Object)}.
@@ -72,14 +104,14 @@ Request Headers
 </p>
 
 <p>
-	The {@link oaj.httppart.HttpPartSchema} API allows you to define OpenAPI schemas to POJO data structures on both requests
-	and responses.
+	The {@link oaj.httppart.HttpPartSchema} API allows you to define OpenAPI schemas to POJO data structures on request headers.
 </p>
 
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a client that adds a header "Foo: bar|baz" to every request.</jc>
-	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>()
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
 		.header(<js>"Foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), <jsf>T_ARRAY_PIPES</jsf>)
 		.build();
 </p>
@@ -92,3 +124,7 @@ Request Headers
 	<li>Methods that pass in POJOs convert values to strings using the part serializers.  Methods that pass in <c>Header</c> or
 		<c>NameValuePair</c> objects use the values returned by that bean directly.
 </ul>
+<ul class='seealso'>
+	<li class='jp'>{@link oaj.http.header} - Predefined {@link org.apache.http.Header} beans.
+</ul>
+
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/03.RequestQueryParameters.html b/juneau-doc/docs/Topics/09.juneau-rest-client/03.RequestQueryParameters.html
index 0fa83fe..c72668c 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/03.RequestQueryParameters.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/03.RequestQueryParameters.html
@@ -49,8 +49,47 @@ Request Query Parameters
 	String <jv>response</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).query(<js>"foo"</js>, <js>"bar"</js>).run().getBody().asString();
 </p>
 
+<p>
+	{@link oajr.client2.RestClientBuilder#queries(Object...) queries(Object...)} allows you to pass in a variety
+	of query parameter objects, and {@link oajr.client2.RestClientBuilder#queryPairs(Object...) queryPairs(Object...)} allows
+	you to specify several query parameters in a compact fashion.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a bunch of query parameters to every request.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.queries(
+			AMap.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>,<js>"qux"</js>)  <jc>// Arbitrary key/value pairs.</jc>
+			BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>)  <jc>// A NameValuePair object.</jc>
+			BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,()->getBar())  <jc>// A dynamic NameValuePair object.</jc>
+			NameValuePairSupplier.<jsm>ofPairs</jsm>(<js>"foo"</js>,<js>"bar"</js>)  <jc>// A dynamically changing list of NameValuePair objects.</jc>
+			AList.<jsm>of</jsm>(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>))  <jc>// A list of anything else on this list.</jc>
+		)
+		.queryPairs(<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>,<js>"qux"</js>)
+		.build();
+</p>
+
+<p>
+	The {@link oaj.httppart.HttpPartSchema} API allows you to define OpenAPI schemas to POJO data structures on query parameters.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a query parameter "foo=bar|baz" to every request.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.query(<js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), <jsf>T_ARRAY_PIPES</jsf>)
+		.build();
+</p>
+
+<p>
+	The methods with {@link oaj.AddFlag} parameters allow you to control whether new query parameters get appended, prepended, or
+	replace existing query parameters with the same name.
+</p>
+
 <ul class='notes'>
-	<li>Like header values, dynamic values and OpenAPI schemas are supported.
 	<li>Methods that pass in POJOs convert values to strings using the part serializers.  Methods that pass in <c>NameValuePair</c>
 		objects use the values returned by that bean directly.
 </ul>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/04.RequestFormData.html b/juneau-doc/docs/Topics/09.juneau-rest-client/04.RequestFormData.html
index a7ed7f8..45aa0f8 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/04.RequestFormData.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/04.RequestFormData.html
@@ -40,6 +40,55 @@ Request Form Data
 	</ul>
 </ul>
 
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a foo=bar form-data parameter to every request.</jc>
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().formData(<js>"foo"</js>, <js>"bar"</js>).build();
+
+	<jc>// Or do it on every request.</jc>
+	String <jv>response</jv> = <jv>client</jv>.formPost(<jsf>URI</jsf>).formData(<js>"foo"</js>, <js>"bar"</js>).run().getBody().asString();
+</p>
+
+<p>
+	{@link oajr.client2.RestClientBuilder#formDatas(Object...) formDatas(Object...)} allows you to pass in a variety
+	of form-data parameter objects, and {@link oajr.client2.RestClientBuilder#formDataPairs(Object...) formDataPairs(Object...)} allows
+	you to specify several form-data parameters in a compact fashion.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a bunch of form-data parameters to every request.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.formDatas(
+			AMap.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>,<js>"qux"</js>)  <jc>// Arbitrary key/value pairs.</jc>
+			BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>)  <jc>// A NameValuePair object.</jc>
+			BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,()->getBar())  <jc>// A dynamic NameValuePair object.</jc>
+			NameValuePairSupplier.<jsm>ofPairs</jsm>(<js>"foo"</js>,<js>"bar"</js>)  <jc>// A dynamically changing list of NameValuePair objects.</jc>
+			AList.<jsm>of</jsm>(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>))  <jc>// A list of anything else on this list.</jc>
+		)
+		.formDataPairs(<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>,<js>"qux"</js>)
+		.build();
+</p>
+
+<p>
+	The {@link oaj.httppart.HttpPartSchema} API allows you to define OpenAPI schemas to POJO data structures on form-data parameters.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a form-data parameter "foo=bar|baz" to every request.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.formData(<js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), <jsf>T_ARRAY_PIPES</jsf>)
+		.build();
+</p>
+
+<p>
+	The methods with {@link oaj.AddFlag} parameters allow you to control whether new form-data parameters get appended, prepended, or
+	replace existing form-data parameters with the same name.
+</p>
+
 <ul class='notes'>
 	<li>Like header values, dynamic values and OpenAPI schemas are supported.
 	<li>Methods that pass in POJOs convert values to strings using the part serializers.  Methods that pass in <c>NameValuePair</c>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/05.RequestBody.html b/juneau-doc/docs/Topics/09.juneau-rest-client/05.RequestBody.html
index ea9274b..5e1602d 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/05.RequestBody.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/05.RequestBody.html
@@ -50,6 +50,33 @@ Request Body
 		{@link java.util.function.Supplier} - A supplier of anything on this list.
 </ul>
 
+<h5 class='figure'>Examples:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client with Simple-JSON support.</jc>
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build();
+	
+	<jc>// Post a JSON-serialized bean.</jc>
+	<jv>client</jv>
+		.post(<jsf>URI</jsf>)
+		.body(<jv>bean</jv>)
+		.complete()
+		.assertStatus().code().is(200);
+	
+	<jc>// Post contents from a reader.</jc>
+	<jv>client</jv>
+		.post(<jsf>URI</jsf>)
+		.body(<jk>new</jk> FileReader(<js>"/tmp/foo.json"</js>))
+		.complete()
+		.assertStatus().code().is(200);
+	
+	<jc>// Post contents from an Apache HttpEntity object.</jc>
+	<jv>client</jv>
+		.post(<jsf>URI</jsf>)
+		.body(<jk>new</jk> StringEntity(<jv>jsonString</jv>, ContentType.<jsf>APPLICATION_JSON</jsf>))
+		.complete()
+		.assertStatus().code().is(200);
+</p>
+
 <ul class='notes'>
 	<li>If the serializer on the client or request is explicitly set to <jk>null</jk>, POJOs will be converted to strings
 		using the registered part serializer as content type <js>"text/plain</js>.  If the part serializer is also <jk>null</jk>,
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/08.ResponseBody.html b/juneau-doc/docs/Topics/09.juneau-rest-client/08.ResponseBody.html
index cb27f86..451e3b6 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/08.ResponseBody.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/08.ResponseBody.html
@@ -54,10 +54,14 @@ Response Body
 	</ul>
 </ul>
 
-<br>
-
 <h5 class='figure'>Examples:</h5>
 <p class='bpcode w800'>
+	<jc>// Parse into a bean.</jc>
+	MyBean <jv>bean</jv> = <jv>client</jv>
+		.get(<jsf>URI</jsf>)
+		.run()
+		.getBody().as(MyBean.<jk>class</jk>);
+
 	<jc>// Parse into a linked-list of strings.</jc>
 	List&lt;String&gt; <jv>l1</jv> = <jv>client</jv>
 		.get(<jsf>URI</jsf>)
@@ -120,8 +124,6 @@ Response Body
 	</ul>
 </ul>
 
-<br>
-
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Assert that the body contains the string "Success".</jc>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/09.CustomCallHandlers.html b/juneau-doc/docs/Topics/09.juneau-rest-client/09.CustomCallHandlers.html
index bde12a5..18ec529 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/09.CustomCallHandlers.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/09.CustomCallHandlers.html
@@ -32,6 +32,35 @@ Custom Call Handlers
 	</ul>
 </ul>
 
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Our custom call handler.</jc>
+	<jk>public class</jk> MyRestCallHandler <jk>implements</jk> RestCallHandler {
+
+		<jk>private final</jk> RestClient <jf>client</jf>;
+
+		<jk>public</jk> MyRestCallHandler(RestClient <jv>client</jv>) {
+			<jk>this</jk>.<jf>client</jf> = <jv>client</jv>;
+		}
+
+		<ja>@Override</ja>
+		<jk>public</jk> HttpResponse run(HttpHost <jv>target</jv>, HttpRequest <jv>request</jv>, HttpContext <jv>context</jv>) <jk>throws</jk> IOException {
+			<jc>// Insert any special handling here.</jc>
+			<jc>// The following is the default behavior:</jc>
+			<jk>if</jk> (<jv>target</jv> == <jk>null</jk>)
+				<jk>return</jk> <jf>client</jf>.execute((HttpUriRequest)<jv>request</jv>, <jv>context</jv>);
+			<jk>return</jk> <jf>client</jf>.execute(<jv>target</jv>, <jv>request</jv>, <jv>context</jv>);
+		}
+	}
+	
+	<jc>// Create a client that uses our custom handler.</jc>
+	RestClient <jv>client</jv> = RestClient()
+		.create()
+		.json()
+		.callHandler(MyCallHandler.<jk>class</jk>)
+		.build();
+</p>
+ 
 <p>
 	Note that there are other ways of accomplishing this such as extending the {@link oajr.client2.RestClient} class and overriding
 	the {@link oaj.rest.client2.RestClient#run(HttpHost,HttpRequest,HttpContext)} method
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/10.Interceptors.html b/juneau-doc/docs/Topics/09.juneau-rest-client/10.Interceptors.html
index 9404207..eb201c5 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/10.Interceptors.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/10.Interceptors.html
@@ -1,15 +1,15 @@
 <!--
 /***************************************************************************************************************************
- * 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.
+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.
  ***************************************************************************************************************************/
  -->
 
@@ -37,3 +37,32 @@ Interceptors
 		<li class='jm'>{@link oajr.client2.RestCallInterceptor#onClose(RestRequest,RestResponse) onClose(RestRequest,RestResponse)}
 	</ul>
 </ul>
+
+<h5 class='section'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client with a customized interceptor.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.interceptors(
+			<jk>new</jk> RestCallInterceptor() {
+
+				<ja>@Override</ja>
+				<jk>public void</jk> onInit(RestRequest <jv>req</jv>) <jk>throws</jk> Exception {
+					<jc>// Intercept immediately after RestRequest object is created and all headers/query/form-data has been
+					// set on the request from the client.</jc>
+				}
+
+				<ja>@Override</ja>
+				<jk>public void</jk> onConnect(RestRequest <jv>req</jv>, RestResponse <jv>res</jv>) <jk>throws</jk> Exception {
+					<jc>// Intercept immediately after an HTTP response has been received.</jc>
+				}
+
+				<ja>@Override</ja>
+				<jk>public void</jk> onClose(RestRequest <jv>req</jv>, RestResponse <jv>res</jv>) <jk>throws</jk> Exception {
+					<jc>// Intercept when the response body is consumed.</jc>
+				}
+			}
+		)
+		.build();
+</p>
+
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies.html b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies.html
index d163f3d..4751779 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies.html
@@ -13,34 +13,12 @@
  ***************************************************************************************************************************/
  -->
 
-{8.1.4-new} 
+{8.1.4-updated} 
 REST Proxies
 
 <p>
 	One of the more powerful features of the REST client class is the ability to produce Java interface proxies against
-	arbitrary remote REST resources.
-</p>
-
-<h5 class='figure'>Example:</h5>
-<p class='bpcode w800'>
-	<jc>// Define a Remote proxy for interacting with a REST interface.</jc>
-	<ja>@Remote</ja>(path=<js>"/petstore"</js>)
-	
-	<jk>public interface</jk> PetStore {
-		<ja>@RemoteMethod</ja>(httpMethod=<jsf>POST</jsf>, path=<js>"/pets"</js>)
-		Pet addPet(
-			<ja>@Body</ja> CreatePet <jv>pet</jv>,
-			<ja>@Header</ja>(<js>"E-Tag"</js>) UUID <jv>etag</jv>,
-			<ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> <jv>debug</jv>
-		);
-	}
-
-	<jc>// Use a RestClient with default Simple JSON support.</jc>
-	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build()) {
-	
-	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
-	CreatePet <jv>createPet</jv> = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99);
-	Pet <jv>pet</jv> = <jv>store</jv>.addPet(<jv>createPet</jv>, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>);
+	arbitrary 3rd party REST resources.
 </p>
 
 <p>
@@ -53,47 +31,10 @@ REST Proxies
 		<li class='jm'><c>{@link oajr.client2.RestClient#getRemote(Class) getRemote(Class&lt;T&gt;)} <jk>returns</jk> T</c>
 		<li class='jm'><c>{@link oajr.client2.RestClient#getRemote(Class,Object) getRemote(Class&lt;T&gt;,Object)} <jk>returns</jk> T</c>
 		<li class='jm'><c>{@link oajr.client2.RestClient#getRemote(Class,Object,Serializer,Parser) getRemote(Class&lt;T&gt;,Object,Serializer,Parser)} <jk>returns</jk> T</c>
-		<li class='jm'><c>{@link oajr.client2.RestClient#getRrpcInterface(Class) getRrpcInterface(Class&lt;T&gt;)} <jk>returns</jk> T</c>
-		<li class='jm'><c>{@link oajr.client2.RestClient#getRrpcInterface(Class,Object) getRrpcInterface(Class&lt;T&gt;,Object)} <jk>returns</jk> T</c>
-		<li class='jm'><c>{@link oajr.client2.RestClient#getRrpcInterface(Class,Object,Serializer,Parser) getRrpcInterface(Class&lt;T&gt;,Object,Serializer,Parser)} <jk>returns</jk> T</c>
 	</ul>
 </ul>
 
 <p>
-	Two basic types of remote interfaces are provided:
-</p>
-
-<ul class='spaced-list'>
-	<li>{@link oaj.http.remote.Remote @Remote}-annotated interfaces.  These can be defined against arbitrary external REST resources.
-	<li>RPC-over-REST interfaces.  These are Java interfaces that allow you to make method calls on server-side POJOs.
-</ul>
-
-
-
-
-
-
-
-
-
-
-<p>
-	The <c>juneau-rest-client</c> library can also be used to define interface proxies against 3rd-party REST interfaces.
-	This is an extremely powerful feature that allows you to quickly define easy-to-use interfaces against 
-	virtually any REST interface.
-</p>
-<p>
-	Remote resources are instantiated using one of the following methods:
-</p>
-<ul class='javatree'>
-	<li class='jc'>{@link oajr.client2.RestClient}
-	<ul>
-		<li class='jm'>{@link oajr.client2.RestClient#getRemote(Class) getRemote(Class)}
-		<li class='jm'>{@link oajr.client2.RestClient#getRemote(Class,Object) getRemote(Class,Object)}
-		<li class='jm'>{@link oajr.client2.RestClient#getRemote(Class,Object,Serializer,Parser) getRemote(Class,Object,Serializer,Parser)}
-	</ul>
-</ul>
-<p>
 	Annotations are used on the interface and interface methods to specify how to convert input and output to HTTP headers, query parameters, form 
 	post parameters, or request/response bodies.
 </p>
@@ -121,24 +62,30 @@ REST Proxies
 	<jk>public interface</jk> PetStore {
 		
 		<ja>@RemoteMethod</ja>(method=<jsf>POST</jsf>, path=<js>"/pets"</js>)
-		String addPet(
-			<ja>@Body</ja> CreatePet pet, 
-			<ja>@Header</ja>(<js>"E-Tag"</js>) UUID etag, 
-			<ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> debug
+		Pet addPet(
+			<ja>@Body</ja> CreatePet <jv>createPet</jv>, 
+			<ja>@Header</ja>(<js>"E-Tag"</js>) UUID <jv>etag</jv>, 
+			<ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> <jv>debug</jv>
 		);
 	}
 </p>
+
 <p class='bpcode w800'>	
 	<jc>// Use a RestClient with default Simple JSON support.</jc>
-	<jk>try</jk> (RestClient client = RestClient.<jsm>create</jsm>().simpleJson().build()) {
-		PetStore store = client.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
-		CreatePet pet = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99);
-		String response = store.createPet(pet, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>);
-	}
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build();
+	
+	<jc>// Instantiate our proxy interface.</jc>
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
+	
+	<jc>// Use it to create a pet.</jc>
+	CreatePet <jv>createPet</jv> = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99);
+	Pet <jv>pet</jv> = <jv>store</jv>.addPet(<jv>createPet</jv>, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>);
 </p>
+
 <p>
 	The call above translates to the following REST call:
 </p>
+
 <p class='bpcode w800'>
 	POST http://localhost:10000/petstore/pets?debug=true HTTP/1.1
 	Accept: application/json
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/01.Remote.html b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/01.Remote.html
index 17a1a55..f50fdf0 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/01.Remote.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/01.Remote.html
@@ -1,31 +1,37 @@
 <!--
 /***************************************************************************************************************************
- * 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.
+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.
  ***************************************************************************************************************************/
  -->
 
-{8.1.2-updated} 
+{8.1.2-updated,8.1.4-updated} 
 @Remote
 
 <p>
 	The {@link oaj.http.remote.Remote @Remote} annotation is used on your interface class
 	to identify it as a REST proxy interface.
 </p>
+
 <ul class='javatree'>
 	<li class='ja'>{@link oaj.http.remote.Remote}
 	<ul>
 		<li class='jf'>{@link oaj.http.remote.Remote#path path}
+		<li class='jf'>{@link oaj.http.remote.Remote#headers headers}
+		<li class='jf'>{@link oaj.http.remote.Remote#headerSupplier headerSupplier}
+		<li class='jf'>{@link oaj.http.remote.Remote#version version}
+		<li class='jf'>{@link oaj.http.remote.Remote#versionHeader versionHeader}
 	</ul>
 </ul>
+
 <p>
 	The <ja>@Remote</ja> annotation is optional, but often included for code readability.
 </p>
@@ -35,39 +41,137 @@
 	The {@link oaj.http.remote.Remote#path @Remote(path)} annotation is used to define the
 	HTTP path of the REST service.
 </p>
+
 <p>
 	The path can be an absolute path to your REST service.
 </p>
+
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>	
 	<ja>@Remote</ja>(path=<js>"http://localhost:10000/petstore"</js>)
 	<jk>public interface</jk> PetStore {...}
 </p>
 <p class='bpcode w800'>	
-	PetStore p = client.getRemote(PetStore.<jk>class</jk>);
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>);
+</p>
+
+<p>
+	{@doc DefaultSvlVariables} can also be used in the path.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>	
+	<jc>// URL is specified via a system property.</jc>
+	<ja>@Remote</ja>(path=<js>"$P{PetStoreUrl}"</js>)
+	<jk>public interface</jk> PetStore {...}
 </p>
+
 <p>
 	When a relative path is specified, it's relative to the root-url defined on the <c>RestClient</c> used to instantiate the interface.
 </p>
+
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>	
 	<ja>@Remote</ja>(path=<js>"/petstore"</js>)
 	<jk>public interface</jk> PetStore {...}
 </p>
 <p class='bpcode w800'>
-	RestClient client = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000"</js>).build();	
-	PetStore p = client.getRemote(PetStore.<jk>class</jk>);
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.json()
+		.rootUrl(<js>"http://localhost:10000"</js>)
+		.build();
+			
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>);
 </p>
+
 <p>
 	When no path is specified, the root-url defined on the <c>RestClient</c> is used.
 </p>
+
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>	
 	<ja>@Remote</ja>
 	<jk>public interface</jk> PetStore {...}
 </p>
 <p class='bpcode w800'>
-	RestClient client = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000/petstore"</js>).build();	
-	PetStore p = client.getRemote(PetStore.<jk>class</jk>);
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.json()
+		.rootUrl(<js>"http://localhost:10000/petstore"</js>)
+		.build();
+			
+	PetStore <jv>store</jv> = <jv>client<jv>.getRemote(PetStore.<jk>class</jk>);
+</p>
+
+
+<h5 class='topic'>@Remote(headers/headerSupplier)</h5>
+<p>
+	The {@link oaj.http.remote.Remote#headers @Remote(headers)} and {@link oaj.http.remote.Remote#headerSupplier @Remote(headerSupplier)} 
+	annotations are used to add headers on all requests.  
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>	
+	<ja>@Remote</ja>(
+		path=<js>"/petstore"</js>,
+		headers={
+			<js>"Foo: bar"</js>,
+			<js>"Baz: $P{bazProperty}"</js>
+		},
+		headerSupplier=MyDynamicHeaderSupplier.<jk>class</jk>
+	)
+	<jk>public interface</jk> PetStore {...}
+</p>
+<p class='bpcode w800'>
+	<jc>// Our dynamic supplier.</jc>
+	<jk>public class</jk> MyHeaderSupplier <jk>extends</jk> HeaderSupplier {
+	
+		<jc>// Headers can be added here at runtime.</jc>
+		<jk>public static</jk> HeaderSupplier <jsf>DYNAMIC_HEADERS</jsf> = <jk>new</jk> HeaderSupplier();
+	
+		<jk>public</jk> MyHeaderSupplier() {
+			add(<js>"Qux"</js>,<js>"q2x"</js>);  
+			add(<jsf>DYNAMIC_HEADERS</jsf>);
+		}
+	}
+</p>
+
+
+<h5 class='topic'>@Remote(version/versionHeader)</h5>
+<p>
+	The {@link oaj.http.remote.Remote#version @Remote(version)} and {@link oaj.http.remote.Remote#versionHeader @Remote(versionHeader)} 
+	annotations are used to specify the client-side version of this interface that can be used on the server side
+	to perform version-specific handling.
+</p>
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>	
+	<ja>@Remote</ja>(
+		path=<js>"/petstore"</js>,
+		version=<js>"1.2.3"</js>  <jc>// Adds "X-Client-Version: 1.2.3" header to all requests.</jc>
+	)
+	<jk>public interface</jk> PetStore {...}
+</p>
+
+<p>
+	This can be used in conjunction with the server-side client-versioning support.
+</p>
+<p class='bpcode w800'>
+	<jc>// Call this method if X-Client-Version is at least 2.0.
+	// Note that this also matches 2.0.1.</jc>
+	<ja>@RestMethod</ja>(clientVersion=<js>"2.0"</js>)
+	<jk>public</jk> Object getFoo()  {...}
+
+	<jc>// Call this method if X-Client-Version is at least 1.1, but less than 2.0.</jc>
+	<ja>@RestMethod</ja>(clientVersion=<js>"[1.1,2.0)"</js>)
+	<jk>public</jk> Object getFoo()  {...}
+
+	<jc>// Call this method if X-Client-Version is less than 1.1.</jc>
+	<ja>@RestMethod</ja>(clientVersion=<js>"[0,1.1)"</js>)
+	<jk>public</jk> Object getFoo()  {...}
 </p>
 
+<ul class='seealso'>
+	<li class='doclink'>{@doc juneau-rest-server.ClientVersioning}
+</ul>
+
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/02.RemoteMethod.html b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/02.RemoteMethod.html
index d4f9c39..0f500ba 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/02.RemoteMethod.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/02.RemoteMethod.html
@@ -39,7 +39,7 @@
 		
 		<jc>// GET /pets/{petId}</jc>
 		<ja>@RemoteMethod</ja>(method=<js>"GET"</js>, path=<js>"/pets/{petId}"</js>)
-		Pet getPet(<ja>@Path</ja>(<js>"petId"</js>) <jk>int</jk> id);
+		Pet getPet(<ja>@Path</ja>(<js>"petId"</js>) <jk>int</jk> <jv>id</jv>);
 	}
 </p>
 <p>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/03.Body.html b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/03.Body.html
index edd6fb6..baa4b0b 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/03.Body.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/03.Body.html
@@ -23,7 +23,7 @@
 	<li class='ja'>{@link oaj.http.annotation.Body}
 	<ul>
 		<li class='jf'>{@link oaj.http.annotation.Body#required() required} - Input validation.  Body must be present.
-		<li class='jf'>{@link oaj.http.annotation.Body#schema() schema} - Swagger schema.
+		<li class='jf'>{@link oaj.http.annotation.Body#schema() schema} - OpenAPI schema.
 	</ul>
 </ul>
 
@@ -34,7 +34,7 @@
 	<jk>public interface</jk> PetStore {
 
 		<ja>@RemoteMethod</ja>(path=<js>"/pets"</js>)
-		String addPet(<ja>@Body</ja> Pet pet);
+		String addPet(<ja>@Body</ja> Pet <jv>pet</jv>;
 	}
 </p>
 <p class='bpcode w800'>
@@ -43,7 +43,7 @@
 	<jk>public interface</jk> PetStore {
 
 		<ja>@RemoteMethod</ja>(path=<js>"/pets"</js>)
-		String addPet(Pet pet);
+		String addPet(Pet <jv>pet</jv>);
 	}
 
 	<ja>@Body</ja>
@@ -64,7 +64,7 @@
 		{@link java.io.InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
 		<br><c>Content-Type</c> is set to <js>"application/octet-stream"</js>.
 	<li>
-		<c>NameValuePairs</c> - Converted to a URL-encoded FORM post.
+		{@link oaj.http.NameValuePairSupplier} - Converted to a URL-encoded FORM post.
 		<br><c>Content-Type</c> is set to <js>"aplication/x-www-form-urlencoded"</js>.
 	<li>
 		<c>HttpEntity</c> - Bypass Juneau serialization and pass HttpEntity directly to HttpClient.
@@ -93,7 +93,20 @@
 				)
 			)
 		)
-		<jk>int</jk>[][] input
+		<jk>int</jk>[][] <jv>input</jv>
+	);
+</p>
+<p class='bpcode w800'>
+	<jc>// Same as above but using free-form schema.</jc>
+	<ja>@RemoteMethod</ja>(path=<js>"/comma-delimited-pipe-delimited-ints"</js>)
+	String addCommaDelimitedPipeDelimitedInts(
+		<ja>@Body</ja>(
+			serializer=OpenApiSerializer.<jk>class</jk>,
+			schema=<ja>@Schema</ja>(
+				<js>"type:'array,collectionFormat:'pipes',items:[type:'array',items:[type:'int32',minimum:0,maximum:64]]"</js>
+			)
+		)
+		<jk>int</jk>[][] <jv>input</jv>
 	);
 </p>
 <p>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/04.FormData.html b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/04.FormData.html
index a813e80..9a43d5c 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/04.FormData.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/04.FormData.html
@@ -55,30 +55,30 @@
 		<jc>// Explicit names specified for form data parameters.</jc>
 		<ja>@RemoteMethod</ja>
 		String postParameters(
-			<ja>@FormData</ja>(<js>"foo"</js>)</ja> String foo,
-			<ja>@FormData</ja>(<js>"bar"</js>)</ja> MyPojo pojo
+			<ja>@FormData</ja>(<js>"foo"</js>)</ja> String <jv>foo</jv>,
+			<ja>@FormData</ja>(<js>"bar"</js>)</ja> MyPojo <jv>pojo</jv>
 		);
 
-		<jc>// Multiple values pulled from a NameValuePairs object.</jc>
+		<jc>// Multiple values pulled from a NameValuePairSupplier object.</jc>
 		<jc>// Name "*" is inferred.</jc>
 		<ja>@RemoteMethod</ja>
-		String postNameValuePairs(<ja>@FormData</ja> NameValuePairs nameValuePairs);
+		String postNameValuePairs(<ja>@FormData</ja> NameValuePairSupplier <jv>nameValuePairSupplier</jv>);
 
 		<jc>// Multiple values pulled from a Map.</jc>
 		<ja>@RemoteMethod</ja>
-		String postMap(<ja>@FormData</ja> Map&lt;String,Object&gt; map);
+		String postMap(<ja>@FormData</ja> Map&lt;String,Object&gt; <jv>map</jv>);
 
 		<jc>// Multiple values pulled from a bean.</jc>
 		<ja>@RemoteMethod</ja>
-		String postBean(<ja>@FormData</ja> MyBean bean);
+		String postBean(<ja>@FormData</ja> MyBean <jv>bean</jv>);
 
 		<jc>// An entire form-data HTTP body as a String.</jc>
 		<ja>@RemoteMethod</ja>
-		String postString(<ja>@FormData</ja> String string);
+		String postString(<ja>@FormData</ja> String <jv>string</jv>);
 
 		<jc>// An entire form-data HTTP body as a Reader.</jc>
 		<ja>@RemoteMethod</ja>
-		String postReader(<ja>@FormData</ja> Reader reader);
+		String postReader(<ja>@FormData</ja> Reader <jv>reader</jv>);
 	}
 </p>
 
@@ -99,7 +99,7 @@
 	<li>
 		{@link java.io.InputStream} - Raw contents of {@code InputStream} will be serialized to remote resource.
 	<li>
-		<c>NameValuePairs</c> - Converted to a URL-encoded FORM post.
+		{@link oaj.http.NameValuePairSupplier} - Converted to a URL-encoded FORM post.
 	<li>
 		<c>Map</c> - Converted to key-value pairs.
 			<br>Values serialized using the registered {@link oaj.httppart.HttpPartSerializer} ({@link oaj.oapi.OpenApiSerializer} by default).
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/05.Query.html b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/05.Query.html
index c152440..1f4325c 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/05.Query.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/05.Query.html
@@ -55,33 +55,33 @@
 		<jc>// Explicit names specified for query parameters.</jc>
 		<ja>@RemoteMethod</ja>
 		String parameters(
-			<ja>@Query</ja>(<js>"foo"</js>)</ja> String foo,
-			<ja>@Query</ja>(<js>"bar"</js>)</ja> MyPojo pojo);
+			<ja>@Query</ja>(<js>"foo"</js>)</ja> String <jv>foo</jv>,
+			<ja>@Query</ja>(<js>"bar"</js>)</ja> MyPojo <jv>pojo</jv>);
  
-		<jc>// Multiple values pulled from a NameValuePairs object.</jc>
+		<jc>// Multiple values pulled from a NameValuePairSupplier object.</jc>
 		<jc>// Same as @Query("*").</jc>
 		<ja>@RemoteMethod</ja>
-		String nameValuePairs(<ja>@Query</ja> NameValuePairs nameValuePairs);
+		String nameValuePairs(<ja>@Query</ja> NameValuePairSupplier <jv>nameValuePairSupplier</jv>);
  
 		<jc>// Multiple values pulled from a Map.</jc>
 		<jc>// Same as @Query("*").</jc>
 		<ja>@RemoteMethod</ja>
-		String map(<ja>@Query</ja> Map&lt;String,Object&gt; map);
+		String map(<ja>@Query</ja> Map&lt;String,Object&gt; <jv>map</jv>);
 
 		<jc>// Multiple values pulled from a bean.</jc>
 		<jc>// Same as @Query("*").</jc>
 		<ja>@RemoteMethod</ja>
-		String bean(<ja>@Query</ja> MyBean myBean);
+		String bean(<ja>@Query</ja> MyBean <jv>myBean</jv>);
 
 		<jc>// An entire query string as a String.</jc>
 		<jc>// Same as @Query("*").</jc>
 		<ja>@RemoteMethod</ja>
-		String string(<ja>@Query</ja> String string);
+		String string(<ja>@Query</ja> String <jv>string</jv>);
 
 		<jc>// An entire query string as a Reader.</jc>
 		<jc>// Same as @Query("*").</jc>
 		<ja>@RemoteMethod</ja>
-		String reader(<ja>@Query</ja> Reader reader);
+		String reader(<ja>@Query</ja> Reader <jv>reader</jv>);
 	}
 </p>
 
@@ -101,7 +101,7 @@
 	<li>
 		{@link java.io.Reader} - Raw contents of {@code Reader} will be serialized directly a query string.
 	<li>
-		<c>NameValuePairs</c> - Serialized as individual query parameters.
+		{@link oaj.http.NameValuePairSupplier} - Serialized as individual query parameters.
 	<li>
 		<c>Map</c> - Converted to key-value pairs.
 			<br>Values serialized using the registered {@link oaj.httppart.HttpPartSerializer} ({@link oaj.oapi.OpenApiSerializer} by default).
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/06.Header.html b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/06.Header.html
index 72bba67..ea8f6dd 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/06.Header.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/06.Header.html
@@ -55,23 +55,23 @@
 		<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);
+		String myProxyMethod1(<ja>@Header</ja>(<js>"Foo"</js>)</ja> String <jv>foo</jv>,
+			<ja>@Header</ja>(<js>"Bar"</js>)</ja> MyPojo <jv>pojo</jv>);
 
-		<jc>// Multiple values pulled from a NameValuePairs object.</jc>
+		<jc>// Multiple values pulled from a HeaderSupplier object.</jc>
 		<jc>// Same as @Header("*").</jc>
 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod2"</js>)
-		String myProxyMethod2(<ja>@Header</ja> NameValuePairs nameValuePairs);
+		String myProxyMethod2(<ja>@Header</ja> HeaderSupplier <jv>headerSupplier</jv>);
 
 		<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);
+		String myProxyMethod3(<ja>@Header</ja> Map&lt;String,Object&gt; <jv>map</jv>);
 
 		<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);
+		String myProxyMethod4(<ja>@Header</ja> MyBean <jv>myBean</jv>);
 	}
 </p>
 
@@ -89,7 +89,7 @@
 </p>
 <ul class='spaced-list'>
 	<li>
-		<c>NameValuePairs</c> - Serialized as individual headers.
+		{@link oaj.http.HeaderSupplier} - Serialized as individual headers.
 	<li>
 		<c>Map</c> - Converted to key-value pairs.
 			<br>Values serialized using the registered {@link oaj.httppart.HttpPartSerializer} ({@link oaj.oapi.OpenApiSerializer} by default).
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/07.Path.html b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/07.Path.html
index 2f226b6..93c1c5f 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/07.Path.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/07.Path.html
@@ -49,22 +49,22 @@
 		<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);
+		String myProxyMethod1(<ja>@Path</ja>(<js>"foo"</js>)</ja> String <jv>foo</jv>, <ja>@Path</ja>(<js>"bar"</js>)</ja> MyPojo <jv>pojo</jv>);
 
-		<jc>// Multiple values pulled from a NameValuePairs object.</jc>
+		<jc>// Multiple values pulled from a NameValuePairSupplier object.</jc>
 		<jc>// Same as @Path("*").</jc>
 		<ja>@RemoteMethod</ja>(path=<js>"/mymethod2/{foo}/{bar}/{baz}"</js>)
-		String myProxyMethod2(<ja>@Path</ja> NameValuePairs nameValuePairs);
+		String myProxyMethod2(<ja>@Path</ja> NameValuePairSupplier <jv>nameValuePairSupplier</jv>);
 
 		<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);
+		String myProxyMethod3(<ja>@Path</ja> Map&lt;String,Object&gt; <jv>map</jv>);
 
 		<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);
+		String myProxyMethod4(<ja>@Path</ja> MyBean <jv>myBean</jv>);
 	}
 </p>
 
@@ -82,7 +82,7 @@
 </p>
 <ul class='spaced-list'>
 	<li>
-		<c>NameValuePairs</c> - Serialized as individual query parameters.
+		{@link oaj.http.NameValuePairSupplier} - Serialized as individual path parameters.
 	<li>
 		<c>Map</c> - Converted to key-value pairs.
 			<br>Values serialized using the registered {@link oaj.httppart.HttpPartSerializer} ({@link oaj.oapi.OpenApiSerializer} by default).
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/08.Request.html b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/08.Request.html
index e293d1d..a8279ea 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/08.Request.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/08.Request.html
@@ -34,7 +34,7 @@
 	<jk>public interface</jk> PetStore {
 
 		<ja>@RemoteMethod</ja>
-		String postPet(CreatePetRequest bean);
+		String postPet(CreatePetRequest <jv>bean</jv>);
 	}
 </p>
 <p class='bpcode w800'>
@@ -43,8 +43,8 @@
 	
 		<jk>private</jk> CreatePet <jf>pet</jf>;
 	
-		<jk>public</jk> CreatePetRequest(String name, <jk>float</jk> price) {
-			<jk>this</jk>.<jf>pet</jf> = <jk>new</jk> CreatePet(name, price);
+		<jk>public</jk> CreatePetRequest(String <jv>name</jv>, <jk>float</jk> <jv>price</jv>) {
+			<jk>this</jk>.<jf>pet</jf> = <jk>new</jk> CreatePet(<jv>name</jv>, <jv>price</jv>);
 		}
 		
 		<ja>@Body</ja>
@@ -54,7 +54,7 @@
 	
 		<ja>@Query</ja>
 	 	<jk>public</jk> Map&lt;String,Object&gt; getQueryParams() {
-	 		<jk>return</jk> OMap.<jsm>of</jsm>(<js>"debug"</js>, <jk>true</jk>);
+	 		<jk>return</jk> AMap.<jsm>of</jsm>(<js>"debug"</js>, <jk>true</jk>);
 	 	}
 	 	
 	 	<ja>@Header</ja>(<js>"E-Tag"</js>)
@@ -64,9 +64,10 @@
 	}
 </p>
 <p class='bpcode w800'>
-	PetStore store = restClient.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
-	CreatePetRequest requestBean = <jk>new</jk> CreatePetRequest(<js>"Fluffy"</js>, 9.99);
-	String response = store.postPet(requestBean);
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
+	
+	CreatePetRequest <jv>requestBean</jv> = <jk>new</jk> CreatePetRequest(<js>"Fluffy"</js>, 9.99);
+	String <jv>response</jv> = <jv>store</jv>.postPet(requestBean);
 </p>
 <p>
 	The <ja>@Request</ja> annotation can be applied to either the class or argument.
@@ -110,7 +111,7 @@
 <p class='bpcode w800'>
 	<jk>public class</jk> CreatePetRequestImpl <jk>implements</jk> CreatePetRequest {
 	
-		<jk>public</jk> CreatePetRequestImpl(String name, <jk>float</jk> price) {...}
+		<jk>public</jk> CreatePetRequestImpl(String <jv>name</jv>, <jk>float</jk> <jv>price</jv>) {...}
 
 		<ja>@Override</ja>
 		<jk>public</jk> CreatePet getBody() {
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/09.Response.html b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/09.Response.html
index 3091286..466cea3 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/09.Response.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/09.Response.html
@@ -47,15 +47,16 @@
 		UUID getUUID();
 		
 		<ja>@ResponseStatus</ja>
-		int getStatus();
+		<jk>int</jk> getStatus();
 	}
 </p>
 <p class='bpcode w800'>
-	PetStore store = restClient.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
-	CreatePetResponse response = store.postPet(...);
-	Pet pet = response.getBody();
-	UUID uuid = response.getUUID();
-	<jk>int</jk> status = response.getStatus();
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
+	
+	CreatePetResponse <jv>response</jv> = <jv>store</jv>.postPet(...);
+	Pet <jv>pet</jv> = <jv>response</jv>.getBody();
+	UUID <jv>uuid</jv> = <jv>response</jv>.getUUID();
+	<jk>int</jk> <jv>status</jv> = <jv>response</jv>.getStatus();
 </p>
 <p>
 	The annotated methods must be no-arg.  
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/10.DualPurposeInterfaces.html b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/10.DualPurposeInterfaces.html
index cf1f937..830aaf7 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/10.DualPurposeInterfaces.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/11.RestProxies/10.DualPurposeInterfaces.html
@@ -46,13 +46,13 @@ Dual-purpose (end-to-end) interfaces
 				required=<jk>true</jk>,
 				example=<js>"foobar"</js>
 			)
-			String apiKey,
+			String <jv>apiKey</jv>,
 			<ja>@Path</ja>(
 				name=<js>"petId"</js>,
 				description=<js>"Pet id to delete"</js>,
 				example=<js>"123"</js>
 			)
-			<jk>long</jk> petId
+			<jk>long</jk> <jv>petId</jv>
 		) <jk>throws</jk> IdNotFound, NotAcceptable;
 		
 		...
@@ -88,8 +88,8 @@ Dual-purpose (end-to-end) interfaces
 			summary=<js>"Deletes a pet"</js>,
 			...
 		)
-		<jk>public</jk> Ok deletePet(String apiKey, long petId) <jk>throws</jk> IdNotFound, NotAcceptable {
-			<jsf>store</jsf>.removePet(petId);
+		<jk>public</jk> Ok deletePet(String <jv>apiKey</jv>, <jk>long</jk> <jv>petId</jv>) <jk>throws</jk> IdNotFound, NotAcceptable {
+			<jsf>store</jsf>.removePet(<jv>petId</jv>);
 			<jk>return</jk> <jsf>OK</jsf>;
 		}
 </p>
@@ -97,13 +97,12 @@ Dual-purpose (end-to-end) interfaces
 	Then use the interface as a remote resource like so:
 </p>
 <p class='bpcode w800'>
-	<jk>try</jk> (RestClient rc = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000"</js>).build()) {
-		PetStore ps = rc.getRemote(PetStore.<jk>class</jk>);
+	RestClient client = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000"</js>).build();
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>);
 
-		<jk>for</jk> (Pet x : ps.getPets()) {
-			ps.deletePet(<js>"my-special-key"</js>, x.getId());
-			System.<jsf>err</jsf>.println(<js>"Deleted pet:  id="</js> + x.getId());
-		}
+	<jk>for</jk> (Pet <jv>x</jv> : <jv>store</jv>.getPets()) {
+		<jv>store</jv>.deletePet(<js>"my-special-key"</js>, <jv>x</jv>.getId());
+		System.<jsf>err</jsf>.println(<js>"Deleted pet:  id="</js> + <jv>x</jv>.getId());
 	}
 </p>	
 <p>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/12.LoggingAndDebugging.html b/juneau-doc/docs/Topics/09.juneau-rest-client/12.LoggingAndDebugging.html
index ae6cfa2..ac81d49 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/12.LoggingAndDebugging.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/12.LoggingAndDebugging.html
@@ -35,13 +35,16 @@ Logging and Debugging
 
 <h5 class='figure'>Examples:</h5>
 <p class='bpcode w800'>
-	MyBean <jv>bean</jv> = RestClient
+	<jc>// A simple bean we're going to round-trip.</jc>
+	MyBean <jv>bean</jv> = <jk>new</jk> MyBean();
+	
+	<jv>bean</jv> = RestClient
 		.<jsm>create</jsm>()
 		.simpleJson()
-		.logRequests(DetailLevel.<jsf>FULL</jsf>, Level.<jsf>SEVERE</jsf>, (req,res)-&gt;req.getUri().endsWith(<js>"/bean"</js>))
+		.logRequests(DetailLevel.<jsf>FULL</jsf>, Level.<jsf>SEVERE</jsf>, (<jv>req</jv>,<jv>res</jv>)-&gt;<jv>req</jv>.getUri().endsWith(<js>"/bean"</js>))
 		.logToConsole()
 		.build()
-		.post(<js>"http://localhost/bean"</js>, <jv>anotherBean</jv>)
+		.post(<js>"http://localhost/bean"</js>, <jv>bean</jv>)
 		.run()
 		.getBody().as(MyBean.<jk>class</jk>);
 </p>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/13.CustomizingHttpClient.html b/juneau-doc/docs/Topics/09.juneau-rest-client/13.CustomizingHttpClient.html
index fe8ca73..4afbafb 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/13.CustomizingHttpClient.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/13.CustomizingHttpClient.html
@@ -46,5 +46,5 @@ Customizing HttpClient
 </p>
 
 <p>
-	Refer to the {@link org.apache.http.client.impl.HttpClientBuilder HTTP Client Builder API} for more information.
+	Refer to the {@link org.apache.http.client.impl.HttpClientBuilder HttpClientBuilder} docs for more information.
 </p>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/01.BASIC.html b/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/01.BASIC.html
index 9da2c80..0a64d1b 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/01.BASIC.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/01.BASIC.html
@@ -23,7 +23,7 @@ BASIC Authentication
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a client that performs BASIC authentication using the specified user/pw.</jc>
-	RestClient client = RestClient.<jsm>create</jsm>() 
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>() 
 		.basicAuth(<jsf>HOST</jsf>, <jsf>PORT</jsf>, <jsf>USER</jsf>, <jsf>PW</jsf>)
 		.build();
 </p>
@@ -31,10 +31,10 @@ BASIC Authentication
 	This is functionally equivalent to the following:
 </p>
 <p class='bpcode w800'>
-	RestClientBuilder builder = RestClient.<jsm>create</jsm>();
-	AuthScope scope = <jk>new</jk> AuthScope(<jsf>HOST</jsf>, <jsf>PORT</jsf>);
-	Credentials up = <jk>new</jk> UsernamePasswordCredentials(<jsf>USER</jsf>, <jsf>PW</jsf>);
-	CredentialsProvider p = <jk>new</jk> BasicCredentialsProvider();
-	p.setCredentials(scope, up);
-	builder.setDefaultCredentialsProvider(p);
+	RestClientBuilder <jv>builder</jv> = RestClient.<jsm>create</jsm>();
+	AuthScope <jv>scope</jv> = <jk>new</jk> AuthScope(<jsf>HOST</jsf>, <jsf>PORT</jsf>);
+	Credentials <jv>up</jv> = <jk>new</jk> UsernamePasswordCredentials(<jsf>USER</jsf>, <jsf>PW</jsf>);
+	CredentialsProvider <jv>p</jv> = <jk>new</jk> BasicCredentialsProvider();
+	<jv>p</jv>.setCredentials(<jv>scope</jv>, <jv>up</jv>);
+	<jv>builder</jv>.setDefaultCredentialsProvider(<jv>p</jv>);
 </p>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/02.FORM.html b/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/02.FORM.html
index 0f2614d..9cdaffd 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/02.FORM.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/02.FORM.html
@@ -24,14 +24,14 @@ FORM-based Authentication
 	authenticated client.
 </p>
 <p>
-	The following example shows how the <c>JazzRestClient</c> class provides FORM-based 
-	authentication support.
+	The following example shows an implementation of a client that performs FORM-based authentication against
+	the IBM Jazz platform.
 </p>
 <p class='bpcode w800'>
 	<jd>/**
 	 * Constructor.
 	 */</jd>
-	<jk>public</jk> JazzRestClientBuilder(URI jazzUri, String user, String pw) <jk>throws</jk> IOException {
+	<jk>public</jk> JazzRestClientBuilder(URI <jv>jazzUri</jv>, String <jv>user</jv>, String <jv>pw</jv>) <jk>throws</jk> IOException {
 		...
 	}
 
@@ -40,46 +40,47 @@ FORM-based Authentication
 	 */</jd>
 	<ja>@Override</ja> <jc>/* RestClientBuilder */</jc>
 	<jk>protected</jk> CloseableHttpClient createHttpClient() <jk>throws</jk> Exception {
-		CloseableHttpClient client = <jk>super</jk>.createHttpClient();
-		formBasedAuthenticate(client);
-		visitAuthenticatedURL(client);
-		<jk>return</jk> client;
+		CloseableHttpClient <jv>client</jv> = <jk>super</jk>.createHttpClient();
+		formBasedAuthenticate(<jv>client</jv>);
+		visitAuthenticatedURL(<jv>client</jv>);
+		<jk>return</jk> <jv>client</jv>;
 	}
 
 	<jc>/*
 	 * Performs form-based authentication against the Jazz server.
 	 */</jc>
-	<jk>private void</jk> formBasedAuthenticate(HttpClient client) <jk>throws</jk> IOException {
+	<jk>private void</jk> formBasedAuthenticate(HttpClient <jv>client</jv>) <jk>throws</jk> IOException {
 
-		URI uri2 = <jf>jazzUri</jf>.resolve(<js>"j_security_check"</js>);
-		HttpPost request = <jk>new</jk> HttpPost(uri2);
-		request.setConfig(RequestConfig.<jsm>custom</jsm>().setRedirectsEnabled(<jk>false</jk>).build());
+		URI <jv>uri2</jv> = <jf>jazzUri</jf>.resolve(<js>"j_security_check"</js>);
+		HttpPost <jv>request</jv> = <jk>new</jk> HttpPost(uri2);
+		<jv>request</jv>.setConfig(RequestConfig.<jsm>custom</jsm>().setRedirectsEnabled(<jk>false</jk>).build());
 		
 		<jc>// Charset must explicitly be set to UTF-8 to handle user/pw with non-ascii characters.</jc>
-		request.addHeader(<js>"Content-Type"</js>, <js>"application/x-www-form-urlencoded; charset=utf-8"</js>);
+		<jv>request</jv>.addHeader(<js>"Content-Type"</js>, <js>"application/x-www-form-urlencoded; charset=utf-8"</js>);
 
-		NameValuePairs params = <jk>new</jk> NameValuePairs()
-			.append(<jk>new</jk> BasicNameValuePair(<js>"j_username""</js>, <jf>user</jf>))
-			.append(<jk>new</jk> BasicNameValuePair(<js>"j_password"</js>, <jf>pw</jf>));
-		request.setEntity(<jk>new</jk> UrlEncodedFormEntity(params));
+		List&lt;NameValuePair&gt; <jv>params</jv> = AList.<jsm>of</jsm>(
+			BasicNameValuePair.<jsm>of</jsm>(<js>"j_username""</js>, <jf>user</jf>),
+			BasicNameValuePair.<jsm>of</jsm>(<js>"j_password"</js>, <jf>pw</jf>)
+		);
+		<jv>request</jv>.setEntity(<jk>new</jk> UrlEncodedFormEntity(<jv>params</jv>));
 
-		HttpResponse response = client.execute(request);
+		HttpResponse <jv>response</jv> = <jv>client</jv>.execute(<jv>request</jv>);
 		<jk>try</jk> {
-			<jk>int</jk> rc = response.getStatusLine().getStatusCode();
+			<jk>int</jk> <jv>rc</jv> = <jv>response</jv>.getStatusLine().getStatusCode();
 
-			Header authMsg = response.getFirstHeader(<js>"X-com-ibm-team-repository-web-auth-msg"</js>);
-			<jk>if</jk> (authMsg != <jk>null</jk>)
-				<jk>throw new</jk> IOException(authMsg.getValue());
+			Header <jv>authMsg</jv> = <jv>response</jv>.getFirstHeader(<js>"X-com-ibm-team-repository-web-auth-msg"</js>);
+			<jk>if</jk> (<jv>authMsg</jv> != <jk>null</jk>)
+				<jk>throw new</jk> IOException(<jv>authMsg</jv>.getValue());
 
 			<jc>// The form auth request should always respond with a 200 ok or 302 redirect code</jc>
-			<jk>if</jk> (rc == <jsf>SC_MOVED_TEMPORARILY</jsf>) {
-				<jk>if</jk> (response.getFirstHeader(<js>"Location"</js>).getValue().matches(<js>"^.*/auth/authfailed.*$"</js>))
+			<jk>if</jk> (<jv>rc</jv> == <jsf>SC_MOVED_TEMPORARILY</jsf>) {
+				<jk>if</jk> (<jv>response</jv>.getFirstHeader(<js>"Location"</js>).getValue().matches(<js>"^.*/auth/authfailed.*$"</js>))
 					<jk>throw new</jk> IOException(<js>"Invalid credentials."</js>);
-			} <jk>else if</jk> (rc != <jsf>SC_OK</jsf>) {
-				<jk>throw new</jk> IOException(<js>"Unexpected HTTP status: "</js> + rc);
+			} <jk>else if</jk> (<jv>rc</jv> != <jsf>SC_OK</jsf>) {
+				<jk>throw new</jk> IOException(<js>"Unexpected HTTP status: "</js> + <jv>rc</jv>);
 			}
 		} <jk>finally</jk> {
-			EntityUtils.<jsm>consume</jsm>(response.getEntity());
+			EntityUtils.<jsm>consume</jsm>(<jv>response</jv>.getEntity());
 		}
 	}
 
@@ -88,13 +89,13 @@ FORM-based Authentication
 	 * authenticated URL has been visited. This same URL must also be visited after authenticating with j_security_check
 	 * otherwise tomcat will not consider the session authenticated
 	 */</jc>
-	<jk>private int</jk> visitAuthenticatedURL(HttpClient httpClient) <jk>throws</jk> IOException {
-		HttpGet authenticatedURL = <jk>new</jk> HttpGet(<jf>jazzUri</jf>.resolve(<js>"authenticated/identity"</js>));
-		HttpResponse response = httpClient.execute(authenticatedURL);
+	<jk>private int</jk> visitAuthenticatedURL(HttpClient <jv>httpClient</jv>) <jk>throws</jk> IOException {
+		HttpGet <jv>authenticatedURL</jv> = <jk>new</jk> HttpGet(<jf>jazzUri</jf>.resolve(<js>"authenticated/identity"</js>));
+		HttpResponse <jv>response</jv> = <jv>httpClient</jv>.execute(<jv>authenticatedURL</jv>);
 		<jk>try</jk> {
-			<jk>return</jk> response.getStatusLine().getStatusCode();
+			<jk>return</jk> <jv>response</jv>.getStatusLine().getStatusCode();
 		} <jk>finally</jk> {
-			EntityUtils.<jsm>consume</jsm>(response.getEntity());
+			EntityUtils.<jsm>consume</jsm>(<jv>response</jv>.getEntity());
 		}
 	}
 </p>
diff --git a/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/03.OIDC.html b/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/03.OIDC.html
index ec1e021..118506b 100644
--- a/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/03.OIDC.html
+++ b/juneau-doc/docs/Topics/09.juneau-rest-client/15.Authentication/03.OIDC.html
@@ -16,14 +16,14 @@
 OIDC Authentication
 
 <p>
-	The following example shows how the <c>JazzRestClient</c> class provides OIDC authentication 
-	support.
+	The following example shows an implementation of a client that performs OIDC authentication against
+	the IBM Jazz platform.
 </p>
 <p class='bpcode w800'>
 	<jd>/**
 	 * Constructor.
 	 */</jd>
-	<jk>public</jk> JazzRestClientBuilder(URI jazzUri, String user, String pw) <jk>throws</jk> IOException {
+	<jk>public</jk> JazzRestClientBuilder(URI <jv>jazzUri</jv>, String <jv>user</jv>, String <jv>pw</jv>) <jk>throws</jk> IOException {
 		...
 	}
 
@@ -32,108 +32,108 @@ OIDC Authentication
 	 */</jd>
 	<ja>@Override</ja> <jc>/* RestClientBuilder */</jc>
 	<jk>protected</jk> CloseableHttpClient createHttpClient() <jk>throws</jk> Exception {
-		CloseableHttpClient client = <jk>super</jk>.createHttpClient();
-		oidcAuthenticate(client);
-			<jk>return</jk> client;
-		}
+		CloseableHttpClient <jv>client</jv> = <jk>super</jk>.createHttpClient();
+		oidcAuthenticate(<jv>client</jv>);
+		<jk>return</jk> <jv>client</jv>;
+	}
 
-	<jk>private void</jk> oidcAuthenticate(HttpClient client) <jk>throws</jk> IOException {
+	<jk>private void</jk> oidcAuthenticate(HttpClient <jv>client</jv>) <jk>throws</jk> IOException {
 
-		HttpGet request = <jk>new</jk> HttpGet(<jf>jazzUri</jf>);
-		request.setConfig(RequestConfig.<jsm>custom</jsm>().setRedirectsEnabled(<jk>false</jk>).build());
+		HttpGet <jv>request</jv> = <jk>new</jk> HttpGet(<jf>jazzUri</jf>);
+		<jv>request</jv>.setConfig(RequestConfig.<jsm>custom</jsm>().setRedirectsEnabled(<jk>false</jk>).build());
 		
 		<jc>// Charset must explicitly be set to UTF-8 to handle user/pw with non-ascii characters.</jc>
-		request.addHeader(<js>"Content-Type"</js>, <js>"application/x-www-form-urlencoded; charset=utf-8"</js>);
+		<jv>request</jv>.addHeader(<js>"Content-Type"</js>, <js>"application/x-www-form-urlencoded; charset=utf-8"</js>);
 
-		HttpResponse response = client.execute(request);
+		HttpResponse <jv>response</jv> = <jv>client</jv>.execute(<jv>request</jv>);
 		<jk>try</jk> {
-			<jk>int</jk> code = response.getStatusLine().getStatusCode();
+			<jk>int</jk> <jv>code</jv> = <jv>response</jv>.getStatusLine().getStatusCode();
 
 			<jc>// Already authenticated</jc>
-			<jk>if</jk> (code == <jsf>SC_OK</jsf>)
+			<jk>if</jk> (<jv>code</jv> == <jsf>SC_OK</jsf>)
 				<jk>return</jk>;
 
-			<jk>if</jk> (code != <jsf>SC_UNAUTHORIZED</jsf>)
+			<jk>if</jk> (<jv>code</jv> != <jsf>SC_UNAUTHORIZED</jsf>)
 				<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
 			<jc>// x-jsa-authorization-redirect</jc>
-			String redirectUri = getHeader(response, <js>"X-JSA-AUTHORIZATION-REDIRECT"</js>);
+			String <jv>redirectUri</jv> = getHeader(<jv>response</jv>, <js>"X-JSA-AUTHORIZATION-REDIRECT"</js>);
 
-			<jk>if</jk> (redirectUri == <jk>null</jk>)
+			<jk>if</jk> (<jv>redirectUri</jv> == <jk>null</jk>)
 				<jk>throw new</jk> RestCallException(<js>"Expected a redirect URI during OIDC authentication: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
 			<jc>// Handle Bearer Challenge</jc>
-			HttpGet method = <jk>new</jk> HttpGet(redirectUri + <js>"&amp;prompt=none"</js>);
-			addDefaultOidcHeaders(method);
+			HttpGet <jv>method</jv> = <jk>new</jk> HttpGet(<jv>redirectUri</jv> + <js>"&amp;prompt=none"</js>);
+			addDefaultOidcHeaders(<jv>method</jv>);
 
-			response = client.execute(method);
+			<jv>response</jv> = <jv>client</jv>.execute(<jv>method</jv>);
 
-			code = response.getStatusLine().getStatusCode();
+			<jv>code</jv> = <jv>response</jv>.getStatusLine().getStatusCode();
 
-			<jk>if</jk> (code != <jsf>SC_OK</jsf>)
+			<jk>if</jk> (<jv>code</jv> != <jsf>SC_OK</jsf>)
 				<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication phase 2: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
-			String loginRequired = getHeader(response, <js>"X-JSA-LOGIN-REQUIRED"</js>);
+			String <jv>loginRequired</jv> = getHeader(<jv>response</jv>, <js>"X-JSA-LOGIN-REQUIRED"</js>);
 
-			<jk>if</jk> (! <js>"true"</js>.equals(loginRequired))
+			<jk>if</jk> (! <js>"true"</js>.equals(<jv>loginRequired</jv>))
 				<jk>throw new</jk> RestCallException(<js>"X-JSA-LOGIN-REQUIRED header not found on response during OIDC authentication phase 2: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
-			method = <jk>new</jk> HttpGet(redirectUri + <js>"&amp;prompt=none"</js>);
+			<jv>method</jv> = <jk>new</jk> HttpGet(<jv>redirectUri</jv> + <js>"&amp;prompt=none"</js>);
 
-			addDefaultOidcHeaders(method);
-			response = client.execute(method);
+			addDefaultOidcHeaders(<jv>method</jv>);
+			<jv>response</jv> = <jv>client</jv>.execute(<jv>method</jv>);
 
-			code = response.getStatusLine().getStatusCode();
+			<jv>code</jv> = <jv>response</jv>.getStatusLine().getStatusCode();
 
-			<jk>if</jk> (code != <jsf>SC_OK</jsf>)
+			<jk>if</jk> (<jv>code</jv> != <jsf>SC_OK</jsf>)
 				<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication phase 3: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
 			<jc>// Handle JAS Challenge</jc>
-			method = <jk>new</jk> HttpGet(redirectUri);
-			addDefaultOidcHeaders(method);
+			<jv>method</jv> = <jk>new</jk> HttpGet(<jv>redirectUri</jv>);
+			addDefaultOidcHeaders(<jv>method</jv>);
 
-			response = client.execute(method);
+			<jv>response</jv> = <jv>client</jv>.execute(<jv>method</jv>);
 
-			code = response.getStatusLine().getStatusCode();
+			<jv>code</jv> = <jv>response</jv>.getStatusLine().getStatusCode();
 
-			<jk>if</jk> (code != <jsf>SC_OK</jsf>)
+			<jk>if</jk> (<jv>code</jv> != <jsf>SC_OK</jsf>)
 				<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication phase 4: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
-			<jf>cookie</jf> = getHeader(response, <js>"Set-Cookie"</js>);
+			<jf>cookie</jf> = getHeader(<jv>response</jv>, <js>"Set-Cookie"</js>);
 
-			Header[] defaultHeaders = <jk>new</jk> Header[] {
-				<jk>new</jk> BasicHeader(<js>"User-Agent"</js>, <js>"Jazz Native Client"</js>),
-				<jk>new</jk> BasicHeader(<js>"X-com-ibm-team-configuration-versions"</js>, 
+			Header[] <jv>defaultHeaders</jv> = <jk>new</jk> Header[] {
+				BasicStringHeader.<jsm>of</jsm>(<js>"User-Agent"</js>, <js>"Jazz Native Client"</js>),
+				BasicStringHeader.<jsm>of</jsm>(<js>"X-com-ibm-team-configuration-versions"</js>, 
 					<js>"com.ibm.team.rtc=6.0.0,com.ibm.team.jazz.foundation=6.0"</js>),
-				<jk>new</jk> BasicHeader(<js>"Accept"</js>, <js>"text/json"</js>),
-				<jk>new</jk> BasicHeader(<js>"Authorization"</js>, <js>"Basic "</js> 
+				BasicStringHeader.<jsm>of</jsm>(<js>"Accept"</js>, <js>"text/json"</js>),
+				BasicStringHeader.<jsm>of</jsm>(<js>"Authorization"</js>, <js>"Basic "</js> 
 					+ StringUtils.<jsm>base64EncodeToString</jsm>(<jf>user</jf> + <js>":"</js> + <jf>pw</jf>)),
-				<jk>new</jk> BasicHeader(<js>"Cookie"</js>, cookie)
+				BasicStringHeader.<jsm>of</jsm>(<js>"Cookie"</js>, <jf>cookie</jf>)
 			};
 
-			setDefaultHeaders(Arrays.<jsm>asList</jsm>(defaultHeaders));
+			setDefaultHeaders(AList.<jsm>of</jsm>(<jv>defaultHeaders</jv>));
 
 		} <jk>finally</jk> {
-			EntityUtils.<jsm>consume</jsm>(response.getEntity());
+			EntityUtils.<jsm>consume</jsm>(<jv>response</jv>.getEntity());
 		}
 	}
 
-	<jk>private void</jk> addDefaultOidcHeaders(HttpRequestBase method) {
-		method.addHeader(<js>"User-Agent"</js>, <js>"Jazz Native Client"</js>);
-		method.addHeader(<js>"X-com-ibm-team-configuration-versions"</js>, 
+	<jk>private void</jk> addDefaultOidcHeaders(HttpRequestBase <jv>method</jv>) {
+		<jv>method</jv>.addHeader(<js>"User-Agent"</js>, <js>"Jazz Native Client"</js>);
+		<jv>method</jv>.addHeader(<js>"X-com-ibm-team-configuration-versions"</js>, 
 			<js>"com.ibm.team.rtc=6.0.0,com.ibm.team.jazz.foundation=6.0"</js>);
-		method.addHeader(<js>"Accept"</js>, <js>"text/json"</js>);
+		<jv>method</jv>.addHeader(<js>"Accept"</js>, <js>"text/json"</js>);
 
 		<jk>if</jk> (<jf>cookie</jf> != <jk>null</jk>) {
-			method.addHeader(<js>"Authorization"</js>, <js>"Basic "</js> 
+			<jv>method</jv>.addHeader(<js>"Authorization"</js>, <js>"Basic "</js> 
 				+ StringUtils.<jsm>base64EncodeToString</jsm>(<jf>user</jf> + <js>":"</js> + <jf>pw</jf>));
-			method.addHeader(<js>"Cookie"</js>, cookie);
+			<jv>method</jv>.addHeader(<js>"Cookie"</js>, <jf>cookie</jf>);
 		}
 	}
 </p>	
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index 905f17e..635639c 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -470,9 +470,9 @@
 		<li><p><a class='doclink' href='#juneau-rest-client.ResponseBody'>Response Body</a><span class='update'><b>8.1.4-new</b></span></p>
 		<li><p><a class='doclink' href='#juneau-rest-client.CustomCallHandlers'>Custom Call Handlers</a><span class='update'><b>8.1.4-new</b></span></p>
 		<li><p><a class='doclink' href='#juneau-rest-client.Interceptors'>Interceptors</a><span class='update'><b>8.1.4-new</b></span></p>
-		<li><p><a class='doclink' href='#juneau-rest-client.RestProxies'>REST Proxies</a><span class='update'><b>8.1.4-new</b></span></p>
+		<li><p><a class='doclink' href='#juneau-rest-client.RestProxies'>REST Proxies</a><span class='update'><b>8.1.4-updated</b></span></p>
 		<ol>
-			<li><p><a class='doclink' href='#juneau-rest-client.RestProxies.Remote'>@Remote</a><span class='update'>8.1.2-updated</span></p>
+			<li><p><a class='doclink' href='#juneau-rest-client.RestProxies.Remote'>@Remote</a><span class='update'>8.1.2-updated,<b>8.1.4-updated</b></span></p>
 			<li><p><a class='doclink' href='#juneau-rest-client.RestProxies.RemoteMethod'>@RemoteMethod</a><span class='update'><b>8.1.4-updated</b></span></p>
 			<li><p><a class='doclink' href='#juneau-rest-client.RestProxies.Body'>@Body</a></p>
 			<li><p><a class='doclink' href='#juneau-rest-client.RestProxies.FormData'>@FormData</a></p>
@@ -22579,7 +22579,7 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a basic REST client with JSON support and download a bean.</jc>
-	MyBean bean = RestClient.<jsm>create</jsm>()
+	MyBean <jv>bean</jv> = RestClient.<jsm>create</jsm>()
 		.simpleJson()
 		.build()
 		.get(<jsf>URI</jsf>)
@@ -22594,17 +22594,17 @@
 </p>
 
 <p class='bpcode w800'>
-	RestClientBuilder builder = RestClient.<jsm>create</jsm>().simpleJson();
-	RestClient client = builder.build();
-	RestRequest req = client.get(<jsf>URI</jsf>);
-	RestResponse res = req.run();
-	RestResponseStatusLineAssertion statusLineAssertion = res.assertStatus();
-	FluentIntegerAssertion&lt;RestResponse&gt; codeAssertion = statusLineAssertion.code();
-	res = codeAssertion.is(200);
-	FluentStringAssertion&lt;RestResponse&gt; headerAssertion = res.assertHeader(<js>"Content-Type"</js>);
-	res = headerAssertion.matchesSimple(<js>"application/json*"</js>);
-	RestResponseBody body = res.getBody();
-	MyBean bean = body.as(MyBean.<jk>class</jk>);
+	RestClientBuilder <jv>builder</jv> = RestClient.<jsm>create</jsm>().simpleJson();
+	RestClient <jv>client</jv> = <jv>builder</jv>.build();
+	RestRequest <jv>req</jv> = <jv>client</jv>.get(<jsf>URI</jsf>);
+	RestResponse <jv>res</jv> = <jv>req</jv>.run();
+	RestResponseStatusLineAssertion <jv>statusLineAssertion</jv> = <jv>res</jv>.assertStatus();
+	FluentIntegerAssertion&lt;RestResponse&gt; <jv>codeAssertion</jv> = <jv>statusLineAssertion</jv>.code();
+	<jv>res</jv> = <jv>codeAssertion</jv>.is(200);
+	FluentStringAssertion&lt;RestResponse&gt; <jv>headerAssertion</jv> = <jv>res</jv>.assertHeader(<js>"Content-Type"</js>);
+	<jv>res</jv> = <jv>headerAssertion</jv>.matchesSimple(<js>"application/json*"</js>);
+	RestResponseBody <jv>body</jv> = <jv>res</jv>.getBody();
+	MyBean <jv>bean</jv> = <jv>body</jv>.as(MyBean.<jk>class</jk>);
 </p>
 
 <p>
@@ -22619,17 +22619,18 @@
 	
 		<ja>@RemoteMethod</ja>(httpMethod=<jsf>POST</jsf>, path=<js>"/pets"</js>)
 		Pet addPet(
-			<ja>@Body</ja> CreatePet pet,
-			<ja>@Header</ja>(<js>"E-Tag"</js>) UUID etag,
-			<ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> debug
+			<ja>@Body</ja> CreatePet <jv>pet</jv>,
+			<ja>@Header</ja>(<js>"E-Tag"</js>) UUID <jv>etag</jv>,
+			<ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> <jv>debug</jv>
 		);
 	}
  
 	<jc>// Use a RestClient with default Simple JSON support.</jc>
-	RestClient client = RestClient.<jsm>create</jsm>().simpleJson().build();
-	PetStore store = client.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
-	CreatePet cp = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99);
-	Pet p = store.addPet(cp, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>);
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build();
+	
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
+	CreatePet <jv>createPet</jv> = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99);
+	Pet <jv>pet</jv> = <jv>store</jv>.addPet(<jv>createPet</jv>, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>);
 </p>
 
 <p>
@@ -22655,10 +22656,10 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a client where all URIs are relative to localhost.</jc>
-	RestClient client = RestClient.<jsm>create</jsm>().json().rootUri(<js>"http://localhost:10000"</js>).build();
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json().rootUri(<js>"http://localhost:10000"</js>).build();
 
 	<jc>// Use relative paths.</jc>
-	String body = client.get(<js>"/subpath"</js>).run().getBody().asString();
+	String <jv>body</jv> = <jv>client</jv>.get(<js>"/subpath"</js>).run().getBody().asString();
 </p>
 
 <p>
@@ -22706,10 +22707,10 @@
 
 <p class='bpcode w800'>
 	<jc>// Consuming the response, so use run().</jc>
-	String body = client.get(<jsf>URI</jsf>).run().getBody().asString();
+	String <jv>body</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).run().getBody().asString();
 
 	<jc>// Only interested in response status code, so use complete().</jc>
-	<jk>int</jk> status = client.get(<jsf>URI</jsf>).complete().getStatusCode();
+	<jk>int</jk> <jv>status</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).complete().getStatusCode();
 </p>
 
 <!-- ==================================================================================================== -->
@@ -22739,7 +22740,7 @@
 <p class='bpcode w800'>
 	<jc>// Create a basic REST client with Simplified-JSON support.</jc>
 	<jc>// Typically easier to use when performing unit tests.</jc>
-	RestClient c = RestClient.<jsm>create</jsm>().simpleJson().build();
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build();
 </p>
 
 <p>
@@ -22748,21 +22749,21 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a REST client with support for multiple languages.</jc>
-	RestClient c = RestClient.<jsm>create</jsm>().json().xml().openApi().build();
+	RestClient <jv>client1</jv> = RestClient.<jsm>create</jsm>().json().xml().openApi().build();
 
 	<jc>// Create a REST client with support for all supported languages.</jc>
-	RestClient c = RestClient.<jsm>create</jsm>().universal().build();
+	RestClient <jv>client2</jv> = RestClient.<jsm>create</jsm>().universal().build();
 </p>
 
 <p>
-	When using clients with multiple language support, you must specify the <c>Content-Type</c> header on requests
-	with bodies to specify which serializer should be selected.
+	When using clients with multiple language support, the request language is selected by setting the <c>Content-Type</c> 
+	request header.
 </p>
 <p class='bpcode w800'>
 	<jc>// Create a REST client with support for multiple languages.</jc>
-	RestClient c = RestClient.<jsm>create</jsm>().universal().build();
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().universal().build();
 
-	c.post(<jsf>URI</jsf>, myBean).contentType(<js>"application/json"</js>).complete().assertStatus().is(200);
+	<jv>client</jv>.post(<jsf>URI</jsf>, myBean).contentType(<js>"application/json"</js>).complete().assertStatus().is(200);
 </p>
 
 <p>
@@ -22770,10 +22771,10 @@
 </p>
 <p class='bpcode w800'>
 	<jc>// Create a REST client with no default languages supported.</jc>
-	RestClient c = RestClient.<jsm>create</jsm>().build();
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().build();
 
 	<jc>// Use JSON for this request.</jc>
-	c.post(<jsf>URI</jsf>, myBean).json().complete().assertStatus().is(200);
+	<jv>client</jv>.post(<jsf>URI</jsf>, myBean).json().complete().assertStatus().is(200);
 </p>
 
 <p>
@@ -22784,10 +22785,10 @@
 <p class='bpcode w800'>
 	<jc>// Create a basic REST client with JSON support.</jc>
 	<jc>// Use single-quotes and whitespace.</jc>
-	RestClient c = RestClient.<jsm>create</jsm>().json().sq().ws().build();
+	RestClient <jv>client1</jv> = RestClient.<jsm>create</jsm>().json().sq().ws().build();
 
 	<jc>// Same, but using properties.</jc>
-	RestClient c = RestClient
+	RestClient <jv>client2</jv> = RestClient
 		.<jsm>create</jsm>()
 		.json()
 		.set(<jsf>WSERIALIZER_quoteChar</jsf>, <js>'\''</js>)
@@ -22852,6 +22853,38 @@
 	</ul>
 </ul>
 
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a "Foo: bar" header to every request.</jc>
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().header(<js>"Foo"</js>, <js>"bar"</js>).build();
+
+	<jc>// Or do it on every request.</jc>
+	String <jv>response</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).header(<js>"Foo"</js>, <js>"bar"</js>).run().getBody().asString();
+</p>
+
+<p>
+	{@link org.apache.juneau.rest.client2.RestClientBuilder#headers(Object...) headers(Object...)} allows you to pass in a variety
+	of header objects, and {@link org.apache.juneau.rest.client2.RestClientBuilder#headerPairs(Object...) headerPairs(Object...)} allows
+	you to specify several headers in a compact fashion.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a bunch of headers to every request.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.headers(
+			AMap.<jsm>of</jsm>(<js>"Foo"</js>,<js>"bar"</js>,<js>"Baz"</js>,<js>"qux"</js>)  <jc>// Arbitrary key/value pairs.</jc>
+			BasicStringHeader.<jsm>of</jsm>(<js>"Foo"</js>,<js>"bar"</js>)  <jc>// A Header object.</jc>
+			BasicStringHeader.<jsm>of</jsm>(<js>"Foo"</js>,()->getBar())  <jc>// A dynamic Header object.</jc>
+			Accept.<jsm>of</jsm>(<js>"application/json"</js>)  <jc>// Predefined Header objects.</jc>
+			HeaderSupplier.<jsm>ofPairs</jsm>(<js>"Foo"</js>,<js>"bar"</js>)  <jc>// A dynamically changing list of Header objects.</jc>
+			AList.<jsm>of</jsm>(ContentType.<jsm>of</jsm>(<js>"application/json"</js>))  <jc>// A list of anything else on this list.</jc>
+		)
+		.headerPairs(<js>"Foo"</js>,<js>"bar"</js>,<js>"Baz"</js>,<js>"qux"</js>)
+		.build();
+</p>
+
 <p>
 	Additionally, methods are provided on the client builder and per request for all standard HTTP headers
 	such as {@link org.apache.juneau.rest.client2.RestClientBuilder#authorization(Object) authorization(Object)}.
@@ -22860,13 +22893,13 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a client that adds an Authorization header to every request.</jc>
-	RestClient client = RestClient.<jsm>create</jsm>().authorization(<js>"Foo"</js>).build();
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().authorization(<js>"Foo"</js>).build();
 
 	<jc>// Or do it per-request.</jc>
-	String response = client.get(<jsf>URI</jsf>).authorization(<js>"Foo"</js>).run().getBody().asString();
+	String <jv>response</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).authorization(<js>"Foo"</js>).run().getBody().asString();
 
 	<jc>// Or use an HttpHeader.</jc>
-	response = client.get(<jsf>URI</jsf>).headers(Authorization.<jsm>of</jsm>(<js>"Foo"</js>)).run().getBody().asString();
+	<jv>response</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).headers(Authorization.<jsm>of</jsm>(<js>"Foo"</js>)).run().getBody().asString();
 </p>
 
 <p>
@@ -22877,18 +22910,18 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a client that adds a dynamic Authorization header to every request.</jc>
-	RestClient c = RestClient.<jsm>create</jsm>().header(<js>"Authorization"</js>, ()-&gt;getMyAuthToken()).build();
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().header(<js>"Authorization"</js>, ()-&gt;getMyAuthToken()).build();
 </p>
 
 <p>
-	The {@link org.apache.juneau.httppart.HttpPartSchema} API allows you to define OpenAPI schemas to POJO data structures on both requests
-	and responses.
+	The {@link org.apache.juneau.httppart.HttpPartSchema} API allows you to define OpenAPI schemas to POJO data structures on request headers.
 </p>
 
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a client that adds a header "Foo: bar|baz" to every request.</jc>
-	RestClient c = RestClient.<jsm>create</jsm>()
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
 		.header(<js>"Foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), <jsf>T_ARRAY_PIPES</jsf>)
 		.build();
 </p>
@@ -22901,6 +22934,9 @@
 	<li>Methods that pass in POJOs convert values to strings using the part serializers.  Methods that pass in <c>Header</c> or
 		<c>NameValuePair</c> objects use the values returned by that bean directly.
 </ul>
+<ul class='seealso'>
+	<li class='jp'>{@link org.apache.juneau.http.header} - Predefined {@link org.apache.http.Header} beans.
+</ul>
 </div><!-- END: 9.2 - juneau-rest-client.RequestHeaders -->
 
 <!-- ==================================================================================================== -->
@@ -22934,14 +22970,53 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a client that adds a ?foo=bar query parameter to every request.</jc>
-	RestClient client = RestClient.<jsm>create</jsm>().query(<js>"foo"</js>, <js>"bar"</js>).build();
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().query(<js>"foo"</js>, <js>"bar"</js>).build();
 
 	<jc>// Or do it on every request.</jc>
-	String response = client.get(<jsf>URI</jsf>).query(<js>"foo"</js>, <js>"bar"</js>).run().getBody().asString();
+	String <jv>response</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).query(<js>"foo"</js>, <js>"bar"</js>).run().getBody().asString();
+</p>
+
+<p>
+	{@link org.apache.juneau.rest.client2.RestClientBuilder#queries(Object...) queries(Object...)} allows you to pass in a variety
+	of query parameter objects, and {@link org.apache.juneau.rest.client2.RestClientBuilder#queryPairs(Object...) queryPairs(Object...)} allows
+	you to specify several query parameters in a compact fashion.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a bunch of query parameters to every request.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.queries(
+			AMap.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>,<js>"qux"</js>)  <jc>// Arbitrary key/value pairs.</jc>
+			BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>)  <jc>// A NameValuePair object.</jc>
+			BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,()->getBar())  <jc>// A dynamic NameValuePair object.</jc>
+			NameValuePairSupplier.<jsm>ofPairs</jsm>(<js>"foo"</js>,<js>"bar"</js>)  <jc>// A dynamically changing list of NameValuePair objects.</jc>
+			AList.<jsm>of</jsm>(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>))  <jc>// A list of anything else on this list.</jc>
+		)
+		.queryPairs(<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>,<js>"qux"</js>)
+		.build();
+</p>
+
+<p>
+	The {@link org.apache.juneau.httppart.HttpPartSchema} API allows you to define OpenAPI schemas to POJO data structures on query parameters.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a query parameter "foo=bar|baz" to every request.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.query(<js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), <jsf>T_ARRAY_PIPES</jsf>)
+		.build();
+</p>
+
+<p>
+	The methods with {@link org.apache.juneau.AddFlag} parameters allow you to control whether new query parameters get appended, prepended, or
+	replace existing query parameters with the same name.
 </p>
 
 <ul class='notes'>
-	<li>Like header values, dynamic values and OpenAPI schemas are supported.
 	<li>Methods that pass in POJOs convert values to strings using the part serializers.  Methods that pass in <c>NameValuePair</c>
 		objects use the values returned by that bean directly.
 </ul>
@@ -22975,6 +23050,55 @@
 	</ul>
 </ul>
 
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a foo=bar form-data parameter to every request.</jc>
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().formData(<js>"foo"</js>, <js>"bar"</js>).build();
+
+	<jc>// Or do it on every request.</jc>
+	String <jv>response</jv> = <jv>client</jv>.formPost(<jsf>URI</jsf>).formData(<js>"foo"</js>, <js>"bar"</js>).run().getBody().asString();
+</p>
+
+<p>
+	{@link org.apache.juneau.rest.client2.RestClientBuilder#formDatas(Object...) formDatas(Object...)} allows you to pass in a variety
+	of form-data parameter objects, and {@link org.apache.juneau.rest.client2.RestClientBuilder#formDataPairs(Object...) formDataPairs(Object...)} allows
+	you to specify several form-data parameters in a compact fashion.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a bunch of form-data parameters to every request.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.formDatas(
+			AMap.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>,<js>"qux"</js>)  <jc>// Arbitrary key/value pairs.</jc>
+			BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>)  <jc>// A NameValuePair object.</jc>
+			BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,()->getBar())  <jc>// A dynamic NameValuePair object.</jc>
+			NameValuePairSupplier.<jsm>ofPairs</jsm>(<js>"foo"</js>,<js>"bar"</js>)  <jc>// A dynamically changing list of NameValuePair objects.</jc>
+			AList.<jsm>of</jsm>(BasicNameValuePair.<jsm>of</jsm>(<js>"foo"</js>,<js>"bar"</js>))  <jc>// A list of anything else on this list.</jc>
+		)
+		.formDataPairs(<js>"foo"</js>,<js>"bar"</js>,<js>"baz"</js>,<js>"qux"</js>)
+		.build();
+</p>
+
+<p>
+	The {@link org.apache.juneau.httppart.HttpPartSchema} API allows you to define OpenAPI schemas to POJO data structures on form-data parameters.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client that adds a form-data parameter "foo=bar|baz" to every request.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.formData(<js>"foo"</js>, AList.<jsm>of</jsm>(<js>"bar"</js>,<js>"baz"</js>), <jsf>T_ARRAY_PIPES</jsf>)
+		.build();
+</p>
+
+<p>
+	The methods with {@link org.apache.juneau.AddFlag} parameters allow you to control whether new form-data parameters get appended, prepended, or
+	replace existing form-data parameters with the same name.
+</p>
+
 <ul class='notes'>
 	<li>Like header values, dynamic values and OpenAPI schemas are supported.
 	<li>Methods that pass in POJOs convert values to strings using the part serializers.  Methods that pass in <c>NameValuePair</c>
@@ -23020,6 +23144,33 @@
 		{@link java.util.function.Supplier} - A supplier of anything on this list.
 </ul>
 
+<h5 class='figure'>Examples:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client with Simple-JSON support.</jc>
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build();
+	
+	<jc>// Post a JSON-serialized bean.</jc>
+	<jv>client</jv>
+		.post(<jsf>URI</jsf>)
+		.body(<jv>bean</jv>)
+		.complete()
+		.assertStatus().code().is(200);
+	
+	<jc>// Post contents from a reader.</jc>
+	<jv>client</jv>
+		.post(<jsf>URI</jsf>)
+		.body(<jk>new</jk> FileReader(<js>"/tmp/foo.json"</js>))
+		.complete()
+		.assertStatus().code().is(200);
+	
+	<jc>// Post contents from an Apache HttpEntity object.</jc>
+	<jv>client</jv>
+		.post(<jsf>URI</jsf>)
+		.body(<jk>new</jk> StringEntity(<jv>jsonString</jv>, ContentType.<jsf>APPLICATION_JSON</jsf>))
+		.complete()
+		.assertStatus().code().is(200);
+</p>
+
 <ul class='notes'>
 	<li>If the serializer on the client or request is explicitly set to <jk>null</jk>, POJOs will be converted to strings
 		using the registered part serializer as content type <js>"text/plain</js>.  If the part serializer is also <jk>null</jk>,
@@ -23048,7 +23199,7 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Only interested in status code.</jc>
-	<jk>int</jk> statusCode = client.get(<jsf>URI</jsf>).complete().getStatusCode();
+	<jk>int</jk> <jv>statusCode</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).complete().getStatusCode();
 </p>
 
 <p>
@@ -23058,11 +23209,11 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Interested in multiple values.</jc>
-	Mutable&lt;Integer&gt; statusCode = Mutable.<jsm>create</jsm>();
-	Mutable&lt;String&gt; reasonPhrase = Mutable.<jsm>create</jsm>();
+	Mutable&lt;Integer&gt; <jv>statusCode</jv> = Mutable.<jsm>create</jsm>();
+	Mutable&lt;String&gt; <jv>reasonPhrase</jv> = Mutable.<jsm>create</jsm>();
 	
-	client.get(<jsf>URI</jsf>).complete().getStatusCode(statusCode).getReasonPhrase(reasonPhrase);
-	System.<jsf>err</jsf>.println(<js>"statusCode="</js>+statusCode.get()+<js>", reasonPhrase="</js>+reasonPhrase.get());
+	<jv>client</jv>.get(<jsf>URI</jsf>).complete().getStatusCode(<jv>statusCode</jv>).getReasonPhrase(<jv>reasonPhrase</jv>);
+	System.<jsf>err</jsf>.println(<js>"statusCode="</js>+<jv>statusCode</jv>.get()+<js>", reasonPhrase="</js>+<jv>reasonPhrase</jv>.get());
 </p>
 
 <ul class='notes'>
@@ -23078,15 +23229,15 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Status assertion using a static value.</jc>
-	String body = client.get(<jsf>URI</jsf>)
+	String <jv>body1</jv> = <jv>client</jv>.get(<jsf>URI</jsf>)
 		.run()
 		.assertStatus().code().isBetween(200,399)
 		.getBody().asString();
 
 	<jc>// Status assertion using a predicate.</jc>
-	String body = client.get(<jsf>URI</jsf>)
+	String <jv>body2</jv> = <jv>client</jv>.get(<jsf>URI</jsf>)
 		.run()
-		.assertStatus().code().passes(x -&gt; x&lt;400)
+		.assertStatus().code().passes(<jv>x</jv> -&gt; <jv>x</jv>&lt;400)
 		.getBody().asString();
 </p>
 </div><!-- END: 9.6 - juneau-rest-client.ResponseStatus -->
@@ -23120,7 +23271,7 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// See if response contains Location header.</jc>
-	<jk>boolean</jk> hasLocationHeader = client.get(<jsf>URI</jsf>).complete().getHeader(<js>"Location"</js>).exists();
+	<jk>boolean</jk> <jv>hasLocationHeader</jv> = <jv>client</jv>.get(<jsf>URI</jsf>).complete().getHeader(<js>"Location"</js>).exists();
 </p>
 
 <p>
@@ -23161,7 +23312,7 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Parse the header "Foo: bar|baz".</jc>
-	List&lt;String&gt; fooHeader = client
+	List&lt;String&gt; <jv>fooHeader</jv> = <jv>client</jv>
 		.get(<jsf>URI</jsf>)
 		.complete()
 		.getHeader(<js>"Foo"</js>).schema(<jsf>T_ARRAY_PIPES</jsf>).as(List.<jk>class</jk>, String.<jk>class</jk>);
@@ -23189,7 +23340,7 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Assert the response content type is any sort of JSON.</jc>
-	String body = client.get(<jsf>URI</jsf>)
+	String <jv>body</jv> = <jv>client</jv>.get(<jsf>URI</jsf>)
 		.run()
 		.getHeader(<js>"Content-Type"</js>).assertString().matchesSimple(<js>"application/json*"</js>)
 		.getBody().asString();
@@ -23238,36 +23389,40 @@
 	</ul>
 </ul>
 
-<br>
-
 <h5 class='figure'>Examples:</h5>
 <p class='bpcode w800'>
+	<jc>// Parse into a bean.</jc>
+	MyBean <jv>bean</jv> = <jv>client</jv>
+		.get(<jsf>URI</jsf>)
+		.run()
+		.getBody().as(MyBean.<jk>class</jk>);
+
 	<jc>// Parse into a linked-list of strings.</jc>
-	List&lt;String&gt; l = client
+	List&lt;String&gt; <jv>l1</jv> = <jv>client</jv>
 		.get(<jsf>URI</jsf>)
 		.run()
 		.getBody().as(LinkedList.<jk>class</jk>, String.<jk>class</jk>);
 
 	<jc>// Parse into a linked-list of beans.</jc>
-	List&lt;MyBean&gt; l = client
+	List&lt;MyBean&gt; <jv>l2</jv> = <jv>client</jv>
 		.get(<jsf>URI</jsf>)
 		.run()
 		.getBody().as(LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
 
 	<jc>// Parse into a linked-list of linked-lists of strings.</jc>
-	List&lt;List&lt;String&gt;&gt; l = client
+	List&lt;List&lt;String&gt;&gt; <jv>l3</jv> = <jv>client</jv>
 		.get(<jsf>URI</jsf>)
 		.run()
 		.getBody().as(LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
 
 	<jc>// Parse into a map of string keys/values.</jc>
-	Map&lt;String,String&gt; m = client
+	Map&lt;String,String&gt; <jv>m4</jv> = <jv>client</jv>
 		.get(<jsf>URI</jsf>)
 		.run()
 		.getBody().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
 
 	<jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
-	Map&lt;String,List&lt;MyBean&gt;&gt; m = client
+	Map&lt;String,List&lt;MyBean&gt;&gt; <jv>m5</jv> = <jv>client</jv>
 		.get(<jsf>URI</jsf>)
 		.run()
 		.getBody().as(TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
@@ -23283,11 +23438,11 @@
 
 <p class='bpcode w800'>
 	<jc>// Cache the response body so we can access it twice.</jc>
-	InputStream inputStream = client
+	InputStream <jv>inputStream</jv> = <jv>client</jv>
 		.get(<jsf>URI</jsf>)
 		.run()
 		.cacheBody()
-		.getBody().pipeTo(someOtherStream)
+		.getBody().pipeTo(<jv>someOtherStream</jv>)
 		.getBody().asInputStream();
 </p>
 
@@ -23304,12 +23459,10 @@
 	</ul>
 </ul>
 
-<br>
-
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Assert that the body contains the string "Success".</jc>
-	String body = client
+	String <jv>body</jv> = <jv>client</jv>
 		.get(<jsf>URI</jsf>)
 		.run()
 		.getBody().assertString().contains(<js>"Success"</js>)
@@ -23324,7 +23477,7 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Parse bean into POJO and then validate that it was parsed correctly.</jc>
-	MyBean bean = client.get(<jsf>URI</jsf>)
+	MyBean <jv>bean</jv> = <jv>client</jv>.get(<jsf>URI</jsf>)
 		.run()
 		.getBody().assertObject(MyBean.<jk>class</jk>).json().is(<js>"{foo:'bar'}"</js>)
 		.getBody().as(MyBean.<jk>class</jk>);
@@ -23351,6 +23504,35 @@
 	</ul>
 </ul>
 
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Our custom call handler.</jc>
+	<jk>public class</jk> MyRestCallHandler <jk>implements</jk> RestCallHandler {
+
+		<jk>private final</jk> RestClient <jf>client</jf>;
+
+		<jk>public</jk> MyRestCallHandler(RestClient <jv>client</jv>) {
+			<jk>this</jk>.<jf>client</jf> = <jv>client</jv>;
+		}
+
+		<ja>@Override</ja>
+		<jk>public</jk> HttpResponse run(HttpHost <jv>target</jv>, HttpRequest <jv>request</jv>, HttpContext <jv>context</jv>) <jk>throws</jk> IOException {
+			<jc>// Insert any special handling here.</jc>
+			<jc>// The following is the default behavior:</jc>
+			<jk>if</jk> (<jv>target</jv> == <jk>null</jk>)
+				<jk>return</jk> <jf>client</jf>.execute((HttpUriRequest)<jv>request</jv>, <jv>context</jv>);
+			<jk>return</jk> <jf>client</jf>.execute(<jv>target</jv>, <jv>request</jv>, <jv>context</jv>);
+		}
+	}
+	
+	<jc>// Create a client that uses our custom handler.</jc>
+	RestClient <jv>client</jv> = RestClient()
+		.create()
+		.json()
+		.callHandler(MyCallHandler.<jk>class</jk>)
+		.build();
+</p>
+ 
 <p>
 	Note that there are other ways of accomplishing this such as extending the {@link org.apache.juneau.rest.client2.RestClient} class and overriding
 	the {@link org.apache.juneau.rest.client2.RestClient#run(HttpHost,HttpRequest,HttpContext)} method
@@ -23383,36 +23565,43 @@
 		<li class='jm'>{@link org.apache.juneau.rest.client2.RestCallInterceptor#onClose(RestRequest,RestResponse) onClose(RestRequest,RestResponse)}
 	</ul>
 </ul>
+
+<h5 class='section'>Example:</h5>
+<p class='bpcode w800'>
+	<jc>// Create a client with a customized interceptor.</jc>
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.interceptors(
+			<jk>new</jk> RestCallInterceptor() {
+
+				<ja>@Override</ja>
+				<jk>public void</jk> onInit(RestRequest <jv>req</jv>) <jk>throws</jk> Exception {
+					<jc>// Intercept immediately after RestRequest object is created and all headers/query/form-data has been
+					// set on the request from the client.</jc>
+				}
+
+				<ja>@Override</ja>
+				<jk>public void</jk> onConnect(RestRequest <jv>req</jv>, RestResponse <jv>res</jv>) <jk>throws</jk> Exception {
+					<jc>// Intercept immediately after an HTTP response has been received.</jc>
+				}
+
+				<ja>@Override</ja>
+				<jk>public void</jk> onClose(RestRequest <jv>req</jv>, RestResponse <jv>res</jv>) <jk>throws</jk> Exception {
+					<jc>// Intercept when the response body is consumed.</jc>
+				}
+			}
+		)
+		.build();
+</p>
 </div><!-- END: 9.10 - juneau-rest-client.Interceptors -->
 
 <!-- ==================================================================================================== -->
 
-<h3 class='topic' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies' id='juneau-rest-client.RestProxies'>9.11 - REST Proxies</a><span class='update'><b>8.1.4-new</b></span></h3>
+<h3 class='topic' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies' id='juneau-rest-client.RestProxies'>9.11 - REST Proxies</a><span class='update'><b>8.1.4-updated</b></span></h3>
 <div class='topic'><!-- START: 9.11 - juneau-rest-client.RestProxies -->
 <p>
 	One of the more powerful features of the REST client class is the ability to produce Java interface proxies against
-	arbitrary remote REST resources.
-</p>
-
-<h5 class='figure'>Example:</h5>
-<p class='bpcode w800'>
-	<jc>// Define a Remote proxy for interacting with a REST interface.</jc>
-	<ja>@Remote</ja>(path=<js>"/petstore"</js>)
-	<jk>public interface</jk> PetStore {
-		<ja>@RemoteMethod</ja>(httpMethod=<jsf>POST</jsf>, path=<js>"/pets"</js>)
-		Pet addPet(
-			<ja>@Body</ja> CreatePet pet,
-			<ja>@Header</ja>(<js>"E-Tag"</js>) UUID etag,
-			<ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> debug
-		);
-	}
-
-	<jc>// Use a RestClient with default Simple JSON support.</jc>
-	<jk>try</jk> (RestClient client = RestClient.<jsm>create</jsm>().simpleJson().build()) {
-		PetStore store = client.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
-		CreatePet cp = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99);
-		Pet p = store.addPet(cp, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>);
-	}
+	arbitrary 3rd party REST resources.
 </p>
 
 <p>
@@ -23425,47 +23614,10 @@
 		<li class='jm'><c>{@link org.apache.juneau.rest.client2.RestClient#getRemote(Class) getRemote(Class&lt;T&gt;)} <jk>returns</jk> T</c>
 		<li class='jm'><c>{@link org.apache.juneau.rest.client2.RestClient#getRemote(Class,Object) getRemote(Class&lt;T&gt;,Object)} <jk>returns</jk> T</c>
 		<li class='jm'><c>{@link org.apache.juneau.rest.client2.RestClient#getRemote(Class,Object,Serializer,Parser) getRemote(Class&lt;T&gt;,Object,Serializer,Parser)} <jk>returns</jk> T</c>
-		<li class='jm'><c>{@link org.apache.juneau.rest.client2.RestClient#getRrpcInterface(Class) getRrpcInterface(Class&lt;T&gt;)} <jk>returns</jk> T</c>
-		<li class='jm'><c>{@link org.apache.juneau.rest.client2.RestClient#getRrpcInterface(Class,Object) getRrpcInterface(Class&lt;T&gt;,Object)} <jk>returns</jk> T</c>
-		<li class='jm'><c>{@link org.apache.juneau.rest.client2.RestClient#getRrpcInterface(Class,Object,Serializer,Parser) getRrpcInterface(Class&lt;T&gt;,Object,Serializer,Parser)} <jk>returns</jk> T</c>
 	</ul>
 </ul>
 
 <p>
-	Two basic types of remote interfaces are provided:
-</p>
-
-<ul class='spaced-list'>
-	<li>{@link org.apache.juneau.http.remote.Remote @Remote}-annotated interfaces.  These can be defined against arbitrary external REST resources.
-	<li>RPC-over-REST interfaces.  These are Java interfaces that allow you to make method calls on server-side POJOs.
-</ul>
-
-
-
-
-
-
-
-
-
-
-<p>
-	The <c>juneau-rest-client</c> library can also be used to define interface proxies against 3rd-party REST interfaces.
-	This is an extremely powerful feature that allows you to quickly define easy-to-use interfaces against 
-	virtually any REST interface.
-</p>
-<p>
-	Remote resources are instantiated using one of the following methods:
-</p>
-<ul class='javatree'>
-	<li class='jc'>{@link org.apache.juneau.rest.client2.RestClient}
-	<ul>
-		<li class='jm'>{@link org.apache.juneau.rest.client2.RestClient#getRemote(Class) getRemote(Class)}
-		<li class='jm'>{@link org.apache.juneau.rest.client2.RestClient#getRemote(Class,Object) getRemote(Class,Object)}
-		<li class='jm'>{@link org.apache.juneau.rest.client2.RestClient#getRemote(Class,Object,Serializer,Parser) getRemote(Class,Object,Serializer,Parser)}
-	</ul>
-</ul>
-<p>
 	Annotations are used on the interface and interface methods to specify how to convert input and output to HTTP headers, query parameters, form 
 	post parameters, or request/response bodies.
 </p>
@@ -23493,24 +23645,30 @@
 	<jk>public interface</jk> PetStore {
 		
 		<ja>@RemoteMethod</ja>(method=<jsf>POST</jsf>, path=<js>"/pets"</js>)
-		String addPet(
-			<ja>@Body</ja> CreatePet pet, 
-			<ja>@Header</ja>(<js>"E-Tag"</js>) UUID etag, 
-			<ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> debug
+		Pet addPet(
+			<ja>@Body</ja> CreatePet <jv>createPet</jv>, 
+			<ja>@Header</ja>(<js>"E-Tag"</js>) UUID <jv>etag</jv>, 
+			<ja>@Query</ja>(<js>"debug"</js>) <jk>boolean</jk> <jv>debug</jv>
 		);
 	}
 </p>
+
 <p class='bpcode w800'>	
 	<jc>// Use a RestClient with default Simple JSON support.</jc>
-	<jk>try</jk> (RestClient client = RestClient.<jsm>create</jsm>().simpleJson().build()) {
-		PetStore store = client.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
-		CreatePet pet = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99);
-		String response = store.createPet(pet, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>);
-	}
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().simpleJson().build();
+	
+	<jc>// Instantiate our proxy interface.</jc>
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
+	
+	<jc>// Use it to create a pet.</jc>
+	CreatePet <jv>createPet</jv> = <jk>new</jk> CreatePet(<js>"Fluffy"</js>, 9.99);
+	Pet <jv>pet</jv> = <jv>store</jv>.addPet(<jv>createPet</jv>, UUID.<jsm>randomUUID</jsm>(), <jk>true</jk>);
 </p>
+
 <p>
 	The call above translates to the following REST call:
 </p>
+
 <p class='bpcode w800'>
 	POST http://localhost:10000/petstore/pets?debug=true HTTP/1.1
 	Accept: application/json
@@ -23540,18 +23698,24 @@
 
 <!-- ==================================================================================================== -->
 
-<h4 class='topic' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.Remote' id='juneau-rest-client.RestProxies.Remote'>9.11.1 - @Remote</a><span class='update'>8.1.2-updated</span></h4>
+<h4 class='topic' onclick='toggle(this)'><a href='#juneau-rest-client.RestProxies.Remote' id='juneau-rest-client.RestProxies.Remote'>9.11.1 - @Remote</a><span class='update'>8.1.2-updated,<b>8.1.4-updated</b></span></h4>
 <div class='topic'><!-- START: 9.11.1 - juneau-rest-client.RestProxies.Remote -->
 <p>
 	The {@link org.apache.juneau.http.remote.Remote @Remote} annotation is used on your interface class
 	to identify it as a REST proxy interface.
 </p>
+
 <ul class='javatree'>
 	<li class='ja'>{@link org.apache.juneau.http.remote.Remote}
 	<ul>
 		<li class='jf'>{@link org.apache.juneau.http.remote.Remote#path path}
+		<li class='jf'>{@link org.apache.juneau.http.remote.Remote#headers headers}
+		<li class='jf'>{@link org.apache.juneau.http.remote.Remote#headerSupplier headerSupplier}
+		<li class='jf'>{@link org.apache.juneau.http.remote.Remote#version version}
+		<li class='jf'>{@link org.apache.juneau.http.remote.Remote#versionHeader versionHeader}
 	</ul>
 </ul>
+
 <p>
 	The <ja>@Remote</ja> annotation is optional, but often included for code readability.
 </p>
@@ -23561,41 +23725,139 @@
 	The {@link org.apache.juneau.http.remote.Remote#path @Remote(path)} annotation is used to define the
 	HTTP path of the REST service.
 </p>
+
 <p>
 	The path can be an absolute path to your REST service.
 </p>
+
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>	
 	<ja>@Remote</ja>(path=<js>"http://localhost:10000/petstore"</js>)
 	<jk>public interface</jk> PetStore {...}
 </p>
 <p class='bpcode w800'>	
-	PetStore p = client.getRemote(PetStore.<jk>class</jk>);
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>);
 </p>
+
+<p>
+	{@doc DefaultSvlVariables} can also be used in the path.
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>	
+	<jc>// URL is specified via a system property.</jc>
+	<ja>@Remote</ja>(path=<js>"$P{PetStoreUrl}"</js>)
+	<jk>public interface</jk> PetStore {...}
+</p>
+
 <p>
 	When a relative path is specified, it's relative to the root-url defined on the <c>RestClient</c> used to instantiate the interface.
 </p>
+
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>	
 	<ja>@Remote</ja>(path=<js>"/petstore"</js>)
 	<jk>public interface</jk> PetStore {...}
 </p>
 <p class='bpcode w800'>
-	RestClient client = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000"</js>).build();	
-	PetStore p = client.getRemote(PetStore.<jk>class</jk>);
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.json()
+		.rootUrl(<js>"http://localhost:10000"</js>)
+		.build();
+			
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>);
 </p>
+
 <p>
 	When no path is specified, the root-url defined on the <c>RestClient</c> is used.
 </p>
+
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>	
 	<ja>@Remote</ja>
 	<jk>public interface</jk> PetStore {...}
 </p>
 <p class='bpcode w800'>
-	RestClient client = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000/petstore"</js>).build();	
-	PetStore p = client.getRemote(PetStore.<jk>class</jk>);
+	RestClient <jv>client</jv> = RestClient
+		.<jsm>create</jsm>()
+		.json()
+		.rootUrl(<js>"http://localhost:10000/petstore"</js>)
+		.build();
+			
+	PetStore <jv>store</jv> = <jv>client<jv>.getRemote(PetStore.<jk>class</jk>);
+</p>
+
+
+<h5 class='topic'>@Remote(headers/headerSupplier)</h5>
+<p>
+	The {@link org.apache.juneau.http.remote.Remote#headers @Remote(headers)} and {@link org.apache.juneau.http.remote.Remote#headerSupplier @Remote(headerSupplier)} 
+	annotations are used to add headers on all requests.  
+</p>
+
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>	
+	<ja>@Remote</ja>(
+		path=<js>"/petstore"</js>,
+		headers={
+			<js>"Foo: bar"</js>,
+			<js>"Baz: $P{bazProperty}"</js>
+		},
+		headerSupplier=MyDynamicHeaderSupplier.<jk>class</jk>
+	)
+	<jk>public interface</jk> PetStore {...}
+</p>
+<p class='bpcode w800'>
+	<jc>// Our dynamic supplier.</jc>
+	<jk>public class</jk> MyHeaderSupplier <jk>extends</jk> HeaderSupplier {
+	
+		<jc>// Headers can be added here at runtime.</jc>
+		<jk>public static</jk> HeaderSupplier <jsf>DYNAMIC_HEADERS</jsf> = <jk>new</jk> HeaderSupplier();
+	
+		<jk>public</jk> MyHeaderSupplier() {
+			add(<js>"Qux"</js>,<js>"q2x"</js>);  
+			add(<jsf>DYNAMIC_HEADERS</jsf>);
+		}
+	}
+</p>
+
+
+<h5 class='topic'>@Remote(version/versionHeader)</h5>
+<p>
+	The {@link org.apache.juneau.http.remote.Remote#version @Remote(version)} and {@link org.apache.juneau.http.remote.Remote#versionHeader @Remote(versionHeader)} 
+	annotations are used to specify the client-side version of this interface that can be used on the server side
+	to perform version-specific handling.
+</p>
+<h5 class='figure'>Example:</h5>
+<p class='bpcode w800'>	
+	<ja>@Remote</ja>(
+		path=<js>"/petstore"</js>,
+		version=<js>"1.2.3"</js>  <jc>// Adds "X-Client-Version: 1.2.3" header to all requests.</jc>
+	)
+	<jk>public interface</jk> PetStore {...}
 </p>
+
+<p>
+	This can be used in conjunction with the server-side client-versioning support.
+</p>
+<p class='bpcode w800'>
+	<jc>// Call this method if X-Client-Version is at least 2.0.
+	// Note that this also matches 2.0.1.</jc>
+	<ja>@RestMethod</ja>(clientVersion=<js>"2.0"</js>)
+	<jk>public</jk> Object getFoo()  {...}
+
+	<jc>// Call this method if X-Client-Version is at least 1.1, but less than 2.0.</jc>
+	<ja>@RestMethod</ja>(clientVersion=<js>"[1.1,2.0)"</js>)
+	<jk>public</jk> Object getFoo()  {...}
+
+	<jc>// Call this method if X-Client-Version is less than 1.1.</jc>
+	<ja>@RestMethod</ja>(clientVersion=<js>"[0,1.1)"</js>)
+	<jk>public</jk> Object getFoo()  {...}
+</p>
+
+<ul class='seealso'>
+	<li class='doclink'>{@doc juneau-rest-server.ClientVersioning}
+</ul>
 </div><!-- END: 9.11.1 - juneau-rest-client.RestProxies.Remote -->
 
 <!-- ==================================================================================================== -->
@@ -23625,7 +23887,7 @@
 		
 		<jc>// GET /pets/{petId}</jc>
 		<ja>@RemoteMethod</ja>(method=<js>"GET"</js>, path=<js>"/pets/{petId}"</js>)
-		Pet getPet(<ja>@Path</ja>(<js>"petId"</js>) <jk>int</jk> id);
+		Pet getPet(<ja>@Path</ja>(<js>"petId"</js>) <jk>int</jk> <jv>id</jv>);
 	}
 </p>
 <p>
@@ -23767,7 +24029,7 @@
 	<li class='ja'>{@link org.apache.juneau.http.annotation.Body}
 	<ul>
 		<li class='jf'>{@link org.apache.juneau.http.annotation.Body#required() required} - Input validation.  Body must be present.
-		<li class='jf'>{@link org.apache.juneau.http.annotation.Body#schema() schema} - Swagger schema.
+		<li class='jf'>{@link org.apache.juneau.http.annotation.Body#schema() schema} - OpenAPI schema.
 	</ul>
 </ul>
 
@@ -23778,7 +24040,7 @@
 	<jk>public interface</jk> PetStore {
 
 		<ja>@RemoteMethod</ja>(path=<js>"/pets"</js>)
-		String addPet(<ja>@Body</ja> Pet pet);
+		String addPet(<ja>@Body</ja> Pet <jv>pet</jv>;
 	}
 </p>
 <p class='bpcode w800'>
@@ -23787,7 +24049,7 @@
 	<jk>public interface</jk> PetStore {
 
 		<ja>@RemoteMethod</ja>(path=<js>"/pets"</js>)
-		String addPet(Pet pet);
+		String addPet(Pet <jv>pet</jv>);
 	}
 
 	<ja>@Body</ja>
@@ -23837,7 +24099,20 @@
 				)
 			)
 		)
-		<jk>int</jk>[][] input
+		<jk>int</jk>[][] <jv>input</jv>
+	);
+</p>
+<p class='bpcode w800'>
+	<jc>// Same as above but using free-form schema.</jc>
+	<ja>@RemoteMethod</ja>(path=<js>"/comma-delimited-pipe-delimited-ints"</js>)
+	String addCommaDelimitedPipeDelimitedInts(
+		<ja>@Body</ja>(
+			serializer=OpenApiSerializer.<jk>class</jk>,
+			schema=<ja>@Schema</ja>(
+				<js>"type:'array,collectionFormat:'pipes',items:[type:'array',items:[type:'int32',minimum:0,maximum:64]]"</js>
+			)
+		)
+		<jk>int</jk>[][] <jv>input</jv>
 	);
 </p>
 <p>
@@ -23894,30 +24169,30 @@
 		<jc>// Explicit names specified for form data parameters.</jc>
 		<ja>@RemoteMethod</ja>
 		String postParameters(
-			<ja>@FormData</ja>(<js>"foo"</js>)</ja> String foo,
-			<ja>@FormData</ja>(<js>"bar"</js>)</ja> MyPojo pojo
+			<ja>@FormData</ja>(<js>"foo"</js>)</ja> String <jv>foo</jv>,
+			<ja>@FormData</ja>(<js>"bar"</js>)</ja> MyPojo <jv>pojo</jv>
 		);
 
 		<jc>// Multiple values pulled from a NameValuePairs object.</jc>
 		<jc>// Name "*" is inferred.</jc>
 		<ja>@RemoteMethod</ja>
-		String postNameValuePairs(<ja>@FormData</ja> NameValuePairs nameValuePairs);
+		String postNameValuePairs(<ja>@FormData</ja> NameValuePairs <jv>nameValuePairs</jv>);
 
 		<jc>// Multiple values pulled from a Map.</jc>
 		<ja>@RemoteMethod</ja>
-		String postMap(<ja>@FormData</ja> Map&lt;String,Object&gt; map);
+		String postMap(<ja>@FormData</ja> Map&lt;String,Object&gt; <jv>map</jv>);
 
 		<jc>// Multiple values pulled from a bean.</jc>
 		<ja>@RemoteMethod</ja>
-		String postBean(<ja>@FormData</ja> MyBean bean);
+		String postBean(<ja>@FormData</ja> MyBean <jv>bean</jv>);
 
 		<jc>// An entire form-data HTTP body as a String.</jc>
 		<ja>@RemoteMethod</ja>
-		String postString(<ja>@FormData</ja> String string);
+		String postString(<ja>@FormData</ja> String <jv>string</jv>);
 
 		<jc>// An entire form-data HTTP body as a Reader.</jc>
 		<ja>@RemoteMethod</ja>
-		String postReader(<ja>@FormData</ja> Reader reader);
+		String postReader(<ja>@FormData</ja> Reader <jv>reader</jv>);
 	}
 </p>
 
@@ -24001,33 +24276,33 @@
 		<jc>// Explicit names specified for query parameters.</jc>
 		<ja>@RemoteMethod</ja>
 		String parameters(
-			<ja>@Query</ja>(<js>"foo"</js>)</ja> String foo,
-			<ja>@Query</ja>(<js>"bar"</js>)</ja> MyPojo pojo);
+			<ja>@Query</ja>(<js>"foo"</js>)</ja> String <jv>foo</jv>,
+			<ja>@Query</ja>(<js>"bar"</js>)</ja> MyPojo <jv>pojo</jv>);
  
 		<jc>// Multiple values pulled from a NameValuePairs object.</jc>
 		<jc>// Same as @Query("*").</jc>
 		<ja>@RemoteMethod</ja>
-		String nameValuePairs(<ja>@Query</ja> NameValuePairs nameValuePairs);
+		String nameValuePairs(<ja>@Query</ja> NameValuePairs <jv>nameValuePairs</jv>);
  
 		<jc>// Multiple values pulled from a Map.</jc>
 		<jc>// Same as @Query("*").</jc>
 		<ja>@RemoteMethod</ja>
-		String map(<ja>@Query</ja> Map&lt;String,Object&gt; map);
+		String map(<ja>@Query</ja> Map&lt;String,Object&gt; <jv>map</jv>);
 
 		<jc>// Multiple values pulled from a bean.</jc>
 		<jc>// Same as @Query("*").</jc>
 		<ja>@RemoteMethod</ja>
-		String bean(<ja>@Query</ja> MyBean myBean);
+		String bean(<ja>@Query</ja> MyBean <jv>myBean</jv>);
 
 		<jc>// An entire query string as a String.</jc>
 		<jc>// Same as @Query("*").</jc>
 		<ja>@RemoteMethod</ja>
-		String string(<ja>@Query</ja> String string);
+		String string(<ja>@Query</ja> String <jv>string</jv>);
 
 		<jc>// An entire query string as a Reader.</jc>
 		<jc>// Same as @Query("*").</jc>
 		<ja>@RemoteMethod</ja>
-		String reader(<ja>@Query</ja> Reader reader);
+		String reader(<ja>@Query</ja> Reader <jv>reader</jv>);
 	}
 </p>
 
@@ -24111,23 +24386,23 @@
 		<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);
+		String myProxyMethod1(<ja>@Header</ja>(<js>"Foo"</js>)</ja> String <jv>foo</jv>,
+			<ja>@Header</ja>(<js>"Bar"</js>)</ja> MyPojo <jv>pojo</jv>);
 
 		<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> NameValuePairs nameValuePairs);
+		String myProxyMethod2(<ja>@Header</ja> NameValuePairs <jv>nameValuePairs</jv>);
 
 		<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);
+		String myProxyMethod3(<ja>@Header</ja> Map&lt;String,Object&gt; <jv>map</jv>);
 
 		<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);
+		String myProxyMethod4(<ja>@Header</ja> MyBean <jv>myBean</jv>);
 	}
 </p>
 
@@ -24201,22 +24476,22 @@
 		<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);
+		String myProxyMethod1(<ja>@Path</ja>(<js>"foo"</js>)</ja> String <jv>foo</jv>, <ja>@Path</ja>(<js>"bar"</js>)</ja> MyPojo <jv>pojo</jv>);
 
 		<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);
+		String myProxyMethod2(<ja>@Path</ja> NameValuePairs <jv>nameValuePairs</jv>);
 
 		<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);
+		String myProxyMethod3(<ja>@Path</ja> Map&lt;String,Object&gt; <jv>map</jv>);
 
 		<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);
+		String myProxyMethod4(<ja>@Path</ja> MyBean <jv>myBean</jv>);
 	}
 </p>
 
@@ -24275,7 +24550,7 @@
 	<jk>public interface</jk> PetStore {
 
 		<ja>@RemoteMethod</ja>
-		String postPet(CreatePetRequest bean);
+		String postPet(CreatePetRequest <jv>bean</jv>);
 	}
 </p>
 <p class='bpcode w800'>
@@ -24284,8 +24559,8 @@
 	
 		<jk>private</jk> CreatePet <jf>pet</jf>;
 	
-		<jk>public</jk> CreatePetRequest(String name, <jk>float</jk> price) {
-			<jk>this</jk>.<jf>pet</jf> = <jk>new</jk> CreatePet(name, price);
+		<jk>public</jk> CreatePetRequest(String <jv>name</jv>, <jk>float</jk> <jv>price</jv>) {
+			<jk>this</jk>.<jf>pet</jf> = <jk>new</jk> CreatePet(<jv>name</jv>, <jv>price</jv>);
 		}
 		
 		<ja>@Body</ja>
@@ -24295,7 +24570,7 @@
 	
 		<ja>@Query</ja>
 	 	<jk>public</jk> Map&lt;String,Object&gt; getQueryParams() {
-	 		<jk>return</jk> OMap.<jsm>of</jsm>(<js>"debug"</js>, <jk>true</jk>);
+	 		<jk>return</jk> AMap.<jsm>of</jsm>(<js>"debug"</js>, <jk>true</jk>);
 	 	}
 	 	
 	 	<ja>@Header</ja>(<js>"E-Tag"</js>)
@@ -24305,9 +24580,10 @@
 	}
 </p>
 <p class='bpcode w800'>
-	PetStore store = restClient.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
-	CreatePetRequest requestBean = <jk>new</jk> CreatePetRequest(<js>"Fluffy"</js>, 9.99);
-	String response = store.postPet(requestBean);
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
+	
+	CreatePetRequest <jv>requestBean</jv> = <jk>new</jk> CreatePetRequest(<js>"Fluffy"</js>, 9.99);
+	String <jv>response</jv> = <jv>store</jv>.postPet(requestBean);
 </p>
 <p>
 	The <ja>@Request</ja> annotation can be applied to either the class or argument.
@@ -24351,7 +24627,7 @@
 <p class='bpcode w800'>
 	<jk>public class</jk> CreatePetRequestImpl <jk>implements</jk> CreatePetRequest {
 	
-		<jk>public</jk> CreatePetRequestImpl(String name, <jk>float</jk> price) {...}
+		<jk>public</jk> CreatePetRequestImpl(String <jv>name</jv>, <jk>float</jk> <jv>price</jv>) {...}
 
 		<ja>@Override</ja>
 		<jk>public</jk> CreatePet getBody() {
@@ -24407,15 +24683,16 @@
 		UUID getUUID();
 		
 		<ja>@ResponseStatus</ja>
-		int getStatus();
+		<jk>int</jk> getStatus();
 	}
 </p>
 <p class='bpcode w800'>
-	PetStore store = restClient.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
-	CreatePetResponse response = store.postPet(...);
-	Pet pet = response.getBody();
-	UUID uuid = response.getUUID();
-	<jk>int</jk> status = response.getStatus();
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>, <js>"http://localhost:10000"</js>);
+	
+	CreatePetResponse <jv>response</jv> = <jv>store</jv>.postPet(...);
+	Pet <jv>pet</jv> = <jv>response</jv>.getBody();
+	UUID <jv>uuid</jv> = <jv>response</jv>.getUUID();
+	<jk>int</jk> <jv>status</jv> = <jv>response</jv>.getStatus();
 </p>
 <p>
 	The annotated methods must be no-arg.  
@@ -24468,13 +24745,13 @@
 				required=<jk>true</jk>,
 				example=<js>"foobar"</js>
 			)
-			String apiKey,
+			String <jv>apiKey</jv>,
 			<ja>@Path</ja>(
 				name=<js>"petId"</js>,
 				description=<js>"Pet id to delete"</js>,
 				example=<js>"123"</js>
 			)
-			<jk>long</jk> petId
+			<jk>long</jk> <jv>petId</jv>
 		) <jk>throws</jk> IdNotFound, NotAcceptable;
 		
 		...
@@ -24510,8 +24787,8 @@
 			summary=<js>"Deletes a pet"</js>,
 			...
 		)
-		<jk>public</jk> Ok deletePet(String apiKey, long petId) <jk>throws</jk> IdNotFound, NotAcceptable {
-			<jsf>store</jsf>.removePet(petId);
+		<jk>public</jk> Ok deletePet(String <jv>apiKey</jv>, <jk>long</jk> <jv>petId</jv>) <jk>throws</jk> IdNotFound, NotAcceptable {
+			<jsf>store</jsf>.removePet(<jv>petId</jv>);
 			<jk>return</jk> <jsf>OK</jsf>;
 		}
 </p>
@@ -24519,13 +24796,12 @@
 	Then use the interface as a remote resource like so:
 </p>
 <p class='bpcode w800'>
-	<jk>try</jk> (RestClient rc = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000"</js>).build()) {
-		PetStore ps = rc.getRemote(PetStore.<jk>class</jk>);
+	RestClient client = RestClient.<jsm>create</jsm>().json().rootUrl(<js>"http://localhost:10000"</js>).build();
+	PetStore <jv>store</jv> = <jv>client</jv>.getRemote(PetStore.<jk>class</jk>);
 
-		<jk>for</jk> (Pet x : ps.getPets()) {
-			ps.deletePet(<js>"my-special-key"</js>, x.getId());
-			System.<jsf>err</jsf>.println(<js>"Deleted pet:  id="</js> + x.getId());
-		}
+	<jk>for</jk> (Pet <jv>x</jv> : <jv>store</jv>.getPets()) {
+		<jv>store</jv>.deletePet(<js>"my-special-key"</js>, <jv>x</jv>.getId());
+		System.<jsf>err</jsf>.println(<js>"Deleted pet:  id="</js> + <jv>x</jv>.getId());
 	}
 </p>	
 <p>
@@ -24562,13 +24838,16 @@
 
 <h5 class='figure'>Examples:</h5>
 <p class='bpcode w800'>
-	MyBean bean = RestClient
+	<jc>// A simple bean we're going to round-trip.</jc>
+	MyBean <jv>bean</jv> = <jk>new</jk> MyBean();
+	
+	<jv>bean</jv> = RestClient
 		.<jsm>create</jsm>()
 		.simpleJson()
-		.logRequests(DetailLevel.<jsf>FULL</jsf>, Level.<jsf>SEVERE</jsf>, (req,res)-&gt;req.getUri().endsWith(<js>"/bean"</js>))
+		.logRequests(DetailLevel.<jsf>FULL</jsf>, Level.<jsf>SEVERE</jsf>, (<jv>req</jv>,<jv>res</jv>)-&gt;<jv>req</jv>.getUri().endsWith(<js>"/bean"</js>))
 		.logToConsole()
 		.build()
-		.post(<js>"http://localhost/bean"</js>, bean)
+		.post(<js>"http://localhost/bean"</js>, <jv>bean</jv>)
 		.run()
 		.getBody().as(MyBean.<jk>class</jk>);
 </p>
@@ -24648,16 +24927,16 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a client with customized HttpClient settings.</jc>
-	MyBean bean = RestClient
+	MyBean <jv>bean</jv> = RestClient
 		.<jsm>create</jsm>()
 		.disableRedirectHandling()
-		.connectionManager(myConnectionManager)
-		.addInterceptorFirst(myHttpRequestInterceptor)
+		.connectionManager(<jv>myConnectionManager</jv>)
+		.addInterceptorFirst(<jv>myHttpRequestInterceptor</jv>)
 		.build();
 </p>
 
 <p>
-	Refer to the {@link org.apache.http.client.impl.HttpClientBuilder HTTP Client Builder API} for more information.
+	Refer to the {@link org.apache.http.client.impl.HttpClientBuilder HttpClientBuilder} docs for more information.
 </p>
 </div><!-- END: 9.13 - juneau-rest-client.CustomizingHttpClient -->
 
@@ -24675,18 +24954,18 @@
 	<jk>public class</jk> MyRestClient <jk>extends</jk> RestClient {
 
 		<jc>// Must provide this constructor!</jc>
-		<jk>public</jk> MyRestClient(PropertyStore ps) {
-			<jk>super</jk>(ps);
+		<jk>public</jk> MyRestClient(PropertyStore <jv>ps</jv>) {
+			<jk>super</jk>(<jv>ps</jv>);
 		}
 
 		<ja>@Override</ja>
-		<jk>public</jk> HttpResponse run(HttpHost target, HttpRequest request, HttpContext context) <jk>throws</jk> IOException {
+		<jk>public</jk> HttpResponse run(HttpHost <jv>target</jv>, HttpRequest <jv>request</jv>, HttpContext <jv>context</jv>) <jk>throws</jk> IOException {
 			<jc>// Perform special handling of requests.</jc>
 		}
 	}
 
 	<jc>// Instantiate your client.</jc>
-	MyRestClient client = RestClient.<jsm>create</jsm>().json().build(MyRestClient.<jk>class</jk>);
+	MyRestClient <jv>client</jv> = RestClient.<jsm>create</jsm>().json().build(MyRestClient.<jk>class</jk>);
 </p>
 
 <p>
@@ -24719,7 +24998,7 @@
 <h5 class='figure'>Example:</h5>
 <p class='bpcode w800'>
 	<jc>// Create a client that performs BASIC authentication using the specified user/pw.</jc>
-	RestClient restClient = RestClient.<jsm>create</jsm>() 
+	RestClient <jv>client</jv> = RestClient.<jsm>create</jsm>() 
 		.basicAuth(<jsf>HOST</jsf>, <jsf>PORT</jsf>, <jsf>USER</jsf>, <jsf>PW</jsf>)
 		.build();
 </p>
@@ -24727,12 +25006,12 @@
 	This is functionally equivalent to the following:
 </p>
 <p class='bpcode w800'>
-	RestClientBuilder builder = RestClient.<jsm>create</jsm>();
-	AuthScope scope = <jk>new</jk> AuthScope(<jsf>HOST</jsf>, <jsf>PORT</jsf>);
-	Credentials up = <jk>new</jk> UsernamePasswordCredentials(<jsf>USER</jsf>, <jsf>PW</jsf>);
-	CredentialsProvider p = <jk>new</jk> BasicCredentialsProvider();
-	p.setCredentials(scope, up);
-	builder.setDefaultCredentialsProvider(p);
+	RestClientBuilder <jv>builder</jv> = RestClient.<jsm>create</jsm>();
+	AuthScope <jv>scope</jv> = <jk>new</jk> AuthScope(<jsf>HOST</jsf>, <jsf>PORT</jsf>);
+	Credentials <jv>up</jv> = <jk>new</jk> UsernamePasswordCredentials(<jsf>USER</jsf>, <jsf>PW</jsf>);
+	CredentialsProvider <jv>p</jv> = <jk>new</jk> BasicCredentialsProvider();
+	<jv>p</jv>.setCredentials(<jv>scope</jv>, <jv>up</jv>);
+	<jv>builder</jv>.setDefaultCredentialsProvider(<jv>p</jv>);
 </p>
 </div><!-- END: 9.15.1 - juneau-rest-client.Authentication.BASIC -->
 
@@ -24749,14 +25028,14 @@
 	authenticated client.
 </p>
 <p>
-	The following example shows how the <c>JazzRestClient</c> class provides FORM-based 
-	authentication support.
+	The following example shows an implementation of a client that performs FORM-based authentication against
+	the IBM Jazz platform.
 </p>
 <p class='bpcode w800'>
 	<jd>/**
 	 * Constructor.
 	 */</jd>
-	<jk>public</jk> JazzRestClientBuilder(URI jazzUri, String user, String pw) <jk>throws</jk> IOException {
+	<jk>public</jk> JazzRestClientBuilder(URI <jv>jazzUri</jv>, String <jv>user</jv>, String <jv>pw</jv>) <jk>throws</jk> IOException {
 		...
 	}
 
@@ -24765,46 +25044,47 @@
 	 */</jd>
 	<ja>@Override</ja> <jc>/* RestClientBuilder */</jc>
 	<jk>protected</jk> CloseableHttpClient createHttpClient() <jk>throws</jk> Exception {
-		CloseableHttpClient client = <jk>super</jk>.createHttpClient();
-		formBasedAuthenticate(client);
-		visitAuthenticatedURL(client);
-		<jk>return</jk> client;
+		CloseableHttpClient <jv>client</jv> = <jk>super</jk>.createHttpClient();
+		formBasedAuthenticate(<jv>client</jv>);
+		visitAuthenticatedURL(<jv>client</jv>);
+		<jk>return</jk> <jv>client</jv>;
 	}
 
 	<jc>/*
 	 * Performs form-based authentication against the Jazz server.
 	 */</jc>
-	<jk>private void</jk> formBasedAuthenticate(HttpClient client) <jk>throws</jk> IOException {
+	<jk>private void</jk> formBasedAuthenticate(HttpClient <jv>client</jv>) <jk>throws</jk> IOException {
 
-		URI uri2 = <jf>jazzUri</jf>.resolve(<js>"j_security_check"</js>);
-		HttpPost request = <jk>new</jk> HttpPost(uri2);
-		request.setConfig(RequestConfig.<jsm>custom</jsm>().setRedirectsEnabled(<jk>false</jk>).build());
+		URI <jv>uri2</jv> = <jf>jazzUri</jf>.resolve(<js>"j_security_check"</js>);
+		HttpPost <jv>request</jv> = <jk>new</jk> HttpPost(uri2);
+		<jv>request</jv>.setConfig(RequestConfig.<jsm>custom</jsm>().setRedirectsEnabled(<jk>false</jk>).build());
 		
 		<jc>// Charset must explicitly be set to UTF-8 to handle user/pw with non-ascii characters.</jc>
-		request.addHeader(<js>"Content-Type"</js>, <js>"application/x-www-form-urlencoded; charset=utf-8"</js>);
+		<jv>request</jv>.addHeader(<js>"Content-Type"</js>, <js>"application/x-www-form-urlencoded; charset=utf-8"</js>);
 
-		NameValuePairs params = <jk>new</jk> NameValuePairs()
-			.append(<jk>new</jk> BasicNameValuePair(<js>"j_username""</js>, <jf>user</jf>))
-			.append(<jk>new</jk> BasicNameValuePair(<js>"j_password"</js>, <jf>pw</jf>));
-		request.setEntity(<jk>new</jk> UrlEncodedFormEntity(params));
+		List&lt;NameValuePair&gt; <jv>params</jv> = AList.<jsm>of</jsm>(
+			BasicNameValuePair.<jsm>of</jsm>(<js>"j_username""</js>, <jf>user</jf>),
+			BasicNameValuePair.<jsm>of</jsm>(<js>"j_password"</js>, <jf>pw</jf>)
+		);
+		<jv>request</jv>.setEntity(<jk>new</jk> UrlEncodedFormEntity(<jv>params</jv>));
 
-		HttpResponse response = client.execute(request);
+		HttpResponse <jv>response</jv> = <jv>client</jv>.execute(<jv>request</jv>);
 		<jk>try</jk> {
-			<jk>int</jk> rc = response.getStatusLine().getStatusCode();
+			<jk>int</jk> <jv>rc</jv> = <jv>response</jv>.getStatusLine().getStatusCode();
 
-			Header authMsg = response.getFirstHeader(<js>"X-com-ibm-team-repository-web-auth-msg"</js>);
-			<jk>if</jk> (authMsg != <jk>null</jk>)
-				<jk>throw new</jk> IOException(authMsg.getValue());
+			Header <jv>authMsg</jv> = <jv>response</jv>.getFirstHeader(<js>"X-com-ibm-team-repository-web-auth-msg"</js>);
+			<jk>if</jk> (<jv>authMsg</jv> != <jk>null</jk>)
+				<jk>throw new</jk> IOException(<jv>authMsg</jv>.getValue());
 
 			<jc>// The form auth request should always respond with a 200 ok or 302 redirect code</jc>
-			<jk>if</jk> (rc == <jsf>SC_MOVED_TEMPORARILY</jsf>) {
-				<jk>if</jk> (response.getFirstHeader(<js>"Location"</js>).getValue().matches(<js>"^.*/auth/authfailed.*$"</js>))
+			<jk>if</jk> (<jv>rc</jv> == <jsf>SC_MOVED_TEMPORARILY</jsf>) {
+				<jk>if</jk> (<jv>response</jv>.getFirstHeader(<js>"Location"</js>).getValue().matches(<js>"^.*/auth/authfailed.*$"</js>))
 					<jk>throw new</jk> IOException(<js>"Invalid credentials."</js>);
-			} <jk>else if</jk> (rc != <jsf>SC_OK</jsf>) {
-				<jk>throw new</jk> IOException(<js>"Unexpected HTTP status: "</js> + rc);
+			} <jk>else if</jk> (<jv>rc</jv> != <jsf>SC_OK</jsf>) {
+				<jk>throw new</jk> IOException(<js>"Unexpected HTTP status: "</js> + <jv>rc</jv>);
 			}
 		} <jk>finally</jk> {
-			EntityUtils.<jsm>consume</jsm>(response.getEntity());
+			EntityUtils.<jsm>consume</jsm>(<jv>response</jv>.getEntity());
 		}
 	}
 
@@ -24813,13 +25093,13 @@
 	 * authenticated URL has been visited. This same URL must also be visited after authenticating with j_security_check
 	 * otherwise tomcat will not consider the session authenticated
 	 */</jc>
-	<jk>private int</jk> visitAuthenticatedURL(HttpClient httpClient) <jk>throws</jk> IOException {
-		HttpGet authenticatedURL = <jk>new</jk> HttpGet(<jf>jazzUri</jf>.resolve(<js>"authenticated/identity"</js>));
-		HttpResponse response = httpClient.execute(authenticatedURL);
+	<jk>private int</jk> visitAuthenticatedURL(HttpClient <jv>httpClient</jv>) <jk>throws</jk> IOException {
+		HttpGet <jv>authenticatedURL</jv> = <jk>new</jk> HttpGet(<jf>jazzUri</jf>.resolve(<js>"authenticated/identity"</js>));
+		HttpResponse <jv>response</jv> = <jv>httpClient</jv>.execute(<jv>authenticatedURL</jv>);
 		<jk>try</jk> {
-			<jk>return</jk> response.getStatusLine().getStatusCode();
+			<jk>return</jk> <jv>response</jv>.getStatusLine().getStatusCode();
 		} <jk>finally</jk> {
-			EntityUtils.<jsm>consume</jsm>(response.getEntity());
+			EntityUtils.<jsm>consume</jsm>(<jv>response</jv>.getEntity());
 		}
 	}
 </p>
@@ -24830,14 +25110,14 @@
 <h4 class='topic' onclick='toggle(this)'><a href='#juneau-rest-client.Authentication.OIDC' id='juneau-rest-client.Authentication.OIDC'>9.15.3 - OIDC Authentication</a></h4>
 <div class='topic'><!-- START: 9.15.3 - juneau-rest-client.Authentication.OIDC -->
 <p>
-	The following example shows how the <c>JazzRestClient</c> class provides OIDC authentication 
-	support.
+	The following example shows an implementation of a client that performs OIDC authentication against
+	the IBM Jazz platform.
 </p>
 <p class='bpcode w800'>
 	<jd>/**
 	 * Constructor.
 	 */</jd>
-	<jk>public</jk> JazzRestClientBuilder(URI jazzUri, String user, String pw) <jk>throws</jk> IOException {
+	<jk>public</jk> JazzRestClientBuilder(URI <jv>jazzUri</jv>, String <jv>user</jv>, String <jv>pw</jv>) <jk>throws</jk> IOException {
 		...
 	}
 
@@ -24846,108 +25126,108 @@
 	 */</jd>
 	<ja>@Override</ja> <jc>/* RestClientBuilder */</jc>
 	<jk>protected</jk> CloseableHttpClient createHttpClient() <jk>throws</jk> Exception {
-		CloseableHttpClient client = <jk>super</jk>.createHttpClient();
-		oidcAuthenticate(client);
-			<jk>return</jk> client;
-		}
+		CloseableHttpClient <jv>client</jv> = <jk>super</jk>.createHttpClient();
+		oidcAuthenticate(<jv>client</jv>);
+		<jk>return</jk> <jv>client</jv>;
+	}
 
-	<jk>private void</jk> oidcAuthenticate(HttpClient client) <jk>throws</jk> IOException {
+	<jk>private void</jk> oidcAuthenticate(HttpClient <jv>client</jv>) <jk>throws</jk> IOException {
 
-		HttpGet request = <jk>new</jk> HttpGet(<jf>jazzUri</jf>);
-		request.setConfig(RequestConfig.<jsm>custom</jsm>().setRedirectsEnabled(<jk>false</jk>).build());
+		HttpGet <jv>request</jv> = <jk>new</jk> HttpGet(<jf>jazzUri</jf>);
+		<jv>request</jv>.setConfig(RequestConfig.<jsm>custom</jsm>().setRedirectsEnabled(<jk>false</jk>).build());
 		
 		<jc>// Charset must explicitly be set to UTF-8 to handle user/pw with non-ascii characters.</jc>
-		request.addHeader(<js>"Content-Type"</js>, <js>"application/x-www-form-urlencoded; charset=utf-8"</js>);
+		<jv>request</jv>.addHeader(<js>"Content-Type"</js>, <js>"application/x-www-form-urlencoded; charset=utf-8"</js>);
 
-		HttpResponse response = client.execute(request);
+		HttpResponse <jv>response</jv> = <jv>client</jv>.execute(<jv>request</jv>);
 		<jk>try</jk> {
-			<jk>int</jk> code = response.getStatusLine().getStatusCode();
+			<jk>int</jk> <jv>code</jv> = <jv>response</jv>.getStatusLine().getStatusCode();
 
 			<jc>// Already authenticated</jc>
-			<jk>if</jk> (code == <jsf>SC_OK</jsf>)
+			<jk>if</jk> (<jv>code</jv> == <jsf>SC_OK</jsf>)
 				<jk>return</jk>;
 
-			<jk>if</jk> (code != <jsf>SC_UNAUTHORIZED</jsf>)
+			<jk>if</jk> (<jv>code</jv> != <jsf>SC_UNAUTHORIZED</jsf>)
 				<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
 			<jc>// x-jsa-authorization-redirect</jc>
-			String redirectUri = getHeader(response, <js>"X-JSA-AUTHORIZATION-REDIRECT"</js>);
+			String <jv>redirectUri</jv> = getHeader(<jv>response</jv>, <js>"X-JSA-AUTHORIZATION-REDIRECT"</js>);
 
-			<jk>if</jk> (redirectUri == <jk>null</jk>)
+			<jk>if</jk> (<jv>redirectUri</jv> == <jk>null</jk>)
 				<jk>throw new</jk> RestCallException(<js>"Expected a redirect URI during OIDC authentication: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
 			<jc>// Handle Bearer Challenge</jc>
-			HttpGet method = <jk>new</jk> HttpGet(redirectUri + <js>"&amp;prompt=none"</js>);
-			addDefaultOidcHeaders(method);
+			HttpGet <jv>method</jv> = <jk>new</jk> HttpGet(<jv>redirectUri</jv> + <js>"&amp;prompt=none"</js>);
+			addDefaultOidcHeaders(<jv>method</jv>);
 
-			response = client.execute(method);
+			<jv>response</jv> = <jv>client</jv>.execute(<jv>method</jv>);
 
-			code = response.getStatusLine().getStatusCode();
+			<jv>code</jv> = <jv>response</jv>.getStatusLine().getStatusCode();
 
-			<jk>if</jk> (code != <jsf>SC_OK</jsf>)
+			<jk>if</jk> (<jv>code</jv> != <jsf>SC_OK</jsf>)
 				<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication phase 2: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
-			String loginRequired = getHeader(response, <js>"X-JSA-LOGIN-REQUIRED"</js>);
+			String <jv>loginRequired</jv> = getHeader(<jv>response</jv>, <js>"X-JSA-LOGIN-REQUIRED"</js>);
 
-			<jk>if</jk> (! <js>"true"</js>.equals(loginRequired))
+			<jk>if</jk> (! <js>"true"</js>.equals(<jv>loginRequired</jv>))
 				<jk>throw new</jk> RestCallException(<js>"X-JSA-LOGIN-REQUIRED header not found on response during OIDC authentication phase 2: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
-			method = <jk>new</jk> HttpGet(redirectUri + <js>"&amp;prompt=none"</js>);
+			<jv>method</jv> = <jk>new</jk> HttpGet(<jv>redirectUri</jv> + <js>"&amp;prompt=none"</js>);
 
-			addDefaultOidcHeaders(method);
-			response = client.execute(method);
+			addDefaultOidcHeaders(<jv>method</jv>);
+			<jv>response</jv> = <jv>client</jv>.execute(<jv>method</jv>);
 
-			code = response.getStatusLine().getStatusCode();
+			<jv>code</jv> = <jv>response</jv>.getStatusLine().getStatusCode();
 
-			<jk>if</jk> (code != <jsf>SC_OK</jsf>)
+			<jk>if</jk> (<jv>code</jv> != <jsf>SC_OK</jsf>)
 				<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication phase 3: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
 			<jc>// Handle JAS Challenge</jc>
-			method = <jk>new</jk> HttpGet(redirectUri);
-			addDefaultOidcHeaders(method);
+			<jv>method</jv> = <jk>new</jk> HttpGet(<jv>redirectUri</jv>);
+			addDefaultOidcHeaders(<jv>method</jv>);
 
-			response = client.execute(method);
+			<jv>response</jv> = <jv>client</jv>.execute(<jv>method</jv>);
 
-			code = response.getStatusLine().getStatusCode();
+			<jv>code</jv> = <jv>response</jv>.getStatusLine().getStatusCode();
 
-			<jk>if</jk> (code != <jsf>SC_OK</jsf>)
+			<jk>if</jk> (<jv>code</jv> != <jsf>SC_OK</jsf>)
 				<jk>throw new</jk> RestCallException(<js>"Unexpected response during OIDC authentication phase 4: "</js> 
-					+ response.getStatusLine());
+					+ <jv>response</jv>.getStatusLine());
 
-			<jf>cookie</jf> = getHeader(response, <js>"Set-Cookie"</js>);
+			<jf>cookie</jf> = getHeader(<jv>response</jv>, <js>"Set-Cookie"</js>);
 
-			Header[] defaultHeaders = <jk>new</jk> Header[] {
-				<jk>new</jk> BasicHeader(<js>"User-Agent"</js>, <js>"Jazz Native Client"</js>),
-				<jk>new</jk> BasicHeader(<js>"X-com-ibm-team-configuration-versions"</js>, 
+			Header[] <jv>defaultHeaders</jv> = <jk>new</jk> Header[] {
+				BasicStringHeader.<jsm>of</jsm>(<js>"User-Agent"</js>, <js>"Jazz Native Client"</js>),
+				BasicStringHeader.<jsm>of</jsm>(<js>"X-com-ibm-team-configuration-versions"</js>, 
 					<js>"com.ibm.team.rtc=6.0.0,com.ibm.team.jazz.foundation=6.0"</js>),
-				<jk>new</jk> BasicHeader(<js>"Accept"</js>, <js>"text/json"</js>),
-				<jk>new</jk> BasicHeader(<js>"Authorization"</js>, <js>"Basic "</js> 
+				BasicStringHeader.<jsm>of</jsm>(<js>"Accept"</js>, <js>"text/json"</js>),
+				BasicStringHeader.<jsm>of</jsm>(<js>"Authorization"</js>, <js>"Basic "</js> 
 					+ StringUtils.<jsm>base64EncodeToString</jsm>(<jf>user</jf> + <js>":"</js> + <jf>pw</jf>)),
-				<jk>new</jk> BasicHeader(<js>"Cookie"</js>, cookie)
+				BasicStringHeader.<jsm>of</jsm>(<js>"Cookie"</js>, <jf>cookie</jf>)
 			};
 
-			setDefaultHeaders(Arrays.<jsm>asList</jsm>(defaultHeaders));
+			setDefaultHeaders(AList.<jsm>of</jsm>(<jv>defaultHeaders</jv>));
 
 		} <jk>finally</jk> {
-			EntityUtils.<jsm>consume</jsm>(response.getEntity());
+			EntityUtils.<jsm>consume</jsm>(<jv>response</jv>.getEntity());
 		}
 	}
 
-	<jk>private void</jk> addDefaultOidcHeaders(HttpRequestBase method) {
-		method.addHeader(<js>"User-Agent"</js>, <js>"Jazz Native Client"</js>);
-		method.addHeader(<js>"X-com-ibm-team-configuration-versions"</js>, 
+	<jk>private void</jk> addDefaultOidcHeaders(HttpRequestBase <jv>method</jv>) {
+		<jv>method</jv>.addHeader(<js>"User-Agent"</js>, <js>"Jazz Native Client"</js>);
+		<jv>method</jv>.addHeader(<js>"X-com-ibm-team-configuration-versions"</js>, 
 			<js>"com.ibm.team.rtc=6.0.0,com.ibm.team.jazz.foundation=6.0"</js>);
-		method.addHeader(<js>"Accept"</js>, <js>"text/json"</js>);
+		<jv>method</jv>.addHeader(<js>"Accept"</js>, <js>"text/json"</js>);
 
 		<jk>if</jk> (<jf>cookie</jf> != <jk>null</jk>) {
-			method.addHeader(<js>"Authorization"</js>, <js>"Basic "</js> 
+			<jv>method</jv>.addHeader(<js>"Authorization"</js>, <js>"Basic "</js> 
 				+ StringUtils.<jsm>base64EncodeToString</jsm>(<jf>user</jf> + <js>":"</js> + <jf>pw</jf>));
-			method.addHeader(<js>"Cookie"</js>, cookie);
+			<jv>method</jv>.addHeader(<js>"Cookie"</js>, <jf>cookie</jf>);
 		}
 	}
 </p>
diff --git a/juneau-doc/src/main/javadoc/resources/fragments/toc.html b/juneau-doc/src/main/javadoc/resources/fragments/toc.html
index d9cdfdb..2c4cbb8 100644
--- a/juneau-doc/src/main/javadoc/resources/fragments/toc.html
+++ b/juneau-doc/src/main/javadoc/resources/fragments/toc.html
@@ -324,9 +324,9 @@
 		<li><p><a class='doclink' href='{OVERVIEW_URL}#juneau-rest-client.ResponseBody'>Response Body</a><span class='update'><b>8.1.4-new</b></span></p>
 		<li><p><a class='doclink' href='{OVERVIEW_URL}#juneau-rest-client.CustomCallHandlers'>Custom Call Handlers</a><span class='update'><b>8.1.4-new</b></span></p>
 		<li><p><a class='doclink' href='{OVERVIEW_URL}#juneau-rest-client.Interceptors'>Interceptors</a><span class='update'><b>8.1.4-new</b></span></p>
-		<li><p><a class='doclink' href='{OVERVIEW_URL}#juneau-rest-client.RestProxies'>REST Proxies</a><span class='update'><b>8.1.4-new</b></span></p>
+		<li><p><a class='doclink' href='{OVERVIEW_URL}#juneau-rest-client.RestProxies'>REST Proxies</a><span class='update'><b>8.1.4-updated</b></span></p>
 		<ol>
-			<li><p><a class='doclink' href='{OVERVIEW_URL}#juneau-rest-client.RestProxies.Remote'>@Remote</a><span class='update'>8.1.2-updated</span></p>
+			<li><p><a class='doclink' href='{OVERVIEW_URL}#juneau-rest-client.RestProxies.Remote'>@Remote</a><span class='update'>8.1.2-updated,<b>8.1.4-updated</b></span></p>
 			<li><p><a class='doclink' href='{OVERVIEW_URL}#juneau-rest-client.RestProxies.RemoteMethod'>@RemoteMethod</a><span class='update'><b>8.1.4-updated</b></span></p>
 			<li><p><a class='doclink' href='{OVERVIEW_URL}#juneau-rest-client.RestProxies.Body'>@Body</a></p>
 			<li><p><a class='doclink' href='{OVERVIEW_URL}#juneau-rest-client.RestProxies.FormData'>@FormData</a></p>
diff --git a/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/LargePojosResource.java b/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/LargePojosResource.java
index ea16b80..56e56e0 100644
--- a/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/LargePojosResource.java
+++ b/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/LargePojosResource.java
@@ -33,7 +33,7 @@ public class LargePojosResource extends BasicRestServletJena {
 	//====================================================================================================
 	@RestMethod(name=GET, path="/")
 	public LargePojo testGet() {
-		return LargePojo.create();
+		return LargePojo.get();
 	}
 
 	@RestMethod(name=PUT, path="/")
diff --git a/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyResource.java b/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyResource.java
index 1b90a62..636df23 100644
--- a/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyResource.java
+++ b/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyResource.java
@@ -16,7 +16,8 @@ import static java.util.Arrays.*;
 import static org.junit.Assert.*;
 import static org.apache.juneau.assertions.Assertions.*;
 import static org.apache.juneau.http.HttpMethodName.*;
-import static org.apache.juneau.rest.testutils.Constants.*;
+import static org.apache.juneau.testutils.Constants.*;
+
 import java.io.*;
 import java.util.*;
 
@@ -30,8 +31,8 @@ import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.http.annotation.Query;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
-import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.serializer.annotation.*;
+import org.apache.juneau.testutils.pojos.*;
 
 /**
  * JUnit automated testcase resource.
diff --git a/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyTest.java b/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyTest.java
index e1c6990..7011c3e 100644
--- a/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyTest.java
+++ b/juneau-microservice/juneau-microservice-ftest/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyTest.java
@@ -13,7 +13,7 @@
 package org.apache.juneau.rest.test.client;
 
 import static org.apache.juneau.assertions.Assertions.*;
-import static org.apache.juneau.rest.testutils.Constants.*;
+import static org.apache.juneau.testutils.Constants.*;
 import static org.junit.Assert.*;
 import static org.junit.Assert.assertEquals;
 import static org.junit.runners.MethodSorters.*;
@@ -34,8 +34,8 @@ import org.apache.juneau.parser.*;
 import org.apache.juneau.http.remote.*;
 import org.apache.juneau.rest.test.*;
 import org.apache.juneau.rest.test.client.ThirdPartyProxyTest.ThirdPartyProxy.*;
-import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.serializer.*;
+import org.apache.juneau.testutils.pojos.*;
 import org.apache.juneau.uon.*;
 import org.apache.juneau.urlencoding.*;
 import org.apache.juneau.xml.*;
diff --git a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_FormDataAnnotation_Test.java b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_FormDataAnnotation_Test.java
index 93e227c..a2f2c38 100644
--- a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_FormDataAnnotation_Test.java
+++ b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_FormDataAnnotation_Test.java
@@ -31,7 +31,7 @@ import org.apache.juneau.rest.RestRequest;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.http.remote.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
+import org.apache.juneau.testutils.*;
 import org.apache.juneau.uon.*;
 import org.apache.juneau.urlencoding.*;
 import org.apache.juneau.utils.*;
diff --git a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_HeaderAnnotation_Test.java b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_HeaderAnnotation_Test.java
index 412348c..008f67a 100644
--- a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_HeaderAnnotation_Test.java
+++ b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_HeaderAnnotation_Test.java
@@ -31,7 +31,7 @@ import org.apache.juneau.rest.RestRequest;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.http.remote.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
+import org.apache.juneau.testutils.*;
 import org.apache.juneau.uon.*;
 import org.junit.*;
 
diff --git a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_PathAnnotation_Test.java b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_PathAnnotation_Test.java
index 857a806..292421f 100644
--- a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_PathAnnotation_Test.java
+++ b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_PathAnnotation_Test.java
@@ -30,7 +30,7 @@ import org.apache.juneau.rest.RestRequest;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.http.remote.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
+import org.apache.juneau.testutils.*;
 import org.apache.juneau.uon.*;
 import org.junit.*;
 
diff --git a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_QueryAnnotation_Test.java b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_QueryAnnotation_Test.java
index 204aaa3..4c0b834 100644
--- a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_QueryAnnotation_Test.java
+++ b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_QueryAnnotation_Test.java
@@ -31,7 +31,7 @@ import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.RestRequest;
 import org.apache.juneau.http.remote.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
+import org.apache.juneau.testutils.*;
 import org.apache.juneau.uon.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
diff --git a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_RequestAnnotation_Test.java b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_RequestAnnotation_Test.java
index 58ccca9..f54dc76 100644
--- a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_RequestAnnotation_Test.java
+++ b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/Remote_RequestAnnotation_Test.java
@@ -27,7 +27,7 @@ import org.apache.juneau.internal.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.http.remote.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
+import org.apache.juneau.testutils.*;
 import org.junit.*;
 
 @FixMethodOrder(NAME_ASCENDING)
diff --git a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RrpcInterfaceTest.java b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RrpcInterfaceTest.java
index c252aa4..22ea53e 100644
--- a/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RrpcInterfaceTest.java
+++ b/juneau-rest/juneau-rest-client-utest/src/test/java/org/apache/juneau/rest/client2/RrpcInterfaceTest.java
@@ -15,7 +15,7 @@ package org.apache.juneau.rest.client2;
 import static java.util.Arrays.*;
 import static org.apache.juneau.assertions.Assertions.*;
 import static org.apache.juneau.http.HttpMethodName.*;
-import static org.apache.juneau.rest.testutils.Constants.*;
+import static org.apache.juneau.testutils.Constants.*;
 import static org.junit.Assert.*;
 import static org.junit.Assert.assertEquals;
 import static org.junit.runners.MethodSorters.*;
@@ -31,9 +31,9 @@ import org.apache.juneau.parser.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.serializer.annotation.*;
+import org.apache.juneau.testutils.pojos.*;
 import org.apache.juneau.uon.*;
 import org.apache.juneau.urlencoding.*;
 import org.apache.juneau.xml.*;
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java
index 5139191..5baddbd 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/remote/RemoteMeta.java
@@ -22,6 +22,7 @@ import org.apache.juneau.http.*;
 import org.apache.juneau.http.header.*;
 import org.apache.juneau.http.remote.*;
 import org.apache.juneau.reflect.*;
+import org.apache.juneau.svl.*;
 
 /**
  * Contains the meta-data about a REST proxy class.
@@ -37,7 +38,7 @@ import org.apache.juneau.reflect.*;
 public class RemoteMeta {
 
 	private final Map<Method,RemoteMethodMeta> methods;
-	private final HeaderSupplier headerSupplier = HeaderSupplier.create();
+	private final HeaderSupplier headerSupplier = HeaderSupplier.create().resolving();
 
 	/**
 	 * Constructor.
@@ -55,13 +56,18 @@ public class RemoteMeta {
 		for (org.apache.juneau.http.remote.RemoteResource r : ci.getAnnotations(org.apache.juneau.http.remote.RemoteResource.class))
 			if (! r.path().isEmpty())
 				path = trimSlashes(r.path());
+
+		String versionHeader = "X-Client-Version", clientVersion = null;
+
 		for (Remote r : ci.getAnnotations(Remote.class)) {
 			if (! r.path().isEmpty())
-				path = trimSlashes(r.path());
+				path = trimSlashes(resolve(r.path()));
 			for (String h : r.headers())
-				headerSupplier.add(BasicHeader.ofPair(h));
+				headerSupplier.add(BasicHeader.ofPair(resolve(h)));
 			if (! r.version().isEmpty())
-				headerSupplier.add(ClientVersion.of(r.version()));
+				clientVersion = resolve(r.version());
+			if (! r.versionHeader().isEmpty())
+				versionHeader = resolve(r.versionHeader());
 			if (r.headerSupplier() != HeaderSupplier.Null.class) {
 				try {
 					headerSupplier.add(r.headerSupplier().newInstance());
@@ -71,6 +77,9 @@ public class RemoteMeta {
 			}
 		}
 
+		if (clientVersion != null)
+			headerSupplier.add(BasicStringHeader.of(versionHeader, clientVersion));
+
 		AMap<Method,RemoteMethodMeta> methods = AMap.of();
 		for (MethodInfo m : ci.getPublicMethods())
 			methods.put(m.inner(), new RemoteMethodMeta(path, m.inner(), "GET"));
@@ -96,4 +105,12 @@ public class RemoteMeta {
 	public Iterable<Header> getHeaders() {
 		return headerSupplier;
 	}
+
+	//------------------------------------------------------------------------------------------------------------------
+	// Helper methods.
+	//------------------------------------------------------------------------------------------------------------------
+
+	private static String resolve(String s) {
+		return VarResolver.DEFAULT.resolve(s);
+	}
 }
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
index a2b1bdf..9332b7b 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClient.java
@@ -1202,7 +1202,7 @@ public class RestClient extends BeanContext implements HttpClient, Closeable, Re
 	 * 	String <jv>body</jv> = <jv>responseFuture</jv>.get().getBody().asString();
 	 *
 	 * 	<jc>// Use it to asynchronously retrieve a response.</jc>
-	 * 	Future&lt;MyBean&gtl <jv>myBeanFuture</jv> = <jv>client</jv>
+	 * 	Future&lt;MyBean&gt; <jv>myBeanFuture</jv> = <jv>client</jv>
 	 * 		.get(<jsf>URI</jsf>)
 	 * 		.run()
 	 * 		.getBody().asFuture(MyBean.<jk>class</jk>);
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java
index a81ce7a..6951e4f 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client2/RestClientBuilder.java
@@ -2554,7 +2554,7 @@ public class RestClientBuilder extends BeanContextBuilder {
 	 * 	String <jv>body</jv> = <jv>responseFuture</jv>.get().getBody().asString();
 	 *
 	 * 	<jc>// Use it to asynchronously retrieve a response.</jc>
-	 * 	Future&lt;MyBean&gtl <jv>myBeanFuture</jv> = <jv>client</jv>
+	 * 	Future&lt;MyBean&gt; <jv>myBeanFuture</jv> = <jv>client</jv>
 	 * 		.get(<jsf>URI</jsf>)
 	 * 		.run()
 	 * 		.getBody().asFuture(MyBean.<jk>class</jk>);
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/ABean.java b/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/ABean.java
deleted file mode 100644
index ce66ddb..0000000
--- a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/ABean.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                                                              *
-// *                                                                                                                         *
-// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
-// *                                                                                                                         *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the License.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.rest.testutils;
-
-import org.apache.juneau.marshall.*;
-
-public class ABean {
-	public int a;
-	public String b;
-
-	public static ABean get() {
-		ABean x = new ABean();
-		x.a = 1;
-		x.b = "foo";
-		return x;
-	}
-
-	@Override
-	public String toString() {
-		return SimpleJson.DEFAULT.toString(this);
-	}
-}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/DTOs.java b/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/DTOs.java
deleted file mode 100644
index fe1d1c4..0000000
--- a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/DTOs.java
+++ /dev/null
@@ -1,142 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                                                              *
-// *                                                                                                                         *
-// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
-// *                                                                                                                         *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the License.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.rest.testutils;
-
-import java.util.*;
-
-import org.apache.juneau.annotation.*;
-import org.apache.juneau.collections.*;
-import org.apache.juneau.urlencoding.annotation.*;
-
-public class DTOs {
-
-	@Bean(sort=true)
-	public static class A {
-		public String a;
-		public int b;
-		public boolean c;
-
-		public static A get() {
-			A t = new A();
-			t.a = "a";
-			t.b = 1;
-			t.c = true;
-			return t;
-		}
-
-	}
-
-	@Bean(sort=true)
-	public static class B {
-		public String[] f01;
-		public List<String> f02;
-		public int[] f03;
-		public List<Integer> f04;
-		public String[][] f05;
-		public List<String[]> f06;
-		public A[] f07;
-		public List<A> f08;
-		public A[][] f09;
-		public List<List<A>> f10;
-
-		private String[] f11;
-		private List<String> f12;
-		private int[] f13;
-		private List<Integer> f14;
-		private String[][] f15;
-		private List<String[]> f16;
-		private A[] f17;
-		private List<A> f18;
-		private A[][] f19;
-		private List<List<A>> f20;
-
-		public String[] getF11() { return f11; }
-		public List<String> getF12() { return f12; }
-		public int[] getF13() { return f13; }
-		public List<Integer> getF14() { return f14; }
-		public String[][] getF15() { return f15; }
-		public List<String[]> getF16() { return f16; }
-		public A[] getF17() { return f17; }
-		public List<A> getF18() { return f18; }
-		public A[][] getF19() { return f19; }
-		public List<List<A>> getF20() { return f20; }
-
-		public void setF11(String[] f11) { this.f11 = f11; }
-		public void setF12(List<String> f12) { this.f12 = f12; }
-		public void setF13(int[] f13) { this.f13 = f13; }
-		public void setF14(List<Integer> f14) { this.f14 = f14; }
-		public void setF15(String[][] f15) { this.f15 = f15; }
-		public void setF16(List<String[]> f16) { this.f16 = f16; }
-		public void setF17(A[] f17) { this.f17 = f17; }
-		public void setF18(List<A> f18) { this.f18 = f18; }
-		public void setF19(A[][] f19) { this.f19 = f19; }
-		public void setF20(List<List<A>> f20) { this.f20 = f20; }
-
-		public static B get() {
-			B t = new B();
-			t.f01 = new String[]{"a","b"};
-			t.f02 = AList.of("c","d");
-			t.f03 = new int[]{1,2};
-			t.f04 = AList.of(3,4);
-			t.f05 = new String[][]{{"e","f"},{"g","h"}};
-			t.f06 = AList.of(new String[]{"i","j"},new String[]{"k","l"});
-			t.f07 = new A[]{A.get(),A.get()};
-			t.f08 = AList.of(A.get(),A.get());
-			t.f09 = new A[][]{{A.get()},{A.get()}};
-			t.f10 = AList.of(Arrays.asList(A.get()),Arrays.asList(A.get()));
-			t.setF11(new String[]{"a","b"});
-			t.setF12(AList.of("c","d"));
-			t.setF13(new int[]{1,2});
-			t.setF14(AList.of(3,4));
-			t.setF15(new String[][]{{"e","f"},{"g","h"}});
-			t.setF16(AList.of(new String[]{"i","j"},new String[]{"k","l"}));
-			t.setF17(new A[]{A.get(),A.get()});
-			t.setF18(AList.of(A.get(),A.get()));
-			t.setF19(new A[][]{{A.get()},{A.get()}});
-			t.setF20(AList.of(Arrays.asList(A.get()),Arrays.asList(A.get())));
-			return t;
-		}
-
-		public static B INSTANCE = get();
-	}
-
-	@UrlEncoding(expandedParams=true)
-	public static class C extends B {
-		public static C get() {
-			C t = new C();
-			t.f01 = new String[]{"a","b"};
-			t.f02 = AList.of("c","d");
-			t.f03 = new int[]{1,2};
-			t.f04 = AList.of(3, 4);
-			t.f05 = new String[][]{{"e","f"},{"g","h"}};
-			t.f06 = AList.of(new String[]{"i","j"}, new String[]{"k","l"});
-			t.f07 = new A[]{A.get(),A.get()};
-			t.f08 = AList.of(A.get(), A.get());
-			t.f09 = new A[][]{{A.get()},{A.get()}};
-			t.f10 = AList.of(Arrays.asList(A.get()), Arrays.asList(A.get()));
-			t.setF11(new String[]{"a","b"});
-			t.setF12(AList.of("c","d"));
-			t.setF13(new int[]{1,2});
-			t.setF14(AList.of(3,4));
-			t.setF15(new String[][]{{"e","f"},{"g","h"}});
-			t.setF16(AList.of(new String[]{"i","j"},new String[]{"k","l"}));
-			t.setF17(new A[]{A.get(),A.get()});
-			t.setF18(AList.of(A.get(), A.get()));
-			t.setF19(new A[][]{{A.get()},{A.get()}});
-			t.setF20(AList.of(Arrays.asList(A.get()), Arrays.asList(A.get())));
-			return t;
-		}
-
-		public static C INSTANCE = get();
-	}
-}
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/DTOs2.java b/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/DTOs2.java
deleted file mode 100644
index e84d0f8..0000000
--- a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/DTOs2.java
+++ /dev/null
@@ -1,143 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                                                              *
-// *                                                                                                                         *
-// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
-// *                                                                                                                         *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the License.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.rest.testutils;
-
-import java.util.*;
-
-import org.apache.juneau.annotation.*;
-import org.apache.juneau.collections.*;
-import org.apache.juneau.urlencoding.annotation.*;
-
-public class DTOs2 {
-
-	@BeanConfig(applyBean={@Bean(on="A,B,C",sort=true)})
-	@UrlEncodingConfig(applyUrlEncoding={@UrlEncoding(on="C",expandedParams=true)})
-	public static class Annotations {}
-
-	public static class A {
-		public String a;
-		public int b;
-		public boolean c;
-
-		public static A get() {
-			A t = new A();
-			t.a = "a";
-			t.b = 1;
-			t.c = true;
-			return t;
-		}
-
-	}
-
-	public static class B {
-		public String[] f01;
-		public List<String> f02;
-		public int[] f03;
-		public List<Integer> f04;
-		public String[][] f05;
-		public List<String[]> f06;
-		public A[] f07;
-		public List<A> f08;
-		public A[][] f09;
-		public List<List<A>> f10;
-
-		private String[] f11;
-		private List<String> f12;
-		private int[] f13;
-		private List<Integer> f14;
-		private String[][] f15;
-		private List<String[]> f16;
-		private A[] f17;
-		private List<A> f18;
-		private A[][] f19;
-		private List<List<A>> f20;
-
-		public String[] getF11() { return f11; }
-		public List<String> getF12() { return f12; }
-		public int[] getF13() { return f13; }
-		public List<Integer> getF14() { return f14; }
-		public String[][] getF15() { return f15; }
-		public List<String[]> getF16() { return f16; }
-		public A[] getF17() { return f17; }
-		public List<A> getF18() { return f18; }
-		public A[][] getF19() { return f19; }
-		public List<List<A>> getF20() { return f20; }
-
-		public void setF11(String[] f11) { this.f11 = f11; }
-		public void setF12(List<String> f12) { this.f12 = f12; }
-		public void setF13(int[] f13) { this.f13 = f13; }
-		public void setF14(List<Integer> f14) { this.f14 = f14; }
-		public void setF15(String[][] f15) { this.f15 = f15; }
-		public void setF16(List<String[]> f16) { this.f16 = f16; }
-		public void setF17(A[] f17) { this.f17 = f17; }
-		public void setF18(List<A> f18) { this.f18 = f18; }
-		public void setF19(A[][] f19) { this.f19 = f19; }
-		public void setF20(List<List<A>> f20) { this.f20 = f20; }
-
-		public static B get() {
-			B t = new B();
-			t.f01 = new String[]{"a","b"};
-			t.f02 = AList.of("c","d");
-			t.f03 = new int[]{1,2};
-			t.f04 = AList.of(3,4);
-			t.f05 = new String[][]{{"e","f"},{"g","h"}};
-			t.f06 = AList.of(new String[]{"i","j"},new String[]{"k","l"});
-			t.f07 = new A[]{A.get(),A.get()};
-			t.f08 = AList.of(A.get(),A.get());
-			t.f09 = new A[][]{{A.get()},{A.get()}};
-			t.f10 = AList.of(Arrays.asList(A.get()),Arrays.asList(A.get()));
-			t.setF11(new String[]{"a","b"});
-			t.setF12(AList.of("c","d"));
-			t.setF13(new int[]{1,2});
-			t.setF14(AList.of(3,4));
-			t.setF15(new String[][]{{"e","f"},{"g","h"}});
-			t.setF16(AList.of(new String[]{"i","j"},new String[]{"k","l"}));
-			t.setF17(new A[]{A.get(),A.get()});
-			t.setF18(AList.of(A.get(),A.get()));
-			t.setF19(new A[][]{{A.get()},{A.get()}});
-			t.setF20(AList.of(Arrays.asList(A.get()),Arrays.asList(A.get())));
-			return t;
-		}
-
-		public static B INSTANCE = get();
-	}
-
-	public static class C extends B {
-		public static C get() {
-			C t = new C();
-			t.f01 = new String[]{"a","b"};
-			t.f02 = AList.of("c","d");
-			t.f03 = new int[]{1,2};
-			t.f04 = AList.of(3, 4);
-			t.f05 = new String[][]{{"e","f"},{"g","h"}};
-			t.f06 = AList.of(new String[]{"i","j"}, new String[]{"k","l"});
-			t.f07 = new A[]{A.get(),A.get()};
-			t.f08 = AList.of(A.get(), A.get());
-			t.f09 = new A[][]{{A.get()},{A.get()}};
-			t.f10 = AList.of(Arrays.asList(A.get()), Arrays.asList(A.get()));
-			t.setF11(new String[]{"a","b"});
-			t.setF12(AList.of("c","d"));
-			t.setF13(new int[]{1,2});
-			t.setF14(AList.of(3,4));
-			t.setF15(new String[][]{{"e","f"},{"g","h"}});
-			t.setF16(AList.of(new String[]{"i","j"},new String[]{"k","l"}));
-			t.setF17(new A[]{A.get(),A.get()});
-			t.setF18(AList.of(A.get(), A.get()));
-			t.setF19(new A[][]{{A.get()},{A.get()}});
-			t.setF20(AList.of(Arrays.asList(A.get()), Arrays.asList(A.get())));
-			return t;
-		}
-
-		public static C INSTANCE = get();
-	}
-}
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/ImplicitSwappedPojo.java b/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/ImplicitSwappedPojo.java
deleted file mode 100644
index e65cee4..0000000
--- a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/ImplicitSwappedPojo.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                                                              *
-// *                                                                                                                         *
-// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
-// *                                                                                                                         *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the License.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.rest.testutils;
-
-import static org.apache.juneau.rest.testutils.Constants.*;
-
-import org.apache.juneau.annotation.*;
-
-@BeanIgnore
-public class ImplicitSwappedPojo {
-	public boolean wasUnswapped;
-
-	@Override
-	public String toString() {
-		return SWAP;
-	}
-
-	public ImplicitSwappedPojo() {}
-
-
-	public ImplicitSwappedPojo(String fromString) {
-		if (fromString.equals(SWAP))
-			wasUnswapped = true;
-	}
-}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/SwappedPojo.java b/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/SwappedPojo.java
deleted file mode 100644
index 17d3249..0000000
--- a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/SwappedPojo.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                                                              *
-// *                                                                                                                         *
-// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
-// *                                                                                                                         *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the License.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.rest.testutils;
-
-import org.apache.juneau.annotation.*;
-
-@Swap(SwappedPojoSwap.class)
-public class SwappedPojo {
-	public boolean wasUnswapped;
-}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/SwappedPojoSwap.java b/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/SwappedPojoSwap.java
deleted file mode 100644
index ffae878..0000000
--- a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/SwappedPojoSwap.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                                                              *
-// *                                                                                                                         *
-// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
-// *                                                                                                                         *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the License.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.rest.testutils;
-
-import static org.apache.juneau.rest.testutils.Constants.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.parser.*;
-import org.apache.juneau.serializer.*;
-import org.apache.juneau.transform.*;
-
-public class SwappedPojoSwap extends PojoSwap<SwappedPojo,String> {
-	@Override
-	public String swap(BeanSession session, SwappedPojo c) throws SerializeException {
-		return SWAP;
-	}
-
-	@Override
-	public SwappedPojo unswap(BeanSession session, String f, ClassMeta<?> hint) throws ParseException {
-		SwappedPojo c = new SwappedPojo();
-		if (f.equals(SWAP))
-			c.wasUnswapped = true;
-		return c;
-	}
-}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/TestEnum.java b/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/TestEnum.java
deleted file mode 100644
index c869f53..0000000
--- a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/TestEnum.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                                                              *
-// *                                                                                                                         *
-// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
-// *                                                                                                                         *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the License.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.rest.testutils;
-
-public enum TestEnum {
-	ONE,TWO,THREE
-}
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/TypedBean.java b/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/TypedBean.java
deleted file mode 100644
index 078ce88..0000000
--- a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/TypedBean.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                                                              *
-// *                                                                                                                         *
-// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
-// *                                                                                                                         *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the License.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.rest.testutils;
-
-@org.apache.juneau.annotation.Bean(dictionary={TypedBeanImpl.class})
-public interface TypedBean {
-}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/TypedBeanImpl.java b/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/TypedBeanImpl.java
deleted file mode 100644
index 95f0352..0000000
--- a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/TypedBeanImpl.java
+++ /dev/null
@@ -1,26 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                                                              *
-// *                                                                                                                         *
-// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
-// *                                                                                                                         *
-// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the License.                                              *
-// ***************************************************************************************************************************
-package org.apache.juneau.rest.testutils;
-
-@org.apache.juneau.annotation.Bean(typeName="TypedBeanImpl", sort=true)
-public class TypedBeanImpl implements TypedBean {
-	public int a;
-	public String b;
-
-	public static TypedBeanImpl get() {
-		TypedBeanImpl x = new TypedBeanImpl();
-		x.a = 1;
-		x.b = "foo";
-		return x;
-	}
-}
\ No newline at end of file
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java
index 4bc2591..f055ac5 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/BodyAnnotationTest.java
@@ -33,9 +33,7 @@ import org.apache.juneau.jsonschema.annotation.*;
 import org.apache.juneau.marshall.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
-import org.apache.juneau.rest.testutils.DTOs;
-import org.apache.juneau.rest.testutils.DTOs2;
+import org.apache.juneau.testutils.pojos.*;
 import org.apache.juneau.uon.*;
 import org.apache.juneau.urlencoding.*;
 import org.apache.juneau.urlencoding.annotation.*;
@@ -849,11 +847,11 @@ public class BodyAnnotationTest {
 	@Rest(serializers=SimpleJsonSerializer.class, parsers=JsonParser.class, defaultAccept="application/json")
 	public static class E {
 		@RestMethod(name=PUT, path="/B")
-		public DTOs.B testPojo1(@Body DTOs.B b) {
+		public XBeans.XB testPojo1(@Body XBeans.XB b) {
 			return b;
 		}
 		@RestMethod(name=PUT, path="/C")
-		public DTOs.C testPojo2(@Body DTOs.C c) {
+		public XBeans.XC testPojo2(@Body XBeans.XC c) {
 			return c;
 		}
 	}
@@ -862,28 +860,28 @@ public class BodyAnnotationTest {
 	@Test
 	public void e01_complexPojos_B_body() throws Exception {
 		String expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true} [...]
-		e.put("/B", SimpleJsonSerializer.DEFAULT.toString(DTOs.B.INSTANCE), "application/json")
+		e.put("/B", SimpleJsonSerializer.DEFAULT.toString(XBeans.XB.INSTANCE), "application/json")
 			.run()
 			.assertBody().is(expected);
 	}
 	@Test
 	public void e02_complexPojos_B_bodyParam() throws Exception {
 		String expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true} [...]
-		e.put("/B?body=" + UonSerializer.DEFAULT.serialize(DTOs.B.INSTANCE), "a")
+		e.put("/B?body=" + UonSerializer.DEFAULT.serialize(XBeans.XB.INSTANCE), "a")
 			.run()
 			.assertBody().is(expected);
 	}
 	@Test
 	public void e03_complexPojos_C_body() throws Exception {
 		String expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true} [...]
-		e.put("/C", SimpleJsonSerializer.DEFAULT.toString(DTOs.B.INSTANCE), "application/json")
+		e.put("/C", SimpleJsonSerializer.DEFAULT.toString(XBeans.XB.INSTANCE), "application/json")
 			.run()
 			.assertBody().is(expected);
 	}
 	@Test
 	public void e04_complexPojos_C_bodyParam() throws Exception {
 		String expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true} [...]
-		e.put("/C?body=" + UonSerializer.DEFAULT.serialize(DTOs.B.INSTANCE), "a")
+		e.put("/C?body=" + UonSerializer.DEFAULT.serialize(XBeans.XB.INSTANCE), "a")
 			.run()
 			.assertBody().is(expected);
 	}
@@ -893,11 +891,11 @@ public class BodyAnnotationTest {
 	@UrlEncodingConfig(applyUrlEncoding={@UrlEncoding(on="C",expandedParams=true)})
 	public static class E2 {
 		@RestMethod(name=PUT, path="/B")
-		public DTOs2.B testPojo1(@Body DTOs2.B b) {
+		public XBeans.XE testPojo1(@Body XBeans.XE b) {
 			return b;
 		}
 		@RestMethod(name=PUT, path="/C")
-		public DTOs2.C testPojo2(@Body DTOs2.C c) {
+		public XBeans.XF testPojo2(@Body XBeans.XF c) {
 			return c;
 		}
 	}
@@ -906,28 +904,28 @@ public class BodyAnnotationTest {
 	@Test
 	public void e05_complexPojos_B_body() throws Exception {
 		String expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true} [...]
-		e2.put("/B", SimpleJsonSerializer.DEFAULT.builder().applyAnnotations(DTOs2.Annotations.class).build().toString(DTOs2.B.INSTANCE), "application/json")
+		e2.put("/B", SimpleJsonSerializer.DEFAULT.builder().applyAnnotations(XBeans.Annotations.class).build().toString(XBeans.XE.INSTANCE), "application/json")
 			.run()
 			.assertBody().is(expected);
 	}
 	@Test
 	public void e06_complexPojos_B_bodyParam() throws Exception {
 		String expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true} [...]
-		e2.put("/B?body=" + UonSerializer.DEFAULT.builder().applyAnnotations(DTOs2.Annotations.class).build().serialize(DTOs2.B.INSTANCE), "a")
+		e2.put("/B?body=" + UonSerializer.DEFAULT.builder().applyAnnotations(XBeans.Annotations.class).build().serialize(XBeans.XE.INSTANCE), "a")
 			.run()
 			.assertBody().is(expected);
 	}
 	@Test
 	public void e07_complexPojos_C_body() throws Exception {
 		String expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true} [...]
-		e2.put("/C", SimpleJsonSerializer.DEFAULT.builder().applyAnnotations(DTOs2.Annotations.class).build().toString(DTOs2.B.INSTANCE), "application/json")
+		e2.put("/C", SimpleJsonSerializer.DEFAULT.builder().applyAnnotations(XBeans.Annotations.class).build().toString(XBeans.XE.INSTANCE), "application/json")
 			.run()
 			.assertBody().is(expected);
 	}
 	@Test
 	public void e08_complexPojos_C_bodyParam() throws Exception {
 		String expected = "{f01:['a','b'],f02:['c','d'],f03:[1,2],f04:[3,4],f05:[['e','f'],['g','h']],f06:[['i','j'],['k','l']],f07:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f08:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f09:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f10:[[{a:'a',b:1,c:true}],[{a:'a',b:1,c:true}]],f11:['a','b'],f12:['c','d'],f13:[1,2],f14:[3,4],f15:[['e','f'],['g','h']],f16:[['i','j'],['k','l']],f17:[{a:'a',b:1,c:true},{a:'a',b:1,c:true}],f18:[{a:'a',b:1,c:true},{a:'a',b:1,c:true} [...]
-		e2.put("/C?body=" + UonSerializer.DEFAULT.builder().applyAnnotations(DTOs2.Annotations.class).build().serialize(DTOs2.B.INSTANCE), "a")
+		e2.put("/C?body=" + UonSerializer.DEFAULT.builder().applyAnnotations(XBeans.Annotations.class).build().serialize(XBeans.XE.INSTANCE), "a")
 			.run()
 			.assertBody().is(expected);
 	}
@@ -977,7 +975,7 @@ public class BodyAnnotationTest {
 	@Rest(serializers=UrlEncodingSerializer.class,parsers=UrlEncodingParser.class)
 	public static class G {
 		@RestMethod(name=POST,path="/")
-		public DTOs.C g(@Body DTOs.C content) throws Exception {
+		public XBeans.XC g(@Body XBeans.XC content) throws Exception {
 			return content;
 		}
 	}
@@ -1025,7 +1023,7 @@ public class BodyAnnotationTest {
 				@Property(name=UrlEncodingParser.URLENC_expandedParams, value="true")
 			}
 		)
-		public DTOs.B g(@Body DTOs.B content) throws Exception {
+		public XBeans.XB g(@Body XBeans.XB content) throws Exception {
 			return content;
 		}
 	}
@@ -1069,7 +1067,7 @@ public class BodyAnnotationTest {
 				@Property(name=UrlEncodingParser.URLENC_expandedParams, value="true")
 			}
 		)
-		public DTOs2.B g(@Body DTOs2.B content) throws Exception {
+		public XBeans.XE g(@Body XBeans.XE content) throws Exception {
 			return content;
 		}
 	}
@@ -1110,7 +1108,7 @@ public class BodyAnnotationTest {
 	@Rest(serializers=JsonSerializer.class,parsers=JsonParser.class)
 	public static class I {
 		@RestMethod(name=POST,path="/")
-		public DTOs.B g(@Body(r=true) DTOs.B content) throws Exception {
+		public XBeans.XB g(@Body(r=true) XBeans.XB content) throws Exception {
 			return content;
 		}
 	}
@@ -1132,7 +1130,7 @@ public class BodyAnnotationTest {
 		@RestMethod(name=POST,path="/")
 		@BeanConfig(applyBean={@Bean(on="A,B,C",sort=true)})
 		@UrlEncodingConfig(applyUrlEncoding={@UrlEncoding(on="C",expandedParams=true)})
-		public DTOs2.B g(@Body(r=true) DTOs2.B content) throws Exception {
+		public XBeans.XE g(@Body(r=true) XBeans.XE content) throws Exception {
 			return content;
 		}
 	}
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java
index 1513c0c..4bfd282 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/FormDataAnnotationTest.java
@@ -27,7 +27,7 @@ import org.apache.juneau.json.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
+import org.apache.juneau.testutils.pojos.*;
 import org.apache.juneau.urlencoding.*;
 import org.junit.*;
 
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/HeaderAnnotationTest.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/HeaderAnnotationTest.java
index 44c5153..e1e6d10 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/HeaderAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/HeaderAnnotationTest.java
@@ -25,7 +25,7 @@ import org.apache.juneau.http.annotation.*;
 import org.apache.juneau.json.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
+import org.apache.juneau.testutils.pojos.*;
 import org.junit.*;
 
 @FixMethodOrder(NAME_ASCENDING)
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java
index 9b63eea..ce84138 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/PathAnnotationTest.java
@@ -28,7 +28,7 @@ import org.apache.juneau.marshall.*;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
+import org.apache.juneau.testutils.pojos.*;
 import org.junit.*;
 
 @FixMethodOrder(NAME_ASCENDING)
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java
index 99f5468..13aa04e 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/PathRemainderAnnotationTest.java
@@ -22,7 +22,7 @@ import org.apache.juneau.http.annotation.Path;
 import org.apache.juneau.json.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
+import org.apache.juneau.testutils.pojos.*;
 import org.junit.*;
 
 @FixMethodOrder(NAME_ASCENDING)
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java
index 8bc7be1..8830cb0 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/annotation2/QueryAnnotationTest.java
@@ -28,7 +28,7 @@ import org.apache.juneau.jsonschema.annotation.Items;
 import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.mock2.*;
-import org.apache.juneau.rest.testutils.*;
+import org.apache.juneau.testutils.pojos.*;
 import org.junit.*;
 
 @FixMethodOrder(NAME_ASCENDING)
diff --git a/juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
similarity index 100%
rename from juneau-rest/juneau-rest-mock-utest/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java
rename to juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/testutils/TestUtils.java