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 2018/07/11 22:55:24 UTC

[juneau] branch master updated: Introduce sessions to HttpPart serializers and parsers.

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 8072b05  Introduce sessions to HttpPart serializers and parsers.
8072b05 is described below

commit 8072b05b1866fff21de359973cbccc56fa2fdb22
Author: JamesBognar <ja...@apache.org>
AuthorDate: Wed Jul 11 18:55:12 2018 -0400

    Introduce sessions to HttpPart serializers and parsers.
---
 .../juneau/httppart/OpenApiPartParserTest.java     |   2 +-
 .../juneau/httppart/OpenApiPartSerializerTest.java |   2 +-
 .../apache/juneau/httppart/UonPartParserTest.java  |   8 +-
 .../java/org/apache/juneau/xml/XmlContentTest.java |   8 +-
 .../java/org/apache/juneau/dto/LinkString.java     |   2 +-
 .../org/apache/juneau/html/HtmlSerializer.java     |   2 +-
 .../org/apache/juneau/httppart/HttpPartParser.java |  16 +-
 ...pPartParser.java => HttpPartParserSession.java} |  24 +-
 .../apache/juneau/httppart/HttpPartSerializer.java |  19 +-
 ...ializer.java => HttpPartSerializerSession.java} |  41 +--
 .../org/apache/juneau/httppart/HttpPartType.java   |   2 +-
 .../apache/juneau/httppart/OpenApiPartParser.java  | 232 ++---------------
 ...rtParser.java => OpenApiPartParserSession.java} | 222 ++---------------
 .../juneau/httppart/OpenApiPartSerializer.java     | 274 ++-------------------
 .../httppart/OpenApiPartSerializerBuilder.java     | 196 +++++++--------
 ...izer.java => OpenApiPartSerializerSession.java} |  66 ++---
 .../apache/juneau/httppart/SimplePartParser.java   |  22 +-
 ...pPartType.java => SimplePartParserSession.java} |  33 ++-
 .../juneau/httppart/SimplePartSerializer.java      |  17 +-
 ...lizer.java => SimplePartSerializerSession.java} |  15 +-
 .../juneau/httppart/SimpleUonPartSerializer.java   |  16 +-
 ...pe.java => SimpleUonPartSerializerSession.java} |  39 +--
 .../org/apache/juneau/httppart/UonPartParser.java  |  49 +---
 ...onPartParser.java => UonPartParserSession.java} |  90 +++----
 .../apache/juneau/httppart/UonPartSerializer.java  |  46 +---
 ...rializer.java => UonPartSerializerSession.java} | 106 +++++---
 .../org/apache/juneau/json/JsonSerializer.java     |   6 +-
 .../juneau/jsonschema/JsonSchemaSerializer.java    |   4 +-
 .../main/java/org/apache/juneau/parser/Parser.java |   2 +-
 .../org/apache/juneau/parser/ParserSession.java    |   3 +-
 .../apache/juneau/parser/ParserSessionArgs.java    |   5 +
 .../serializer/OutputStreamSerializerSession.java  |   2 +-
 .../org/apache/juneau/serializer/Serializer.java   |  57 ++++-
 .../juneau/serializer/SerializerBuilder.java       |  53 ++++
 .../juneau/serializer/SerializerGroupBuilder.java  |  10 +-
 .../juneau/serializer/SerializerSession.java       |  16 +-
 .../juneau/serializer/SerializerSessionArgs.java   |  24 +-
 .../apache/juneau/serializer/WriterSerializer.java |  55 -----
 .../juneau/serializer/WriterSerializerBuilder.java |  53 ----
 .../juneau/serializer/WriterSerializerSession.java |  11 -
 .../java/org/apache/juneau/uon/UonSerializer.java  |   2 +-
 .../juneau/urlencoding/UrlEncodingSerializer.java  |   2 +-
 .../java/org/apache/juneau/xml/XmlSerializer.java  |   4 +-
 .../rest/test/client/RequestBeanProxyTest.java     |  43 ++--
 .../rest/test/client/ThirdPartyProxyTest.java      |   9 +-
 .../org/apache/juneau/rest/client/RestCall.java    |   6 +-
 .../juneau/rest/client/RestClientBuilder.java      |  12 +-
 .../rest/client/SerializedNameValuePair.java       |   2 +-
 .../org/apache/juneau/rest/jaxrs/BaseProvider.java |   2 +-
 .../apache/juneau/rest/BasicRestInfoProvider.java  |   7 +-
 .../java/org/apache/juneau/rest/RequestBody.java   |  12 +-
 .../org/apache/juneau/rest/RequestFormData.java    |  19 +-
 .../org/apache/juneau/rest/RequestHeaders.java     |  20 +-
 .../org/apache/juneau/rest/RequestPathMatch.java   |  18 +-
 .../java/org/apache/juneau/rest/RequestQuery.java  |  21 +-
 .../org/apache/juneau/rest/RestParamDefaults.java  |   4 +-
 .../java/org/apache/juneau/rest/RestRequest.java   |  38 +--
 .../java/org/apache/juneau/rest/RestResponse.java  |   2 +-
 .../apache/juneau/rest/converters/Queryable.java   |  75 +++++-
 .../juneau/rest/response/DefaultHandler.java       |   2 +-
 .../apache/juneau/rest/widget/MenuItemWidget.java  |   2 +-
 61 files changed, 773 insertions(+), 1379 deletions(-)

diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartParserTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartParserTest.java
index 757d87d..226f67a 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartParserTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartParserTest.java
@@ -28,7 +28,7 @@ import org.junit.runners.*;
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class OpenApiPartParserTest {
 
-	static OpenApiPartParser p = OpenApiPartParser.DEFAULT;
+	static OpenApiPartParserSession p = OpenApiPartParser.DEFAULT.createSession();
 
 	//-----------------------------------------------------------------------------------------------------------------
 	// Input validations
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartSerializerTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartSerializerTest.java
index a7eef07..f19a56f 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartSerializerTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/OpenApiPartSerializerTest.java
@@ -26,7 +26,7 @@ import org.junit.runners.*;
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class OpenApiPartSerializerTest {
 
-	static OpenApiPartSerializer s = OpenApiPartSerializer.DEFAULT;
+	static OpenApiPartSerializerSession s = OpenApiPartSerializer.DEFAULT.createSession();
 
 	//-----------------------------------------------------------------------------------------------------------------
 	// Input validations
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/UonPartParserTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/UonPartParserTest.java
index 011f19b..9383f08 100644
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/UonPartParserTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/httppart/UonPartParserTest.java
@@ -25,8 +25,8 @@ import org.junit.runners.*;
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 public class UonPartParserTest {
 
-	static UonPartParser p = UonPartParser.DEFAULT;
-	static BeanSession bs = p.createBeanSession();
+	static UonPartParserSession p = UonPartParser.DEFAULT.createSession();
+	static BeanSession bs = p;
 
 	//====================================================================================================
 	// Basic test
@@ -250,7 +250,7 @@ public class UonPartParserTest {
 	//====================================================================================================
 	@Test
 	public void testSimpleBean() throws Exception {
-		UonPartParser p = UonPartParser.DEFAULT;
+		UonPartParserSession p = UonPartParser.DEFAULT.createSession();
 		A t;
 		String s = null;
 
@@ -274,7 +274,7 @@ public class UonPartParserTest {
 	public void testParseParameterObjectMap() throws Exception {
 		String in = "(name='foo bar')";
 
-		ObjectMap r =  UonPartParser.DEFAULT.parse(HttpPartType.QUERY, in, BeanContext.DEFAULT.createSession().getClassMeta(ObjectMap.class));
+		ObjectMap r =  UonPartParser.DEFAULT.createSession().parse(HttpPartType.QUERY, in, BeanContext.DEFAULT.createSession().getClassMeta(ObjectMap.class));
 
 		assertEquals("{name:'foo bar'}", JsonSerializer.DEFAULT_LAX.toString(r));
 	}
diff --git a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/XmlContentTest.java b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/XmlContentTest.java
index 047e3e7..a8845a1 100755
--- a/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/XmlContentTest.java
+++ b/juneau-core/juneau-core-test/src/test/java/org/apache/juneau/xml/XmlContentTest.java
@@ -44,7 +44,7 @@ public class XmlContentTest {
 		t.f2 = null;
 
 		sw = new StringWriter();
-		session = s1.createSession(new SerializerSessionArgs(null, null, null, null, null, null, null));
+		session = s1.createSession(new SerializerSessionArgs(null, null, null, null, null, null, null, null));
 		session.serialize(t, sw);
 		r = sw.toString();
 		assertEquals("<A f1='f1'>_x0000_</A>", r);
@@ -52,7 +52,7 @@ public class XmlContentTest {
 		assertEqualObjects(t, t2);
 
 		sw = new StringWriter();
-		session = s2.createSession(new SerializerSessionArgs(null, null, null, null, null, null, null));
+		session = s2.createSession(new SerializerSessionArgs(null, null, null, null, null, null, null, null));
 		session.serialize(t, sw);
 		r = sw.toString();
 		assertEquals("<A f1='f1'>_x0000_</A>\n", r);
@@ -152,7 +152,7 @@ public class XmlContentTest {
 		t.f2 = null;
 
 		sw = new StringWriter();
-		session = s1.createSession(new SerializerSessionArgs(null, null, null, null, null, null, null));
+		session = s1.createSession(new SerializerSessionArgs(null, null, null, null, null, null, null, null));
 		session.serialize(t, sw);
 		r = sw.toString();
 		assertEquals("<A f1='f1'>_x0000_</A>", r);
@@ -160,7 +160,7 @@ public class XmlContentTest {
 		assertEqualObjects(t, t2);
 
 		sw = new StringWriter();
-		session = s2.createSession(new SerializerSessionArgs(null, null, null, null, null, null, null));
+		session = s2.createSession(new SerializerSessionArgs(null, null, null, null, null, null, null, null));
 		session.serialize(t, sw);
 		r = sw.toString();
 		assertEquals("<A f1='f1'>_x0000_</A>\n", r);
diff --git a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/LinkString.java b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/LinkString.java
index d9a75b0..e0980d2 100644
--- a/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/LinkString.java
+++ b/juneau-core/juneau-dto/src/main/java/org/apache/juneau/dto/LinkString.java
@@ -121,7 +121,7 @@ public class LinkString implements Comparable<LinkString> {
 	public LinkString uri(String uri, Object...args) {
 		for (int i = 0; i < args.length; i++)
 			try {
-				args[i] = SimpleUonPartSerializer.DEFAULT.serialize(HttpPartType.PATH, args[i]);
+				args[i] = SimpleUonPartSerializer.DEFAULT.createSession().serialize(HttpPartType.PATH, null, args[i]);
 			} catch (SchemaValidationException | SerializeException e) {
 				throw new RuntimeException(e);
 			}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java
index a4ad9d1..e3c6366 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java
@@ -617,7 +617,7 @@ public class HtmlSerializer extends XmlSerializer {
 			super(
 				ps.builder()
 					.set(WSERIALIZER_quoteChar, '\'')
-					.set(WSERIALIZER_useWhitespace, true)
+					.set(SERIALIZER_useWhitespace, true)
 					.build()
 			);
 		}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartParser.java
index bd70465..1b71811 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartParser.java
@@ -41,18 +41,10 @@ public interface HttpPartParser {
 	public static interface Null extends HttpPartParser {}
 
 	/**
-	 * Converts the specified input to the specified class type.
+	 * Creates a new parser session.
 	 *
-	 * @param partType The part type being parsed.
-	 * @param schema
-	 * 	Schema information about the part.
-	 * 	<br>May be <jk>null</jk>.
-	 * 	<br>Not all part parsers use the schema information.
-	 * @param in The input being parsed.
-	 * @param type The category of value being parsed.
-	 * @return The parsed value.
-	 * @throws ParseException If a problem occurred while trying to parse the input.
-	 * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
+	 * @param args The runtime arguments for the session.
+	 * @return A new parser session.
 	 */
-	public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) throws ParseException, SchemaValidationException;
+	public HttpPartParserSession createSession(ParserSessionArgs args);
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartParserSession.java
similarity index 72%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartParser.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartParserSession.java
index bd70465..880a7dc 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartParserSession.java
@@ -16,29 +16,13 @@ import org.apache.juneau.*;
 import org.apache.juneau.parser.*;
 
 /**
- * Interface used to convert HTTP headers, query parameters, form-data parameters, and URI path variables to POJOs
+ * Session object that lives for the duration of a single use of {@link HttpPartParser}.
  *
  * <p>
- * The following default implementations are provided:
- * <ul class='doctree'>
- * 	<li class='jc'>{@link org.apache.juneau.httppart.OpenApiPartParser} - Parts encoded in based on OpenAPI schema.
- * 	<li class='jc'>{@link org.apache.juneau.httppart.UonPartParser} - Parts encoded in UON notation.
- * 	<li class='jc'>{@link org.apache.juneau.httppart.SimplePartParser} - Parts encoded in plain text.
- * </ul>
- *
- * <p>
- * Implementations must include either a public no-args constructor or a public constructor that takes in a single
- * {@link PropertyStore} object.
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
  */
-public interface HttpPartParser {
-
-	/**
-	 * Represent "no" part parser.
-	 *
-	 * <p>
-	 * Used to represent the absence of a part parser in annotations.
-	 */
-	public static interface Null extends HttpPartParser {}
+public interface HttpPartParserSession {
 
 	/**
 	 * Converts the specified input to the specified class type.
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSerializer.java
index e8c732b..a635cf6 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSerializer.java
@@ -57,21 +57,10 @@ public interface HttpPartSerializer {
 	public static interface Null extends HttpPartSerializer {}
 
 	/**
-	 * Converts the specified value to a string that can be used as an HTTP header value, query parameter value,
-	 * form-data parameter, or URI path variable.
+	 * Creates a new serializer session.
 	 *
-	 * <p>
-	 * Returned values should NOT be URL-encoded.
-	 *
-	 * @param type The category of value being serialized.
-	 * @param schema
-	 * 	Schema information about the part.
-	 * 	<br>May be <jk>null</jk>.
-	 * 	<br>Not all part serializer use the schema information.
-	 * @param value The value being serialized.
-	 * @return The serialized value.
-	 * @throws SerializeException If a problem occurred while trying to parse the input.
-	 * @throws SchemaValidationException If the output fails schema validation.
+	 * @param args The runtime arguments for the session.
+	 * @return A new serializer session.
 	 */
-	public String serialize(HttpPartType type, HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException;
+	public HttpPartSerializerSession createSession(SerializerSessionArgs args);
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSerializerSession.java
similarity index 59%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSerializer.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSerializerSession.java
index e8c732b..5d48665 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartSerializerSession.java
@@ -12,49 +12,16 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.httppart;
 
-import org.apache.juneau.*;
-import org.apache.juneau.http.annotation.*;
-import org.apache.juneau.remoteable.*;
 import org.apache.juneau.serializer.*;
 
 /**
- * Interface used to convert POJOs to simple strings in HTTP headers, query parameters, form-data parameters, and URI
- * path variables.
+ * Session object that lives for the duration of a single use of {@link HttpPartSerializer}.
  *
  * <p>
- * The following default implementations are provided:
- * <ul class='doctree'>
- * 	<li class='jc'>{@link org.apache.juneau.httppart.OpenApiPartSerializer} - Parts encoded based on OpenAPI schema.
- * 	<li class='jc'>{@link org.apache.juneau.httppart.UonPartSerializer} - Parts encoded in UON notation.
- * 	<li class='jc'>{@link org.apache.juneau.httppart.SimpleUonPartSerializer} - Parts encoded in UON notation, but
- * 		strings are treated as plain-text and arrays/collections are serialized as comma-delimited lists.
- * 	<li class='jc'>{@link org.apache.juneau.httppart.SimplePartSerializer} - Parts encoded in plain text.
- * </ul>
- *
- * <p>
- * This class is used in the following locations:
- * <ul>
- * 	<li class='ja'>{@link FormData#serializer()}
- * 	<li class='ja'>{@link Query#serializer()}
- * 	<li class='ja'>{@link Header#serializer()}
- * 	<li class='ja'>{@link Path#serializer()}
- * 	<li class='ja'>{@link RequestBean#serializer()}
- * 	<li class='jc'><code>RestClientBuilder.partSerializer(Class)</code>
- * </ul>
- *
- * <p>
- * Implementations must include either a public no-args constructor or a public constructor that takes in a single
- * {@link PropertyStore} object.
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
  */
-public interface HttpPartSerializer {
-
-	/**
-	 * Represent "no" part part serializer.
-	 *
-	 * <p>
-	 * Used to represent the absence of a part serializer in annotations.
-	 */
-	public static interface Null extends HttpPartSerializer {}
+public interface HttpPartSerializerSession {
 
 	/**
 	 * Converts the specified value to a string that can be used as an HTTP header value, query parameter value,
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartType.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartType.java
index 44f4bbd..a79fbda 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartType.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartType.java
@@ -13,7 +13,7 @@
 package org.apache.juneau.httppart;
 
 /**
- * Represents possible enum values that can be passed to the {@link HttpPartSerializer#serialize(HttpPartType, HttpPartSchema, Object)}.
+ * Represents possible enum values that can be passed to the {@link HttpPartSerializerSession#serialize(HttpPartType, HttpPartSchema, Object)}.
  */
 public enum HttpPartType {
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParser.java
index 2496f1a..fadafcf 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParser.java
@@ -12,16 +12,10 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.httppart;
 
-import static org.apache.juneau.internal.StringUtils.*;
-import static org.apache.juneau.httppart.HttpPartSchema.Type.*;
-import static org.apache.juneau.httppart.HttpPartSchema.Format.*;
-import static org.apache.juneau.httppart.HttpPartSchema.CollectionFormat.*;
-
 import java.io.*;
 import java.util.*;
 
 import org.apache.juneau.*;
-import org.apache.juneau.internal.*;
 import org.apache.juneau.parser.*;
 
 /**
@@ -154,7 +148,6 @@ public class OpenApiPartParser extends UonPartParser {
 	 */
 	public static final String OAPI_schema = PREFIX + "schema.o";
 
-
 	//-------------------------------------------------------------------------------------------------------------------
 	// Predefined instances
 	//-------------------------------------------------------------------------------------------------------------------
@@ -163,23 +156,13 @@ public class OpenApiPartParser extends UonPartParser {
 	public static final OpenApiPartParser DEFAULT = new OpenApiPartParser(PropertyStore.DEFAULT);
 
 	// Cache these for faster lookup
-	private static final BeanContext BC = BeanContext.DEFAULT;
-	private static final ClassMeta<Long> CM_Long = BC.getClassMeta(Long.class);
-	private static final ClassMeta<Integer> CM_Integer = BC.getClassMeta(Integer.class);
-	private static final ClassMeta<Double> CM_Double = BC.getClassMeta(Double.class);
-	private static final ClassMeta<Float> CM_Float = BC.getClassMeta(Float.class);
-	private static final ClassMeta<Boolean> CM_Boolean = BC.getClassMeta(Boolean.class);
-	private static final ClassMeta<ObjectList> CM_ObjectList = BC.getClassMeta(ObjectList.class);
-	private static final ClassMeta<ObjectMap> CM_ObjectMap = BC.getClassMeta(ObjectMap.class);
-
 	private static final HttpPartSchema DEFAULT_SCHEMA = HttpPartSchema.DEFAULT;
 
 	//-------------------------------------------------------------------------------------------------------------------
 	// Instance
 	//-------------------------------------------------------------------------------------------------------------------
-
+	
 	private final HttpPartSchema schema;
-	private final BeanSession bs;
 
 	/**
 	 * Constructor.
@@ -190,7 +173,6 @@ public class OpenApiPartParser extends UonPartParser {
 		super(
 			ps.builder().build()
 		);
-		this.bs = createBeanSession();
 		this.schema = getProperty(OAPI_schema, HttpPartSchema.class, DEFAULT_SCHEMA);
 	}
 
@@ -215,202 +197,32 @@ public class OpenApiPartParser extends UonPartParser {
 		return new UonPartParserBuilder();
 	}
 
-	/**
-	 * Convenience method for parsing a part.
-	 *
-	 * @param schema
-	 * 	Schema information about the part.
-	 * 	<br>May be <jk>null</jk>.
-	 * 	<br>Not all part parsers use the schema information.
-	 * @param in The input being parsed.
-	 * @param type The category of value being parsed.
-	 * @return The parsed value.
-	 * @throws ParseException If a problem occurred while trying to parse the input.
-	 * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
-	 */
-	public <T> T parse(HttpPartSchema schema, String in, Class<T> type) throws ParseException, SchemaValidationException {
-		return parse(null, schema, in, getClassMeta(type));
-	}
+	//-------------------------------------------------------------------------------------------------------------------
+	// Entry point methods
+	//-------------------------------------------------------------------------------------------------------------------
 
-	/**
-	 * Convenience method for parsing a part to a map or collection.
-	 *
-	 * @param schema
-	 * 	Schema information about the part.
-	 * 	<br>May be <jk>null</jk>.
-	 * 	<br>Not all part parsers use the schema information.
-	 * @param in The input being parsed.
-	 * @param type The category of value being parsed.
-	 * @param args The type arguments of the map or collection.
-	 * @return The parsed value.
-	 * @throws ParseException If a problem occurred while trying to parse the input.
-	 * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
-	 */
-	@SuppressWarnings("unchecked")
-	public <T> T parse(HttpPartSchema schema, String in, java.lang.reflect.Type type, java.lang.reflect.Type...args) throws ParseException, SchemaValidationException {
-		return (T)parse(null, schema, in, getClassMeta(type, args));
+	@Override
+	public OpenApiPartParserSession createSession() {
+		return new OpenApiPartParserSession(this, ParserSessionArgs.DEFAULT);
 	}
 
-	@Override /* HttpPartParser */
-	public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) throws ParseException, SchemaValidationException {
-		schema = ObjectUtils.firstNonNull(schema, this.schema, DEFAULT_SCHEMA);
-		T t = parseInner(partType, schema, in, type);
-		if (t == null && type.isPrimitive())
-			t = type.getPrimitiveDefault();
-		schema.validateOutput(t, this);
-		return t;
+	@Override
+	public OpenApiPartParserSession createSession(ParserSessionArgs args) {
+		return new OpenApiPartParserSession(this, args);
 	}
 
-	@SuppressWarnings({ "unchecked" })
-	private<T> T parseInner(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) throws SchemaValidationException, ParseException {
-		schema.validateInput(in);
-		if (in == null) {
-			if (schema.getDefault() == null)
-				return null;
-			in = schema.getDefault();
-		} else {
-			HttpPartSchema.Type t = schema.getType(type);
-			HttpPartSchema.Format f = schema.getFormat();
-
-			if (t == STRING) {
-				if (type.isObject()) {
-					if (f == BYTE)
-						return (T)base64Decode(in);
-					if (f == DATE || f == DATE_TIME)
-						return (T)parseIsoCalendar(in);
-					if (f == BINARY)
-						return (T)fromHex(in);
-					if (f == BINARY_SPACED)
-						return (T)fromSpacedHex(in);
-					if (f == HttpPartSchema.Format.UON)
-						return super.parse(partType, schema, in, type);
-					return (T)in;
-				}
-				if (f == BYTE)
-					return toType(base64Decode(in), type);
-				if (f == DATE || f == DATE_TIME)
-					return toType(parseIsoCalendar(in), type);
-				if (f == BINARY)
-					return toType(fromHex(in), type);
-				if (f == BINARY_SPACED)
-					return toType(fromSpacedHex(in), type);
-				if (f == HttpPartSchema.Format.UON)
-					return super.parse(partType, schema, in, type);
-				return toType(in, type);
-
-			} else if (t == ARRAY) {
-				if (type.isObject())
-					type = (ClassMeta<T>)CM_ObjectList;
-
-				ClassMeta<?> eType = type.isObject() ? string() : type.getElementType();
-				if (eType == null)
-					eType = schema.getParsedType().getElementType();
+	//-----------------------------------------------------------------------------------------------------------------
+	// Properties
+	//-----------------------------------------------------------------------------------------------------------------
 
-				HttpPartSchema.CollectionFormat cf = schema.getCollectionFormat();
-				String[] ss = new String[0];
-
-				if (cf == MULTI)
-					ss = new String[]{in};
-				else if (cf == CSV)
-					ss = split(in, ',');
-				else if (cf == PIPES)
-					ss = split(in, '|');
-				else if (cf == SSV)
-					ss = splitQuoted(in);
-				else if (cf == TSV)
-					ss = split(in, '\t');
-				else if (cf == HttpPartSchema.CollectionFormat.UON)
-					return super.parse(partType, null, in, type);
-				else if (cf == NO_COLLECTION_FORMAT) {
-					if (firstNonWhitespaceChar(in) == '@' && lastNonWhitespaceChar(in) == ')')
-						return super.parse(partType, null, in, type);
-					ss = split(in, ',');
-				}
-
-				Object[] o = null;
-				if (schema.getItems() != null) {
-					o = new Object[ss.length];
-					for (int i = 0; i < ss.length; i++)
-						o[i] = parse(partType, schema.getItems(), ss[i], eType);
-				} else {
-					o = ss;
-				}
-				if (type.hasTransformFrom(schema.getParsedType()) || schema.getParsedType().hasTransformTo(type))
-					return toType(toType(o, schema.getParsedType()), type);
-				return toType(o, type);
-
-			} else if (t == BOOLEAN) {
-				if (type.isObject())
-					type = (ClassMeta<T>)CM_Boolean;
-				if (type.isBoolean())
-					return super.parse(partType, schema, in, type);
-				return toType(super.parse(partType, schema, in, CM_Boolean), type);
-
-			} else if (t == INTEGER) {
-				if (type.isObject()) {
-					if (f == INT64)
-						type = (ClassMeta<T>)CM_Long;
-					else
-						type = (ClassMeta<T>)CM_Integer;
-				}
-				if (type.isNumber())
-					return super.parse(partType, schema, in, type);
-				return toType(super.parse(partType, schema, in, CM_Integer), type);
-
-			} else if (t == NUMBER) {
-				if (type.isObject()) {
-					if (f == DOUBLE)
-						type = (ClassMeta<T>)CM_Double;
-					else
-						type = (ClassMeta<T>)CM_Float;
-				}
-				if (type.isNumber())
-					return super.parse(partType, schema, in, type);
-				return toType(super.parse(partType, schema, in, CM_Integer), type);
-
-			} else if (t == OBJECT) {
-				if (type.isObject())
-					type = (ClassMeta<T>)CM_ObjectMap;
-				if (schema.hasProperties() && type.isMapOrBean()) {
-					try {
-						if (type.isBean()) {
-							BeanMap<T> m = BC.createBeanSession().newBeanMap(type.getInnerClass());
-							for (Map.Entry<String,Object> e : parse(partType, DEFAULT_SCHEMA, in, CM_ObjectMap).entrySet()) {
-								String key = e.getKey();
-								BeanPropertyMeta bpm = m.getPropertyMeta(key);
-								m.put(key, parse(partType, schema.getProperty(key), asString(e.getValue()), bpm == null ? object() : bpm.getClassMeta()));
-							}
-							return m.getBean();
-						}
-						Map<String,Object> m = (Map<String,Object>)type.newInstance();
-						for (Map.Entry<String,Object> e : parse(partType, DEFAULT_SCHEMA, in, CM_ObjectMap).entrySet()) {
-							String key = e.getKey();
-							m.put(key, parse(partType, schema.getProperty(key), asString(e.getValue()), object()));
-						}
-						return (T)m;
-					} catch (Exception e1) {
-						throw new ParseException(e1, "Could not instantiate type ''{0}''.", type);
-					}
-				}
-				return super.parse(partType, schema, in, type);
-
-			} else if (t == FILE) {
-				throw new ParseException("File part not supported.");
-
-			} else if (t == NO_TYPE) {
-				// This should never be returned by HttpPartSchema.getType(ClassMeta).
-				throw new ParseException("Invalid type.");
-			}
-		}
-
-		return super.parse(partType, schema, in, type);
-	}
-
-	private <T> T toType(Object in, ClassMeta<T> type) throws ParseException {
-		try {
-			return bs.convertToType(in, type);
-		} catch (InvalidDataConversionException e) {
-			throw new ParseException(e.getMessage());
-		}
+	/**
+	 * Configuration property:  OpenAPI schema description.
+	 *
+	 * @see #OAPI_schema
+	 * @return
+	 * 	The default part schema on this serializer, or <jk>null</jk> if none is defined.
+	 */
+	protected final HttpPartSchema getSchema() {
+		return schema;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParserSession.java
similarity index 52%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParser.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParserSession.java
index 2496f1a..087a1e8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartParserSession.java
@@ -17,7 +17,6 @@ import static org.apache.juneau.httppart.HttpPartSchema.Type.*;
 import static org.apache.juneau.httppart.HttpPartSchema.Format.*;
 import static org.apache.juneau.httppart.HttpPartSchema.CollectionFormat.*;
 
-import java.io.*;
 import java.util.*;
 
 import org.apache.juneau.*;
@@ -25,142 +24,13 @@ import org.apache.juneau.internal.*;
 import org.apache.juneau.parser.*;
 
 /**
- * OpenAPI part parser.
+ * Session object that lives for the duration of a single use of {@link OpenApiPartParser}.
  *
- * <table class='styled'>
- * 	<tr><th>Type</th><th>Format</th><th>Valid parameter types</th></tr>
- * 	<tr>
- * 		<td ><code>string</code></td>
- * 		<td>
- * 			<code>byte</code>
- * 			<br><code>binary</code>
- * 			<br><code>binary-spaced</br>
- * 		</td>
- * 		<td>
- * 			<ul>
- * 				<li><code><jk>byte</jk>[]</code> (default)
- * 				<li>{@link InputStream} - Returns a {@link ByteArrayInputStream}.
- * 				<li>{@link Reader} - Returns a {@link InputStreamReader} wrapped around a {@link ByteArrayInputStream}.
- * 				<li>{@link String} - Constructed using {@link String#String(byte[])}.
- * 				<li>{@link Object} - Returns the default <code><jk>byte</jk>[]</code>.
- * 				<li>Any POJO transformable from a <code><jk>byte</jk>[]</code> (via constructors, static create methods, or toX() instance methods).
- * 			</ul>
- * 		</td>
- * 	</tr>
- * 	<tr>
- * 		<td ><code>string</code></td>
- * 		<td>
- * 			<code>date</code>
- * 			<code>date-time</code>
- * 		</td>
- * 		<td>
- * 			<ul>
- * 				<li>{@link Calendar} (default)
- * 				<li>{@link Date}
- * 				<li>{@link GregorianCalendar}
- * 				<li>{@link String} - Converted using {@link Calendar#toString()}.
- * 				<li>{@link Object} - Returns the default {@link Calendar}.
- * 				<li>Any POJO transformable from a {@link Calendar} (via constructors, static create methods, or toX() instance methods).
- * 			</ul>
- * 		</td>
- * 	</tr>
- * 	<tr>
- * 		<td ><code>string</code></td>
- * 		<td><code>uon</code></td>
- * 		<td>
- * 			<ul>
- * 				<li>Any <a href='../../../../overview-summary#juneau-marshall.PojoCategories'>parsable POJO</a>.
- * 			</ul>
- * 		</td>
- * 	</tr>
- * 	<tr>
- * 		<td ><code>string</code></td>
- * 		<td>none specified</td>
- * 		<td>
- * 			<ul>
- * 				<li>{@link String} (default)
- * 				<li>{@link Object} - Returns the default {@link String}.
- * 				<li>Any POJO transformable from a {@link String} (via constructors, static create methods, or toX() instance methods).
- * 			</ul>
- * 		</td>
- * 	</tr>
- * 	<tr>
- * 		<td ><code>boolean</code></td>
- * 		<td>
- * 			&nbsp;
- * 		</td>
- * 		<td>
- * 			<ul>
- * 				<li>{@link Boolean} (default)
- * 				<li><jk>boolean</code>
- * 				<li>{@link String}
- * 				<li>{@link Object} - Returns the default {@link Boolean}.
- * 				<li>Any POJO transformable from a {@link Boolean} (via constructors, static create methods, or toX() instance methods).
- * 			</ul>
- * 		</td>
- * 	</tr>
- * 	<tr>
- * 		<td ><code>array</code></td>
- * 		<td>
- * 			&nbsp;
- * 		</td>
- * 		<td>
- * 			<ul>
- * 				<li>Arrays or Collections of anything on this list.
- * 				<li>Any POJO transformable from arrays of the default types (e.g. <code>Integer[]</code>, <code>Boolean[][]</code>, etc...).
- * 			</ul>
- * 		</td>
- * 	</tr>
- * 	<tr>
- * 		<td ><code>object</code></td>
- * 		<td>
- * 			&nbsp;
- * 		</td>
- * 		<td>
- * 			<ul>
- * 				<li>Beans with properties of anything on this list.
- * 				<li>Maps with string keys.
- * 			</ul>
- * 		</td>
- * 	</tr>
- * </table>
+ * <p>
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
  */
-public class OpenApiPartParser extends UonPartParser {
-
-	//-------------------------------------------------------------------------------------------------------------------
-	// Configurable properties
-	//-------------------------------------------------------------------------------------------------------------------
-
-	private static final String PREFIX = "OpenApiPartParser.";
-
-	/**
-	 * Configuration property:  OpenAPI schema description.
-	 *
-	 * <h5 class='section'>Property:</h5>
-	 * <ul>
-	 * 	<li><b>Name:</b>  <js>"OpenApiPartParser.schema"</js>
-	 * 	<li><b>Data type:</b>  <code>HttpPartSchema</code>
-	 * 	<li><b>Default:</b>  <jk>false</jk>
-	 * 	<li><b>Session property:</b>  <jk>false</jk>
-	 * 	<li><b>Methods:</b>
-	 * 		<ul>
-	 * 			<li class='jm'>{@link OpenApiPartParserBuilder#schema(HttpPartSchema)}
-	 * 		</ul>
-	 * </ul>
-	 *
-	 * <h5 class='section'>Description:</h5>
-	 * <p>
-	 * Defines the OpenAPI schema for this part parser.
-	 */
-	public static final String OAPI_schema = PREFIX + "schema.o";
-
-
-	//-------------------------------------------------------------------------------------------------------------------
-	// Predefined instances
-	//-------------------------------------------------------------------------------------------------------------------
-
-	/** Reusable instance of {@link OpenApiPartParser}. */
-	public static final OpenApiPartParser DEFAULT = new OpenApiPartParser(PropertyStore.DEFAULT);
+public class OpenApiPartParserSession extends UonPartParserSession {
 
 	// Cache these for faster lookup
 	private static final BeanContext BC = BeanContext.DEFAULT;
@@ -178,86 +48,30 @@ public class OpenApiPartParser extends UonPartParser {
 	// Instance
 	//-------------------------------------------------------------------------------------------------------------------
 
-	private final HttpPartSchema schema;
-	private final BeanSession bs;
-
-	/**
-	 * Constructor.
-	 *
-	 * @param ps The property store containing all the settings for this object.
-	 */
-	public OpenApiPartParser(PropertyStore ps) {
-		super(
-			ps.builder().build()
-		);
-		this.bs = createBeanSession();
-		this.schema = getProperty(OAPI_schema, HttpPartSchema.class, DEFAULT_SCHEMA);
-	}
-
-	@Override /* Context */
-	public UonPartParserBuilder builder() {
-		return new UonPartParserBuilder(getPropertyStore());
-	}
-
-	/**
-	 * Instantiates a new clean-slate {@link UonPartParserBuilder} object.
-	 *
-	 * <p>
-	 * This is equivalent to simply calling <code><jk>new</jk> UonPartParserBuilder()</code>.
-	 *
-	 * <p>
-	 * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies
-	 * the settings of the object called on.
-	 *
-	 * @return A new {@link UonPartParserBuilder} object.
-	 */
-	public static UonPartParserBuilder create() {
-		return new UonPartParserBuilder();
-	}
+	private final OpenApiPartParser ctx;
 
 	/**
-	 * Convenience method for parsing a part.
+	 * Create a new session using properties specified in the context.
 	 *
-	 * @param schema
-	 * 	Schema information about the part.
-	 * 	<br>May be <jk>null</jk>.
-	 * 	<br>Not all part parsers use the schema information.
-	 * @param in The input being parsed.
-	 * @param type The category of value being parsed.
-	 * @return The parsed value.
-	 * @throws ParseException If a problem occurred while trying to parse the input.
-	 * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
+	 * @param ctx
+	 * 	The context creating this session object.
+	 * 	The context contains all the configuration settings for this object.
+	 * @param args
+	 * 	Runtime session arguments.
 	 */
-	public <T> T parse(HttpPartSchema schema, String in, Class<T> type) throws ParseException, SchemaValidationException {
-		return parse(null, schema, in, getClassMeta(type));
+	protected OpenApiPartParserSession(OpenApiPartParser ctx, ParserSessionArgs args) {
+		super(ctx, args);
+		this.ctx = ctx;
 	}
 
-	/**
-	 * Convenience method for parsing a part to a map or collection.
-	 *
-	 * @param schema
-	 * 	Schema information about the part.
-	 * 	<br>May be <jk>null</jk>.
-	 * 	<br>Not all part parsers use the schema information.
-	 * @param in The input being parsed.
-	 * @param type The category of value being parsed.
-	 * @param args The type arguments of the map or collection.
-	 * @return The parsed value.
-	 * @throws ParseException If a problem occurred while trying to parse the input.
-	 * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
-	 */
-	@SuppressWarnings("unchecked")
-	public <T> T parse(HttpPartSchema schema, String in, java.lang.reflect.Type type, java.lang.reflect.Type...args) throws ParseException, SchemaValidationException {
-		return (T)parse(null, schema, in, getClassMeta(type, args));
-	}
 
 	@Override /* HttpPartParser */
 	public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) throws ParseException, SchemaValidationException {
-		schema = ObjectUtils.firstNonNull(schema, this.schema, DEFAULT_SCHEMA);
+		schema = ObjectUtils.firstNonNull(schema, ctx.getSchema(), DEFAULT_SCHEMA);
 		T t = parseInner(partType, schema, in, type);
 		if (t == null && type.isPrimitive())
 			t = type.getPrimitiveDefault();
-		schema.validateOutput(t, this);
+		schema.validateOutput(t, ctx);
 		return t;
 	}
 
@@ -408,7 +222,7 @@ public class OpenApiPartParser extends UonPartParser {
 
 	private <T> T toType(Object in, ClassMeta<T> type) throws ParseException {
 		try {
-			return bs.convertToType(in, type);
+			return convertToType(in, type);
 		} catch (InvalidDataConversionException e) {
 			throw new ParseException(e.getMessage());
 		}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
index 6344926..ba5ae38 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
@@ -12,16 +12,7 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.httppart;
 
-import static org.apache.juneau.httppart.HttpPartSchema.CollectionFormat.*;
-import static org.apache.juneau.httppart.HttpPartSchema.Format.*;
-import static org.apache.juneau.httppart.HttpPartSchema.Type.*;
-import static org.apache.juneau.internal.StringUtils.*;
-
-import java.lang.reflect.*;
-import java.util.*;
-
 import org.apache.juneau.*;
-import org.apache.juneau.internal.*;
 import org.apache.juneau.serializer.*;
 
 /**
@@ -50,7 +41,7 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 	 * 	<li><b>Session property:</b>  <jk>false</jk>
 	 * 	<li><b>Methods:</b>
 	 * 		<ul>
-	 * 			<li class='jm'>{@link OpenPartSerializerBuilder#schema(HttpPartSchema)}
+	 * 			<li class='jm'>{@link OpenApiPartSerializerBuilder#schema(HttpPartSchema)}
 	 * 		</ul>
 	 * </ul>
 	 *
@@ -68,24 +59,12 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 	/** Reusable instance of {@link OpenApiPartSerializer}, all default settings. */
 	public static final OpenApiPartSerializer DEFAULT = new OpenApiPartSerializer(PropertyStore.DEFAULT);
 
-	// Cache these for faster lookup
-	private static final BeanContext BC = BeanContext.DEFAULT;
-	private static final ClassMeta<byte[]> CM_ByteArray = BC.getClassMeta(byte[].class);
-	private static final ClassMeta<Calendar> CM_Calendar = BC.getClassMeta(Calendar.class);
-	private static final ClassMeta<Long> CM_Long = BC.getClassMeta(Long.class);
-	private static final ClassMeta<Integer> CM_Integer = BC.getClassMeta(Integer.class);
-	private static final ClassMeta<Double> CM_Double = BC.getClassMeta(Double.class);
-	private static final ClassMeta<Float> CM_Float = BC.getClassMeta(Float.class);
-	private static final ClassMeta<Boolean> CM_Boolean = BC.getClassMeta(Boolean.class);
-
-	private static final HttpPartSchema DEFAULT_SCHEMA = HttpPartSchema.DEFAULT;
 
 	//-------------------------------------------------------------------------------------------------------------------
 	// Instance
 	//-------------------------------------------------------------------------------------------------------------------
 
 	final HttpPartSchema schema;
-	final BeanSession bs;
 
 	/**
 	 * Constructor.
@@ -99,13 +78,12 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 				.set(UON_encoding, false)
 				.build()
 		);
-		this.bs = createBeanSession();
 		this.schema = getProperty(OAPI_schema, HttpPartSchema.class, HttpPartSchema.DEFAULT);
 	}
 
 	@Override /* Context */
-	public UonPartSerializerBuilder builder() {
-		return new UonPartSerializerBuilder(getPropertyStore());
+	public OpenApiPartSerializerBuilder builder() {
+		return new OpenApiPartSerializerBuilder(getPropertyStore());
 	}
 
 	/**
@@ -117,238 +95,36 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 	 *
 	 * @return A new {@link UonPartSerializerBuilder} object.
 	 */
-	public static UonPartSerializerBuilder create() {
-		return new UonPartSerializerBuilder();
+	public static OpenApiPartSerializerBuilder create() {
+		return new OpenApiPartSerializerBuilder();
 	}
 
-	//--------------------------------------------------------------------------------
+	//-----------------------------------------------------------------------------------------------------------------
 	// Entry point methods
-	//--------------------------------------------------------------------------------
-
-	/**
-	 * Convenience method for serializing a part.
-	 *
-	 * @param schema
-	 * 	Schema information about the part.
-	 * 	<br>May be <jk>null</jk>.
-	 * 	<br>Not all part serializers use the schema information.
-	 * @param value The value being serialized.
-	 * @return The serialized value.
-	 * @throws SerializeException If a problem occurred while trying to serialize the input.
-	 * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
-	 */
-	public String serialize(HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException {
-		return serialize(null, schema, value);
-	}
-
-	@Override /* PartSerializer */
-	public String serialize(HttpPartType partType, HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException {
-
-		schema = ObjectUtils.firstNonNull(schema, this.schema, DEFAULT_SCHEMA);
-		ClassMeta<?> type = getClassMetaForObject(value);
-		if (type == null)
-			type = object();
-		HttpPartSchema.Type t = schema.getType(type);
-		HttpPartSchema.Format f = schema.getFormat();
-		HttpPartSchema.CollectionFormat cf = schema.getCollectionFormat();
-
-		String out = null;
-
-		schema.validateOutput(value, this);
-
-		if (type.hasTransformTo(schema.getParsedType()) || schema.getParsedType().hasTransformFrom(type)) {
-			value = toType(value, schema.getParsedType());
-			type = schema.getParsedType();
-		}
-
-		if (value != null) {
-
-			if (t == STRING) {
-
-				if (f == BYTE)
-					out = base64Encode(toType(value, CM_ByteArray));
-				else if (f == BINARY)
-					out = toHex(toType(value, CM_ByteArray));
-				else if (f == BINARY_SPACED)
-					out = toSpacedHex(toType(value, CM_ByteArray));
-				else if (f == DATE)
-					out = toIsoDate(toType(value, CM_Calendar));
-				else if (f == DATE_TIME)
-					out = toIsoDateTime(toType(value, CM_Calendar));
-				else if (f == HttpPartSchema.Format.UON)
-					out = super.serialize(partType, schema, value);
-				else
-					out = toType(value, string());
-
-			} else if (t == ARRAY) {
-
-				if (f == HttpPartSchema.Format.UON)
-					out = super.serialize(partType, null, toList(partType, type, value, schema));
-				else {
-					List<String> l = new ArrayList<>();
-
-					HttpPartSchema items = schema.getItems();
-					ClassMeta<?> vt = getClassMetaForObject(value);
-
-					if (type.isArray()) {
-						for (int i = 0; i < Array.getLength(value); i++)
-							l.add(serialize(partType, items, Array.get(value, i)));
-					} else if (type.isCollection()) {
-						for (Object o : (Collection<?>)value)
-							l.add(serialize(partType, items, o));
-					} else if (vt.hasTransformTo(String[].class)) {
-						l.add(serialize(partType, items, value));
-					}
+	//-----------------------------------------------------------------------------------------------------------------
 
-					if (cf == PIPES)
-						out = joine(l, '|');
-					else if (cf == SSV)
-						out = join(l, ' ');
-					else if (cf == TSV)
-						out = join(l, '\t');
-					else
-						out = joine(l, ',');
-				}
-
-			} else if (t == BOOLEAN) {
-
-				if (f == HttpPartSchema.Format.UON)
-					out = super.serialize(partType, null, value);
-				else
-					out = asString(toType(value, CM_Boolean));
-
-			} else if (t == INTEGER) {
-
-				if (f == HttpPartSchema.Format.UON)
-					out = super.serialize(partType, null, value);
-				else if (f == INT64)
-					out = asString(toType(value, CM_Long));
-				else
-					out = asString(toType(value, CM_Integer));
-
-			} else if (t == NUMBER) {
-
-				if (f == HttpPartSchema.Format.UON)
-					out = super.serialize(partType, null, value);
-				else if (f == DOUBLE)
-					out = asString(toType(value, CM_Double));
-				else
-					out = asString(toType(value, CM_Float));
-
-			} else if (t == OBJECT) {
-
-				if (f == HttpPartSchema.Format.UON) {
-					out = super.serialize(partType, null, value);
-				} else if (schema.hasProperties() && type.isMapOrBean()) {
-					out = super.serialize(partType, null, toMap(partType, type, value, schema));
-				} else {
-					out = super.serialize(partType, null, value);
-				}
-
-			} else if (t == FILE) {
-				throw new SerializeException("File part not supported.");
-
-			} else if (t == NO_TYPE) {
-				// This should never be returned by HttpPartSchema.getType(ClassMeta).
-				throw new SerializeException("Invalid type.");
-			}
-		}
-
-		schema.validateInput(out);
-		if (out == null)
-			out = schema.getDefault();
-		if (out == null)
-			out = "null";
-		return out;
-	}
-
-	@SuppressWarnings("rawtypes")
-	private Map toMap(HttpPartType partType, ClassMeta<?> type, Object o, HttpPartSchema s) throws SerializeException, SchemaValidationException {
-		if (s == null)
-			s = DEFAULT_SCHEMA;
-		ObjectMap m = new ObjectMap();
-		if (type.isBean()) {
-			for (BeanPropertyValue p : bs.toBeanMap(o).getValues(isTrimNullProperties())) {
-				if (p.getMeta().canRead()) {
-					Throwable t = p.getThrown();
-					if (t == null)
-						m.put(p.getName(), toObject(partType, p.getValue(), s.getProperty(p.getName())));
-				}
-			}
-		} else {
-			for (Map.Entry e : (Set<Map.Entry>)((Map)o).entrySet())
-				m.put(asString(e.getKey()), toObject(partType, e.getValue(), s.getProperty(asString(e.getKey()))));
-		}
-		if (isSortMaps())
-			return createSession().sort(m);
-		return m;
+	@Override
+	public OpenApiPartSerializerSession createSession(SerializerSessionArgs args) {
+		return new OpenApiPartSerializerSession(this, args);
 	}
 
-	@SuppressWarnings("rawtypes")
-	private Collection toList(HttpPartType partType, ClassMeta<?> type, Object o, HttpPartSchema s) throws SerializeException, SchemaValidationException {
-		if (s == null)
-			s = DEFAULT_SCHEMA;
-		ObjectList l = new ObjectList();
-		HttpPartSchema items = s.getItems();
-		if (type.isArray()) {
-			for (int i = 0; i < Array.getLength(o); i++)
-				l.add(toObject(partType, Array.get(o, i), items));
-		} else if (type.isCollection()) {
-			for (Object o2 : (Collection<?>)o)
-				l.add(toObject(partType, o2, items));
-		} else {
-			l.add(toObject(partType, o, items));
-		}
-		if (isSortCollections())
-			return createSession().sort(l);
-		return l;
+	@Override
+	public OpenApiPartSerializerSession createSession() {
+		return new OpenApiPartSerializerSession(this, SerializerSessionArgs.DEFAULT);
 	}
 
-	@SuppressWarnings("rawtypes")
-	private Object toObject(HttpPartType partType, Object o, HttpPartSchema s) throws SerializeException, SchemaValidationException {
-		if (o == null)
-			return null;
-		if (s == null)
-			s = DEFAULT_SCHEMA;
-		HttpPartSchema.Type t = s.getType();
-		HttpPartSchema.Format f = s.getFormat();
-		HttpPartSchema.CollectionFormat cf = s.getCollectionFormat();
-
-		if (t == STRING) {
-			if (f == BYTE)
-				return base64Encode(toType(o, CM_ByteArray));
-			if (f == BINARY)
-				return toHex(toType(o, CM_ByteArray));
-			if (f == BINARY_SPACED)
-				return toSpacedHex(toType(o, CM_ByteArray));
-			if (f == DATE)
-				return toIsoDate(toType(o, CM_Calendar));
-			if (f == DATE_TIME)
-				return toIsoDateTime(toType(o, CM_Calendar));
-			return o;
-		} else if (t == ARRAY) {
-			Collection l = toList(partType, getClassMetaForObject(o), o, s);
-			if (cf == CSV)
-				return joine(l, ',');
-			if (cf == PIPES)
-				return joine(l, '|');
-			if (cf == SSV)
-				return join(l, ' ');
-			if (cf == TSV)
-				return join(l, '\t');
-			return l;
-		} else if (t == OBJECT) {
-			return toMap(partType, getClassMetaForObject(o), o, s);
-		}
-
-		return o;
-	}
+	//-----------------------------------------------------------------------------------------------------------------
+	// Properties
+	//-----------------------------------------------------------------------------------------------------------------
 
-	private <T> T toType(Object in, ClassMeta<T> type) throws SerializeException {
-		try {
-			return bs.convertToType(in, type);
-		} catch (InvalidDataConversionException e) {
-			throw new SerializeException(e.getMessage());
-		}
+	/**
+	 * Configuration property:  OpenAPI schema description.
+	 *
+	 * @see #OAPI_schema
+	 * @return
+	 * 	The default part schema on this serializer, or <jk>null</jk> if none is defined.
+	 */
+	protected final HttpPartSchema getSchema() {
+		return schema;
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializerBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializerBuilder.java
index 1cba386..87cbd91 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializerBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializerBuilder.java
@@ -25,12 +25,12 @@ import org.apache.juneau.urlencoding.*;
 /**
  * Builder class for building instances of {@link UonPartSerializer}.
  */
-public class OpenPartSerializerBuilder extends UonPartSerializerBuilder {
+public class OpenApiPartSerializerBuilder extends UonPartSerializerBuilder {
 
 	/**
 	 * Constructor, default settings.
 	 */
-	public OpenPartSerializerBuilder() {
+	public OpenApiPartSerializerBuilder() {
 		super();
 	}
 
@@ -39,7 +39,7 @@ public class OpenPartSerializerBuilder extends UonPartSerializerBuilder {
 	 *
 	 * @param ps The initial configuration settings for this builder.
 	 */
-	public OpenPartSerializerBuilder(PropertyStore ps) {
+	public OpenApiPartSerializerBuilder(PropertyStore ps) {
 		super(ps);
 	}
 
@@ -70,569 +70,569 @@ public class OpenPartSerializerBuilder extends UonPartSerializerBuilder {
 	 * 	<br>Default is <jk>false</jk> for {@link UonParser}, <jk>true</jk> for {@link UrlEncodingParser}
 	 * @return This object (for method chaining).
 	 */
-	public OpenPartSerializerBuilder schema(HttpPartSchema value) {
+	public OpenApiPartSerializerBuilder schema(HttpPartSchema value) {
 		return set(OAPI_schema, value);
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder addBeanTypes(boolean value) {
+	public OpenApiPartSerializerBuilder addBeanTypes(boolean value) {
 		super.addBeanTypes(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder addBeanTypes() {
+	public OpenApiPartSerializerBuilder addBeanTypes() {
 		super.addBeanTypes();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder addRootType(boolean value) {
+	public OpenApiPartSerializerBuilder addRootType(boolean value) {
 		super.addRootType(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder addRootType() {
+	public OpenApiPartSerializerBuilder addRootType() {
 		super.addRootType();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder detectRecursions(boolean value) {
+	public OpenApiPartSerializerBuilder detectRecursions(boolean value) {
 		super.detectRecursions(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder detectRecursions() {
+	public OpenApiPartSerializerBuilder detectRecursions() {
 		super.detectRecursions();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder ignoreRecursions(boolean value) {
+	public OpenApiPartSerializerBuilder ignoreRecursions(boolean value) {
 		super.ignoreRecursions(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder ignoreRecursions() {
+	public OpenApiPartSerializerBuilder ignoreRecursions() {
 		super.ignoreRecursions();
 		return this;
 	}
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder initialDepth(int value) {
+	public OpenApiPartSerializerBuilder initialDepth(int value) {
 		super.initialDepth(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder listener(Class<? extends SerializerListener> value) {
+	public OpenApiPartSerializerBuilder listener(Class<? extends SerializerListener> value) {
 		super.listener(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder maxDepth(int value) {
+	public OpenApiPartSerializerBuilder maxDepth(int value) {
 		super.maxDepth(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder maxIndent(int value) {
+	public OpenApiPartSerializerBuilder maxIndent(int value) {
 		super.maxIndent(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder quoteChar(char value) {
+	public OpenApiPartSerializerBuilder quoteChar(char value) {
 		super.quoteChar(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder sortCollections(boolean value) {
+	public OpenApiPartSerializerBuilder sortCollections(boolean value) {
 		super.sortCollections(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder sortCollections() {
+	public OpenApiPartSerializerBuilder sortCollections() {
 		super.sortCollections();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder sortMaps(boolean value) {
+	public OpenApiPartSerializerBuilder sortMaps(boolean value) {
 		super.sortMaps(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder sortMaps() {
+	public OpenApiPartSerializerBuilder sortMaps() {
 		super.sortMaps();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder sq() {
+	public OpenApiPartSerializerBuilder sq() {
 		super.sq();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder trimEmptyCollections(boolean value) {
+	public OpenApiPartSerializerBuilder trimEmptyCollections(boolean value) {
 		super.trimEmptyCollections(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder trimEmptyCollections() {
+	public OpenApiPartSerializerBuilder trimEmptyCollections() {
 		super.trimEmptyCollections();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder trimEmptyMaps(boolean value) {
+	public OpenApiPartSerializerBuilder trimEmptyMaps(boolean value) {
 		super.trimEmptyMaps(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder trimEmptyMaps() {
+	public OpenApiPartSerializerBuilder trimEmptyMaps() {
 		super.trimEmptyMaps();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder trimNullProperties(boolean value) {
+	public OpenApiPartSerializerBuilder trimNullProperties(boolean value) {
 		super.trimNullProperties(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder trimStrings(boolean value) {
+	public OpenApiPartSerializerBuilder trimStrings(boolean value) {
 		super.trimStrings(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder trimStrings() {
+	public OpenApiPartSerializerBuilder trimStrings() {
 		super.trimStrings();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder uriContext(UriContext value) {
+	public OpenApiPartSerializerBuilder uriContext(UriContext value) {
 		super.uriContext(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder uriRelativity(UriRelativity value) {
+	public OpenApiPartSerializerBuilder uriRelativity(UriRelativity value) {
 		super.uriRelativity(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder uriResolution(UriResolution value) {
+	public OpenApiPartSerializerBuilder uriResolution(UriResolution value) {
 		super.uriResolution(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder useWhitespace(boolean value) {
+	public OpenApiPartSerializerBuilder useWhitespace(boolean value) {
 		super.useWhitespace(value);
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder useWhitespace() {
+	public OpenApiPartSerializerBuilder useWhitespace() {
 		super.useWhitespace();
 		return this;
 	}
 
 	@Override /* SerializerBuilder */
-	public OpenPartSerializerBuilder ws() {
+	public OpenApiPartSerializerBuilder ws() {
 		super.ws();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanClassVisibility(Visibility value) {
+	public OpenApiPartSerializerBuilder beanClassVisibility(Visibility value) {
 		super.beanClassVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanConstructorVisibility(Visibility value) {
+	public OpenApiPartSerializerBuilder beanConstructorVisibility(Visibility value) {
 		super.beanConstructorVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanDictionary(boolean append, Object...values) {
+	public OpenApiPartSerializerBuilder beanDictionary(boolean append, Object...values) {
 		super.beanDictionary(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanDictionary(Class<?>...values) {
+	public OpenApiPartSerializerBuilder beanDictionary(Class<?>...values) {
 		super.beanDictionary(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanDictionary(Object...values) {
+	public OpenApiPartSerializerBuilder beanDictionary(Object...values) {
 		super.beanDictionary(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanDictionaryRemove(Object...values) {
+	public OpenApiPartSerializerBuilder beanDictionaryRemove(Object...values) {
 		super.beanDictionaryRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanFieldVisibility(Visibility value) {
+	public OpenApiPartSerializerBuilder beanFieldVisibility(Visibility value) {
 		super.beanFieldVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanFilters(boolean append, Object...values) {
+	public OpenApiPartSerializerBuilder beanFilters(boolean append, Object...values) {
 		super.beanFilters(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanFilters(Class<?>...values) {
+	public OpenApiPartSerializerBuilder beanFilters(Class<?>...values) {
 		super.beanFilters(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanFilters(Object...values) {
+	public OpenApiPartSerializerBuilder beanFilters(Object...values) {
 		super.beanFilters(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanFiltersRemove(Object...values) {
+	public OpenApiPartSerializerBuilder beanFiltersRemove(Object...values) {
 		super.beanFiltersRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanMapPutReturnsOldValue(boolean value) {
+	public OpenApiPartSerializerBuilder beanMapPutReturnsOldValue(boolean value) {
 		super.beanMapPutReturnsOldValue(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanMapPutReturnsOldValue() {
+	public OpenApiPartSerializerBuilder beanMapPutReturnsOldValue() {
 		super.beanMapPutReturnsOldValue();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanMethodVisibility(Visibility value) {
+	public OpenApiPartSerializerBuilder beanMethodVisibility(Visibility value) {
 		super.beanMethodVisibility(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beansRequireDefaultConstructor(boolean value) {
+	public OpenApiPartSerializerBuilder beansRequireDefaultConstructor(boolean value) {
 		super.beansRequireDefaultConstructor(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beansRequireDefaultConstructor() {
+	public OpenApiPartSerializerBuilder beansRequireDefaultConstructor() {
 		super.beansRequireDefaultConstructor();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beansRequireSerializable(boolean value) {
+	public OpenApiPartSerializerBuilder beansRequireSerializable(boolean value) {
 		super.beansRequireSerializable(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beansRequireSerializable() {
+	public OpenApiPartSerializerBuilder beansRequireSerializable() {
 		super.beansRequireSerializable();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beansRequireSettersForGetters(boolean value) {
+	public OpenApiPartSerializerBuilder beansRequireSettersForGetters(boolean value) {
 		super.beansRequireSettersForGetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beansRequireSettersForGetters() {
+	public OpenApiPartSerializerBuilder beansRequireSettersForGetters() {
 		super.beansRequireSettersForGetters();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beansRequireSomeProperties(boolean value) {
+	public OpenApiPartSerializerBuilder beansRequireSomeProperties(boolean value) {
 		super.beansRequireSomeProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder beanTypePropertyName(String value) {
+	public OpenApiPartSerializerBuilder beanTypePropertyName(String value) {
 		super.beanTypePropertyName(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder debug() {
+	public OpenApiPartSerializerBuilder debug() {
 		super.debug();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public <T> OpenPartSerializerBuilder example(Class<T> c, T o) {
+	public <T> OpenApiPartSerializerBuilder example(Class<T> c, T o) {
 		super.example(c, o);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder ignoreInvocationExceptionsOnGetters(boolean value) {
+	public OpenApiPartSerializerBuilder ignoreInvocationExceptionsOnGetters(boolean value) {
 		super.ignoreInvocationExceptionsOnGetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder ignoreInvocationExceptionsOnGetters() {
+	public OpenApiPartSerializerBuilder ignoreInvocationExceptionsOnGetters() {
 		super.ignoreInvocationExceptionsOnGetters();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder ignoreInvocationExceptionsOnSetters(boolean value) {
+	public OpenApiPartSerializerBuilder ignoreInvocationExceptionsOnSetters(boolean value) {
 		super.ignoreInvocationExceptionsOnSetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder ignoreInvocationExceptionsOnSetters() {
+	public OpenApiPartSerializerBuilder ignoreInvocationExceptionsOnSetters() {
 		super.ignoreInvocationExceptionsOnSetters();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder ignorePropertiesWithoutSetters(boolean value) {
+	public OpenApiPartSerializerBuilder ignorePropertiesWithoutSetters(boolean value) {
 		super.ignorePropertiesWithoutSetters(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder ignoreUnknownBeanProperties(boolean value) {
+	public OpenApiPartSerializerBuilder ignoreUnknownBeanProperties(boolean value) {
 		super.ignoreUnknownBeanProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder ignoreUnknownBeanProperties() {
+	public OpenApiPartSerializerBuilder ignoreUnknownBeanProperties() {
 		super.ignoreUnknownBeanProperties();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder ignoreUnknownNullBeanProperties(boolean value) {
+	public OpenApiPartSerializerBuilder ignoreUnknownNullBeanProperties(boolean value) {
 		super.ignoreUnknownNullBeanProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public <T> OpenPartSerializerBuilder implClass(Class<T> interfaceClass, Class<? extends T> implClass) {
+	public <T> OpenApiPartSerializerBuilder implClass(Class<T> interfaceClass, Class<? extends T> implClass) {
 		super.implClass(interfaceClass, implClass);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder implClasses(Map<String,Class<?>> values) {
+	public OpenApiPartSerializerBuilder implClasses(Map<String,Class<?>> values) {
 		super.implClasses(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder locale(Locale value) {
+	public OpenApiPartSerializerBuilder locale(Locale value) {
 		super.locale(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder mediaType(MediaType value) {
+	public OpenApiPartSerializerBuilder mediaType(MediaType value) {
 		super.mediaType(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder notBeanClasses(boolean append, Object...values) {
+	public OpenApiPartSerializerBuilder notBeanClasses(boolean append, Object...values) {
 		super.notBeanClasses(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder notBeanClasses(Class<?>...values) {
+	public OpenApiPartSerializerBuilder notBeanClasses(Class<?>...values) {
 		super.notBeanClasses(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder notBeanClasses(Object...values) {
+	public OpenApiPartSerializerBuilder notBeanClasses(Object...values) {
 		super.notBeanClasses(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder notBeanClassesRemove(Object...values) {
+	public OpenApiPartSerializerBuilder notBeanClassesRemove(Object...values) {
 		super.notBeanClassesRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder notBeanPackages(boolean append, Object...values) {
+	public OpenApiPartSerializerBuilder notBeanPackages(boolean append, Object...values) {
 		super.notBeanPackages(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder notBeanPackages(Object...values) {
+	public OpenApiPartSerializerBuilder notBeanPackages(Object...values) {
 		super.notBeanPackages(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder notBeanPackages(String...values) {
+	public OpenApiPartSerializerBuilder notBeanPackages(String...values) {
 		super.notBeanPackages(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder notBeanPackagesRemove(Object...values) {
+	public OpenApiPartSerializerBuilder notBeanPackagesRemove(Object...values) {
 		super.notBeanPackagesRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder pojoSwaps(boolean append, Object...values) {
+	public OpenApiPartSerializerBuilder pojoSwaps(boolean append, Object...values) {
 		super.pojoSwaps(append, values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder pojoSwaps(Class<?>...values) {
+	public OpenApiPartSerializerBuilder pojoSwaps(Class<?>...values) {
 		super.pojoSwaps(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder pojoSwaps(Object...values) {
+	public OpenApiPartSerializerBuilder pojoSwaps(Object...values) {
 		super.pojoSwaps(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder pojoSwapsRemove(Object...values) {
+	public OpenApiPartSerializerBuilder pojoSwapsRemove(Object...values) {
 		super.pojoSwapsRemove(values);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder sortProperties(boolean value) {
+	public OpenApiPartSerializerBuilder sortProperties(boolean value) {
 		super.sortProperties(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder sortProperties() {
+	public OpenApiPartSerializerBuilder sortProperties() {
 		super.sortProperties();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder timeZone(TimeZone value) {
+	public OpenApiPartSerializerBuilder timeZone(TimeZone value) {
 		super.timeZone(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder useEnumNames() {
+	public OpenApiPartSerializerBuilder useEnumNames() {
 		super.useEnumNames();
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder useInterfaceProxies(boolean value) {
+	public OpenApiPartSerializerBuilder useInterfaceProxies(boolean value) {
 		super.useInterfaceProxies(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder useJavaBeanIntrospector(boolean value) {
+	public OpenApiPartSerializerBuilder useJavaBeanIntrospector(boolean value) {
 		super.useJavaBeanIntrospector(value);
 		return this;
 	}
 
 	@Override /* BeanContextBuilder */
-	public OpenPartSerializerBuilder useJavaBeanIntrospector() {
+	public OpenApiPartSerializerBuilder useJavaBeanIntrospector() {
 		super.useJavaBeanIntrospector();
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public OpenPartSerializerBuilder set(String name, Object value) {
+	public OpenApiPartSerializerBuilder set(String name, Object value) {
 		super.set(name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public OpenPartSerializerBuilder set(boolean append, String name, Object value) {
+	public OpenApiPartSerializerBuilder set(boolean append, String name, Object value) {
 		super.set(append, name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public OpenPartSerializerBuilder set(Map<String,Object> properties) {
+	public OpenApiPartSerializerBuilder set(Map<String,Object> properties) {
 		super.set(properties);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public OpenPartSerializerBuilder add(Map<String,Object> properties) {
+	public OpenApiPartSerializerBuilder add(Map<String,Object> properties) {
 		super.add(properties);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public OpenPartSerializerBuilder addTo(String name, Object value) {
+	public OpenApiPartSerializerBuilder addTo(String name, Object value) {
 		super.addTo(name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public OpenPartSerializerBuilder addTo(String name, String key, Object value) {
+	public OpenApiPartSerializerBuilder addTo(String name, String key, Object value) {
 		super.addTo(name, key, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public OpenPartSerializerBuilder removeFrom(String name, Object value) {
+	public OpenApiPartSerializerBuilder removeFrom(String name, Object value) {
 		super.removeFrom(name, value);
 		return this;
 	}
 
 	@Override /* ContextBuilder */
-	public OpenPartSerializerBuilder apply(PropertyStore copyFrom) {
+	public OpenApiPartSerializerBuilder apply(PropertyStore copyFrom) {
 		super.apply(copyFrom);
 		return this;
 	}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializerSession.java
similarity index 83%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializerSession.java
index 6344926..0b1c473 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/OpenApiPartSerializerSession.java
@@ -25,13 +25,13 @@ import org.apache.juneau.internal.*;
 import org.apache.juneau.serializer.*;
 
 /**
- * Serializes POJOs to values suitable for transmission as HTTP headers, query/form-data parameters, and path variables.
+ * Session object that lives for the duration of a single use of {@link OpenApiPartSerializer}.
  *
  * <p>
- * This serializer uses UON notation for all parts by default.  This allows for arbitrary POJOs to be losslessly
- * serialized as any of the specified HTTP types.
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
  */
-public class OpenApiPartSerializer extends UonPartSerializer {
+public class OpenApiPartSerializerSession extends UonPartSerializerSession {
 
 	//-------------------------------------------------------------------------------------------------------------------
 	// Configurable properties
@@ -50,7 +50,7 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 	 * 	<li><b>Session property:</b>  <jk>false</jk>
 	 * 	<li><b>Methods:</b>
 	 * 		<ul>
-	 * 			<li class='jm'>{@link OpenPartSerializerBuilder#schema(HttpPartSchema)}
+	 * 			<li class='jm'>{@link OpenApiPartSerializerBuilder#schema(HttpPartSchema)}
 	 * 		</ul>
 	 * </ul>
 	 *
@@ -65,9 +65,6 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 	// Predefined instances
 	//-------------------------------------------------------------------------------------------------------------------
 
-	/** Reusable instance of {@link OpenApiPartSerializer}, all default settings. */
-	public static final OpenApiPartSerializer DEFAULT = new OpenApiPartSerializer(PropertyStore.DEFAULT);
-
 	// Cache these for faster lookup
 	private static final BeanContext BC = BeanContext.DEFAULT;
 	private static final ClassMeta<byte[]> CM_ByteArray = BC.getClassMeta(byte[].class);
@@ -84,41 +81,20 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 	// Instance
 	//-------------------------------------------------------------------------------------------------------------------
 
-	final HttpPartSchema schema;
-	final BeanSession bs;
-
-	/**
-	 * Constructor.
-	 *
-	 * @param ps
-	 * 	The property store containing all the settings for this object.
-	 */
-	public OpenApiPartSerializer(PropertyStore ps) {
-		super(
-			ps.builder()
-				.set(UON_encoding, false)
-				.build()
-		);
-		this.bs = createBeanSession();
-		this.schema = getProperty(OAPI_schema, HttpPartSchema.class, HttpPartSchema.DEFAULT);
-	}
-
-	@Override /* Context */
-	public UonPartSerializerBuilder builder() {
-		return new UonPartSerializerBuilder(getPropertyStore());
-	}
+	private final OpenApiPartSerializer ctx;
 
 	/**
-	 * Instantiates a new clean-slate {@link UonPartSerializerBuilder} object.
-	 *
-	 * <p>
-	 * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies
-	 * the settings of the object called on.
+	 * Create a new session using properties specified in the context.
 	 *
-	 * @return A new {@link UonPartSerializerBuilder} object.
+	 * @param ctx
+	 * 	The context creating this session object.
+	 * 	The context contains all the configuration settings for this object.
+	 * @param args
+	 * 	Runtime session arguments.
 	 */
-	public static UonPartSerializerBuilder create() {
-		return new UonPartSerializerBuilder();
+	protected OpenApiPartSerializerSession(OpenApiPartSerializer ctx, SerializerSessionArgs args) {
+		super(ctx, args);
+		this.ctx = ctx;
 	}
 
 	//--------------------------------------------------------------------------------
@@ -144,7 +120,7 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 	@Override /* PartSerializer */
 	public String serialize(HttpPartType partType, HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException {
 
-		schema = ObjectUtils.firstNonNull(schema, this.schema, DEFAULT_SCHEMA);
+		schema = ObjectUtils.firstNonNull(schema, ctx.getSchema(), DEFAULT_SCHEMA);
 		ClassMeta<?> type = getClassMetaForObject(value);
 		if (type == null)
 			type = object();
@@ -154,7 +130,7 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 
 		String out = null;
 
-		schema.validateOutput(value, this);
+		schema.validateOutput(value, ctx);
 
 		if (type.hasTransformTo(schema.getParsedType()) || schema.getParsedType().hasTransformFrom(type)) {
 			value = toType(value, schema.getParsedType());
@@ -268,7 +244,7 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 			s = DEFAULT_SCHEMA;
 		ObjectMap m = new ObjectMap();
 		if (type.isBean()) {
-			for (BeanPropertyValue p : bs.toBeanMap(o).getValues(isTrimNullProperties())) {
+			for (BeanPropertyValue p : toBeanMap(o).getValues(isTrimNullProperties())) {
 				if (p.getMeta().canRead()) {
 					Throwable t = p.getThrown();
 					if (t == null)
@@ -280,7 +256,7 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 				m.put(asString(e.getKey()), toObject(partType, e.getValue(), s.getProperty(asString(e.getKey()))));
 		}
 		if (isSortMaps())
-			return createSession().sort(m);
+			return sort(m);
 		return m;
 	}
 
@@ -300,7 +276,7 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 			l.add(toObject(partType, o, items));
 		}
 		if (isSortCollections())
-			return createSession().sort(l);
+			return sort(l);
 		return l;
 	}
 
@@ -346,7 +322,7 @@ public class OpenApiPartSerializer extends UonPartSerializer {
 
 	private <T> T toType(Object in, ClassMeta<T> type) throws SerializeException {
 		try {
-			return bs.convertToType(in, type);
+			return convertToType(in, type);
 		} catch (InvalidDataConversionException e) {
 			throw new SerializeException(e.getMessage());
 		}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartParser.java
index 42db0cf..2af625e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartParser.java
@@ -12,8 +12,7 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.httppart;
 
-import org.apache.juneau.*;
-import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
 
 /**
  * An implementation of {@link HttpPartParser} that takes in the strings and tries to convert them to POJOs using constructors and static create methods.
@@ -48,13 +47,26 @@ public class SimplePartParser implements HttpPartParser {
 	/** Reusable instance of {@link SimplePartParser}, all default settings. */
 	public static final SimplePartParser DEFAULT = new SimplePartParser();
 
-
 	//-------------------------------------------------------------------------------------------------------------------
 	// Instance
 	//-------------------------------------------------------------------------------------------------------------------
 
 	@Override
-	public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) {
-		return ClassUtils.fromString(type.getInnerClass(), in);
+	public SimplePartParserSession createSession(ParserSessionArgs args) {
+		return new SimplePartParserSession();
+	}
+
+	/**
+	 * Create a new parser session on the properties defined on this context.
+	 *
+	 * <p>
+	 * Use this method for creating sessions if you don't need to override any
+	 * properties or locale/timezone currently set on this context.
+	 *
+	 * @return A new session object.
+	 */
+	public SimplePartParserSession createSession() {
+		return new SimplePartParserSession();
 	}
+
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartType.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartParserSession.java
similarity index 71%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartType.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartParserSession.java
index 44f4bbd..c328b1c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartType.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartParserSession.java
@@ -12,26 +12,21 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.httppart;
 
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.parser.*;
+
 /**
- * Represents possible enum values that can be passed to the {@link HttpPartSerializer#serialize(HttpPartType, HttpPartSchema, Object)}.
+ * Session object that lives for the duration of a single use of {@link SimplePartParser}.
+ *
+ * <p>
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
  */
-public enum HttpPartType {
-
-	/** An HTTP request body */
-	BODY,
-
-	/** A URI path variable */
-	PATH,
-
-	/** A URI query parameter */
-	QUERY,
-
-	/** A form-data parameter */
-	FORMDATA,
-
-	/** An HTTP header */
-	HEADER,
+public class SimplePartParserSession implements HttpPartParserSession {
 
-	/** A non-standard field */
-	OTHER;
+	@Override
+	public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) throws ParseException, SchemaValidationException {
+		return ClassUtils.fromString(type.getInnerClass(), in);
+	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializer.java
index 664b7b4..2c82741 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializer.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.httppart;
 
 import org.apache.juneau.internal.*;
+import org.apache.juneau.serializer.*;
 
 /**
  * An implementation of {@link HttpPartSerializer} that simply serializes everything using {@link Object#toString()}.
@@ -29,13 +30,21 @@ public class SimplePartSerializer implements HttpPartSerializer {
 	/** Reusable instance of {@link SimplePartSerializer}, all default settings. */
 	public static final SimplePartSerializer DEFAULT = new SimplePartSerializer();
 
-
 	//-------------------------------------------------------------------------------------------------------------------
 	// Instance
 	//-------------------------------------------------------------------------------------------------------------------
 
-	@Override /* PartSerializer */
-	public String serialize(HttpPartType type, HttpPartSchema schema, Object value) {
-		return ClassUtils.toString(value);
+	@Override
+	public SimplePartSerializerSession createSession(SerializerSessionArgs args) {
+		return new SimplePartSerializerSession();
+	}
+
+	/**
+	 * Convenience method for creating a new serializer session with default session args.
+	 *
+	 * @return A new session object.
+	 */
+	public SimplePartSerializerSession createSession() {
+		return new SimplePartSerializerSession();
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializerSession.java
similarity index 73%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializer.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializerSession.java
index 664b7b4..628f28d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializerSession.java
@@ -15,20 +15,13 @@ package org.apache.juneau.httppart;
 import org.apache.juneau.internal.*;
 
 /**
- * An implementation of {@link HttpPartSerializer} that simply serializes everything using {@link Object#toString()}.
+ * Session object that lives for the duration of a single use of {@link SimplePartSerializer}.
  *
  * <p>
- * More precisely, uses the {@link ClassUtils#toString(Object)} method to stringify objects.
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
  */
-public class SimplePartSerializer implements HttpPartSerializer {
-
-	//-------------------------------------------------------------------------------------------------------------------
-	// Predefined instances
-	//-------------------------------------------------------------------------------------------------------------------
-
-	/** Reusable instance of {@link SimplePartSerializer}, all default settings. */
-	public static final SimplePartSerializer DEFAULT = new SimplePartSerializer();
-
+public class SimplePartSerializerSession implements HttpPartSerializerSession {
 
 	//-------------------------------------------------------------------------------------------------------------------
 	// Instance
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimpleUonPartSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimpleUonPartSerializer.java
index e04bacc..a20709c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimpleUonPartSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimpleUonPartSerializer.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.httppart;
 
 import org.apache.juneau.*;
+import org.apache.juneau.serializer.*;
 import org.apache.juneau.uon.*;
 
 /**
@@ -37,7 +38,6 @@ public class SimpleUonPartSerializer extends UonPartSerializer {
 	/** Reusable instance of {@link SimpleUonPartSerializer}, all default settings. */
 	public static final SimpleUonPartSerializer DEFAULT = new SimpleUonPartSerializer(PropertyStore.DEFAULT);
 
-
 	//-------------------------------------------------------------------------------------------------------------------
 	// Instance
 	//-------------------------------------------------------------------------------------------------------------------
@@ -73,4 +73,18 @@ public class SimpleUonPartSerializer extends UonPartSerializer {
 	public static SimpleUonPartSerializerBuilder create() {
 		return new SimpleUonPartSerializerBuilder();
 	}
+	
+	//-----------------------------------------------------------------------------------------------------------------
+	// Entry point methods
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Override
+	public SimpleUonPartSerializerSession createSession(SerializerSessionArgs args) {
+		return new SimpleUonPartSerializerSession(this, args);
+	}
+
+	@Override
+	public SimpleUonPartSerializerSession createSession() {
+		return new SimpleUonPartSerializerSession(this, SerializerSessionArgs.DEFAULT);
+	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartType.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimpleUonPartSerializerSession.java
similarity index 67%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartType.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimpleUonPartSerializerSession.java
index 44f4bbd..7e5b4a8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/HttpPartType.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimpleUonPartSerializerSession.java
@@ -12,26 +12,27 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.httppart;
 
+import org.apache.juneau.serializer.*;
+
 /**
- * Represents possible enum values that can be passed to the {@link HttpPartSerializer#serialize(HttpPartType, HttpPartSchema, Object)}.
+ * Session object that lives for the duration of a single use of {@link SimpleUonPartSerializer}.
+ *
+ * <p>
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
  */
-public enum HttpPartType {
-
-	/** An HTTP request body */
-	BODY,
-
-	/** A URI path variable */
-	PATH,
-
-	/** A URI query parameter */
-	QUERY,
-
-	/** A form-data parameter */
-	FORMDATA,
-
-	/** An HTTP header */
-	HEADER,
+public class SimpleUonPartSerializerSession extends UonPartSerializerSession {
 
-	/** A non-standard field */
-	OTHER;
+	/**
+	 * Create a new session using properties specified in the context.
+	 *
+	 * @param ctx
+	 * 	The context creating this session object.
+	 * 	The context contains all the configuration settings for this object.
+	 * @param args
+	 * 	Runtime session arguments.
+	 */
+	protected SimpleUonPartSerializerSession(UonPartSerializer ctx, SerializerSessionArgs args) {
+		super(ctx, args);
+	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParser.java
index 0c3f4a2..df5e60b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParser.java
@@ -12,8 +12,6 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.httppart;
 
-import static org.apache.juneau.internal.StringUtils.*;
-
 import org.apache.juneau.*;
 import org.apache.juneau.parser.*;
 import org.apache.juneau.uon.*;
@@ -24,7 +22,6 @@ import org.apache.juneau.uon.*;
  * <p>
  * This parser expects UON notation for all parts by default.
  */
-@SuppressWarnings({ "unchecked" })
 public class UonPartParser extends UonParser implements HttpPartParser {
 
 	//-------------------------------------------------------------------------------------------------------------------
@@ -73,43 +70,17 @@ public class UonPartParser extends UonParser implements HttpPartParser {
 		return new UonPartParserBuilder();
 	}
 
-	/**
-	 * Convenience method for calling the parse method without a schema object.
-	 *
-	 * @param partType The part type being parsed.
-	 * @param in The input being parsed.
-	 * @param type The category of value being parsed.
-	 * @return The parsed value.
-	 * @throws ParseException If a problem occurred while trying to parse the input.
-	 * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
-	 */
-	public <T> T parse(HttpPartType partType, String in, ClassMeta<T> type) throws ParseException, SchemaValidationException {
-		return parse(partType, null, in, type);
+	//-------------------------------------------------------------------------------------------------------------------
+	// Entry point methods
+	//-------------------------------------------------------------------------------------------------------------------
+
+	@Override
+	public UonPartParserSession createSession(ParserSessionArgs args) {
+		return new UonPartParserSession(this, args);
 	}
 
-	@Override /* HttpPartParser */
-	public <T> T parse(HttpPartType partType, HttpPartSchema schema, String in, ClassMeta<T> type) throws ParseException, SchemaValidationException {
-		if (in == null)
-			return null;
-		if (type.isString() && in.length() > 0) {
-			// Shortcut - If we're returning a string and the value doesn't start with "'" or is "null", then
-			// just return the string since it's a plain value.
-			// This allows us to bypass the creation of a UonParserSession object.
-			char x = firstNonWhitespaceChar(in);
-			if (x != '\'' && x != 'n' && in.indexOf('~') == -1)
-				return (T)in;
-			if (x == 'n' && "null".equals(in))
-				return null;
-		}
-		UonParserSession session = createParameterSession();
-		try (ParserPipe pipe = session.createPipe(in)) {
-			try (UonReader r = session.getUonReader(pipe, false)) {
-				return session.parseAnything(type, r, null, true, null);
-			}
-		} catch (ParseException e) {
-			throw e;
-		} catch (Exception e) {
-			throw new ParseException(e);
-		}
+	@Override
+	public UonPartParserSession createSession() {
+		return new UonPartParserSession(this, ParserSessionArgs.DEFAULT);
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParserSession.java
similarity index 54%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParser.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParserSession.java
index 0c3f4a2..4a9e4da 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartParserSession.java
@@ -19,64 +19,69 @@ import org.apache.juneau.parser.*;
 import org.apache.juneau.uon.*;
 
 /**
- * Parses HTTP headers, query/form-data parameters, and path variables into POJOs.
+ * Session object that lives for the duration of a single use of {@link UonPartParser}.
  *
  * <p>
- * This parser expects UON notation for all parts by default.
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
  */
 @SuppressWarnings({ "unchecked" })
-public class UonPartParser extends UonParser implements HttpPartParser {
-
-	//-------------------------------------------------------------------------------------------------------------------
-	// Predefined instances
-	//-------------------------------------------------------------------------------------------------------------------
-
-	/** Reusable instance of {@link UonPartParser}. */
-	public static final UonPartParser DEFAULT = new UonPartParser(PropertyStore.DEFAULT);
-
-
-	//-------------------------------------------------------------------------------------------------------------------
-	// Instance
-	//-------------------------------------------------------------------------------------------------------------------
+public class UonPartParserSession extends UonParserSession implements HttpPartParserSession {
 
 	/**
-	 * Constructor.
+	 * Create a new session using properties specified in the context.
 	 *
-	 * @param ps The property store containing all the settings for this object.
+	 * @param ctx
+	 * 	The context creating this session object.
+	 * 	The context contains all the configuration settings for this object.
+	 * @param args
+	 * 	Runtime session arguments.
 	 */
-	public UonPartParser(PropertyStore ps) {
-		super(
-			ps.builder()
-				.build(),
-			"application/x-www-form-urlencoded"
-		);
+	protected UonPartParserSession(UonPartParser ctx, ParserSessionArgs args) {
+		super(ctx, args);
 	}
 
-	@Override /* Context */
-	public UonPartParserBuilder builder() {
-		return new UonPartParserBuilder(getPropertyStore());
+	/**
+	 * Convenience method for parsing a part to a map or collection.
+	 *
+	 * @param schema
+	 * 	Schema information about the part.
+	 * 	<br>May be <jk>null</jk>.
+	 * 	<br>Not all part parsers use the schema information.
+	 * @param in The input being parsed.
+	 * @param type The category of value being parsed.
+	 * @param args The type arguments of the map or collection.
+	 * @return The parsed value.
+	 * @throws ParseException If a problem occurred while trying to parse the input.
+	 * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
+	 */
+	public <T> T parse(HttpPartSchema schema, String in, java.lang.reflect.Type type, java.lang.reflect.Type...args) throws ParseException, SchemaValidationException {
+		return (T)parse(null, schema, in, getClassMeta(type, args));
 	}
 
 	/**
-	 * Instantiates a new clean-slate {@link UonPartParserBuilder} object.
-	 *
-	 * <p>
-	 * This is equivalent to simply calling <code><jk>new</jk> UonPartParserBuilder()</code>.
+	 * Convenience method for parsing a part.
 	 *
-	 * <p>
-	 * Note that this method creates a builder initialized to all default settings, whereas {@link #builder()} copies
-	 * the settings of the object called on.
-	 *
-	 * @return A new {@link UonPartParserBuilder} object.
+	 * @param schema
+	 * 	Schema information about the part.
+	 * 	<br>May be <jk>null</jk>.
+	 * 	<br>Not all part parsers use the schema information.
+	 * @param in The input being parsed.
+	 * @param type The category of value being parsed.
+	 * @return The parsed value.
+	 * @throws ParseException If a problem occurred while trying to parse the input.
+	 * @throws SchemaValidationException If the input or resulting HTTP part object fails schema validation.
 	 */
-	public static UonPartParserBuilder create() {
-		return new UonPartParserBuilder();
+	public <T> T parse(HttpPartSchema schema, String in, Class<T> type) throws ParseException, SchemaValidationException {
+		return parse(null, schema, in, getClassMeta(type));
 	}
 
 	/**
-	 * Convenience method for calling the parse method without a schema object.
+	 * Convenience method for parsing a part.
 	 *
-	 * @param partType The part type being parsed.
+	 * @param partType
+	 * 	The part type being parsed.
+	 * 	<br>May be <jk>null</jk>.
 	 * @param in The input being parsed.
 	 * @param type The category of value being parsed.
 	 * @return The parsed value.
@@ -101,10 +106,9 @@ public class UonPartParser extends UonParser implements HttpPartParser {
 			if (x == 'n' && "null".equals(in))
 				return null;
 		}
-		UonParserSession session = createParameterSession();
-		try (ParserPipe pipe = session.createPipe(in)) {
-			try (UonReader r = session.getUonReader(pipe, false)) {
-				return session.parseAnything(type, r, null, true, null);
+		try (ParserPipe pipe = createPipe(in)) {
+			try (UonReader r = getUonReader(pipe, false)) {
+				return parseAnything(type, r, null, true, null);
 			}
 		} catch (ParseException e) {
 			throw e;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializer.java
index 043c4d4..c61597a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializer.java
@@ -12,10 +12,7 @@
 // ***************************************************************************************************************************
 package org.apache.juneau.httppart;
 
-import java.io.*;
-
 import org.apache.juneau.*;
-import org.apache.juneau.internal.*;
 import org.apache.juneau.serializer.*;
 import org.apache.juneau.uon.*;
 
@@ -35,7 +32,6 @@ public class UonPartSerializer extends UonSerializer implements HttpPartSerializ
 	/** Reusable instance of {@link UonPartSerializer}, all default settings. */
 	public static final UonPartSerializer DEFAULT = new UonPartSerializer(PropertyStore.DEFAULT);
 
-
 	//-------------------------------------------------------------------------------------------------------------------
 	// Instance
 	//-------------------------------------------------------------------------------------------------------------------
@@ -72,43 +68,17 @@ public class UonPartSerializer extends UonSerializer implements HttpPartSerializ
 		return new UonPartSerializerBuilder();
 	}
 
-	//--------------------------------------------------------------------------------
+	//-----------------------------------------------------------------------------------------------------------------
 	// Entry point methods
-	//--------------------------------------------------------------------------------
+	//-----------------------------------------------------------------------------------------------------------------
 
-	/**
-	 * Convenience method for calling the parse method without a schema object.
-	 *
-	 * @param type The category of value being serialized.
-	 * @param value The value being serialized.
-	 * @return The serialized value.
-	 * @throws SerializeException If a problem occurred while trying to parse the input.
-	 * @throws SchemaValidationException If the output fails schema validation.
-	 */
-	public String serialize(HttpPartType type, Object value) throws SerializeException, SchemaValidationException {
-		return serialize(type, null, value);
+	@Override
+	public UonPartSerializerSession createSession(SerializerSessionArgs args) {
+		return new UonPartSerializerSession(this, args);
 	}
 
-	@Override /* PartSerializer */
-	public String serialize(HttpPartType type, HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException {
-		try {
-			// Shortcut for simple types.
-			ClassMeta<?> cm = getClassMetaForObject(value);
-			if (cm != null) {
-				if (cm.isNumber() || cm.isBoolean())
-					return ClassUtils.toString(value);
-				if (cm.isString()) {
-					String s = ClassUtils.toString(value);
-					if (s.isEmpty() || ! UonUtils.needsQuotes(s))
-						return s;
-				}
-			}
-			StringWriter w = new StringWriter();
-			UonSerializerSession s = new UonSerializerSession(this, false, createDefaultSessionArgs());
-			s.serialize(value, w);
-			return w.toString();
-		} catch (Exception e) {
-			throw new RuntimeException(e);
-		}
+	@Override
+	public UonPartSerializerSession createSession() {
+		return new UonPartSerializerSession(this, SerializerSessionArgs.DEFAULT);
 	}
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializerSession.java
similarity index 55%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializer.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializerSession.java
index 664b7b4..cef43bf 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/SimplePartSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/httppart/UonPartSerializerSession.java
@@ -1,41 +1,65 @@
-// ***************************************************************************************************************************
-// * 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.httppart;
-
-import org.apache.juneau.internal.*;
-
-/**
- * An implementation of {@link HttpPartSerializer} that simply serializes everything using {@link Object#toString()}.
- *
- * <p>
- * More precisely, uses the {@link ClassUtils#toString(Object)} method to stringify objects.
- */
-public class SimplePartSerializer implements HttpPartSerializer {
-
-	//-------------------------------------------------------------------------------------------------------------------
-	// Predefined instances
-	//-------------------------------------------------------------------------------------------------------------------
-
-	/** Reusable instance of {@link SimplePartSerializer}, all default settings. */
-	public static final SimplePartSerializer DEFAULT = new SimplePartSerializer();
-
-
-	//-------------------------------------------------------------------------------------------------------------------
-	// Instance
-	//-------------------------------------------------------------------------------------------------------------------
-
-	@Override /* PartSerializer */
-	public String serialize(HttpPartType type, HttpPartSchema schema, Object value) {
-		return ClassUtils.toString(value);
-	}
-}
+// ***************************************************************************************************************************
+// * 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.httppart;
+
+import java.io.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.serializer.*;
+import org.apache.juneau.uon.*;
+
+/**
+ * Session object that lives for the duration of a single use of {@link UonPartSerializer}.
+ *
+ * <p>
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
+ */
+public class UonPartSerializerSession extends UonSerializerSession implements HttpPartSerializerSession {
+
+	/**
+	 * Create a new session using properties specified in the context.
+	 *
+	 * @param ctx
+	 * 	The context creating this session object.
+	 * 	The context contains all the configuration settings for this object.
+	 * @param args
+	 * 	Runtime session arguments.
+	 */
+	protected UonPartSerializerSession(UonPartSerializer ctx, SerializerSessionArgs args) {
+		super(ctx, false, args);
+	}
+
+	@Override /* PartSerializer */
+	public String serialize(HttpPartType type, HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException {
+		try {
+			// Shortcut for simple types.
+			ClassMeta<?> cm = getClassMetaForObject(value);
+			if (cm != null) {
+				if (cm.isNumber() || cm.isBoolean())
+					return ClassUtils.toString(value);
+				if (cm.isString()) {
+					String s = ClassUtils.toString(value);
+					if (s.isEmpty() || ! UonUtils.needsQuotes(s))
+						return s;
+				}
+			}
+			StringWriter w = new StringWriter();
+			super.serialize(value, w);
+			return w.toString();
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java
index 3e5cc62..f9243c2 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java
@@ -287,7 +287,7 @@ public class JsonSerializer extends WriterSerializer {
 		 */
 		public Readable(PropertyStore ps) {
 			super(
-				ps.builder().set(WSERIALIZER_useWhitespace, true).build()
+				ps.builder().set(SERIALIZER_useWhitespace, true).build()
 			);
 		}
 	}
@@ -324,7 +324,7 @@ public class JsonSerializer extends WriterSerializer {
 				ps.builder()
 					.set(JSON_simpleMode, true)
 					.set(WSERIALIZER_quoteChar, '\'')
-					.set(WSERIALIZER_useWhitespace, true)
+					.set(SERIALIZER_useWhitespace, true)
 					.build()
 			);
 		}
@@ -346,7 +346,7 @@ public class JsonSerializer extends WriterSerializer {
 				ps.builder()
 					.set(JSON_simpleMode, true)
 					.set(WSERIALIZER_quoteChar, '\'')
-					.set(WSERIALIZER_useWhitespace, true)
+					.set(SERIALIZER_useWhitespace, true)
 					.set(SERIALIZER_detectRecursions, true)
 					.build()
 			);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializer.java
index 71ac841..70f3657 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaSerializer.java
@@ -274,7 +274,7 @@ public class JsonSchemaSerializer extends JsonSerializer {
 		 */
 		public Readable(PropertyStore ps) {
 			super(
-				ps.builder().set(WSERIALIZER_useWhitespace, true).build()
+				ps.builder().set(SERIALIZER_useWhitespace, true).build()
 			);
 		}
 	}
@@ -310,7 +310,7 @@ public class JsonSchemaSerializer extends JsonSerializer {
 				ps.builder()
 					.set(JSON_simpleMode, true)
 					.set(WSERIALIZER_quoteChar, '\'')
-					.set(WSERIALIZER_useWhitespace, true)
+					.set(SERIALIZER_useWhitespace, true)
 					.build()
 			);
 		}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
index d3a4a6c..bbf5cf8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/Parser.java
@@ -693,7 +693,7 @@ public abstract class Parser extends BeanContext {
 	}
 
 	@Override /* Context */
-	public final ParserSession createSession() {
+	public ParserSession createSession() {
 		return createSession(createDefaultSessionArgs());
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
index 190db6d..1b8f912 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSession.java
@@ -56,7 +56,8 @@ public abstract class ParserSession extends BeanSession {
 	 * 	Runtime session arguments.
 	 */
 	protected ParserSession(Parser ctx, ParserSessionArgs args) {
-		super(ctx, args);
+		super(ctx, args == null ? ParserSessionArgs.DEFAULT : args);
+		args = args == null ? ParserSessionArgs.DEFAULT : args;
 		this.ctx = ctx;
 		javaMethod = args.javaMethod;
 		outer = args.outer;
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSessionArgs.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSessionArgs.java
index 8e3c5bb..d70e362 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSessionArgs.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ParserSessionArgs.java
@@ -27,6 +27,11 @@ public final class ParserSessionArgs extends BeanSessionArgs {
 	Object outer;
 
 	/**
+	 * Default parser session args.
+	 */
+	public static final ParserSessionArgs DEFAULT = new ParserSessionArgs();
+
+	/**
 	 * Constructor
 	 */
 	public ParserSessionArgs() {}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/OutputStreamSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/OutputStreamSerializerSession.java
index 18e95e6..355cff0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/OutputStreamSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/OutputStreamSerializerSession.java
@@ -85,7 +85,7 @@ public abstract class OutputStreamSerializerSession extends SerializerSession {
 		byte[] b = serialize(o);
 		switch(getBinaryFormat()) {
 			case SPACED_HEX:  return StringUtils.toSpacedHex(b);
-			case HEX:  return StringUtils.toHex(b);
+			case HEX:  return isUseWhitespace() ? StringUtils.toSpacedHex(b) : StringUtils.toHex(b);
 			case BASE64:  return StringUtils.base64Encode(b);
 			default: return null;
 		}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
index e086afa..18a3641 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/Serializer.java
@@ -831,6 +831,48 @@ public abstract class Serializer extends BeanContext {
 	 */
 	public static final String SERIALIZER_uriResolution = PREFIX + "uriResolution.s";
 
+	/**
+	 * Configuration property:  Use whitespace.
+	 *
+	 * <h5 class='section'>Property:</h5>
+	 * <ul>
+	 * 	<li><b>Name:</b>  <js>"Serializer.useWhitespace.b"</js>
+	 * 	<li><b>Data type:</b>  <code>Boolean</code>
+	 * 	<li><b>Default:</b>  <jk>false</jk>
+	 * 	<li><b>Session property:</b>  <jk>true</jk>
+	 * 	<li><b>Methods:</b>
+	 * 		<ul>
+	 * 			<li class='jm'>{@link SerializerBuilder#useWhitespace(boolean)}
+	 * 			<li class='jm'>{@link SerializerBuilder#useWhitespace()}
+	 * 			<li class='jm'>{@link SerializerBuilder#ws()}
+	 * 			<li class='jm'>{@link SerializerSessionArgs#useWhitespace(Boolean)}
+	 * 		</ul>
+	 * </ul>
+	 *
+	 * <h5 class='section'>Description:</h5>
+	 * <p>
+	 * If <jk>true</jk>, whitespace is added to the output to improve readability.
+	 *
+	 * <h5 class='section'>Example:</h5>
+	 * <p class='bcode'>
+	 * 	<jc>// Create a serializer with whitespace enabled.</jc>
+	 * 	WriterSerializer s = JsonSerializer
+	 * 		.<jsm>create</jsm>()
+	 * 		.ws()
+	 * 		.build();
+	 *
+	 * 	<jc>// Same, but use property.</jc>
+	 * 	WriterSerializer s = JsonSerializer
+	 * 		.<jsm>create</jsm>()
+	 * 		.set(<jsf>SERIALIZER_useWhitespace</jsf>, <jk>true</jk>)
+	 * 		.build();
+	 *
+	 * 	<jc>// Produces "\{\n\t'foo': 'bar'\n\}\n"</jc>
+	 * 	String json = s.serialize(<jk>new</jk> MyBean());
+	 * </p>
+	 */
+	public static final String SERIALIZER_useWhitespace = PREFIX + "useWhitespace.b";
+
 
 	static final Serializer DEFAULT = new Serializer(PropertyStore.create().build(), "", "") {
 		@Override
@@ -854,7 +896,8 @@ public abstract class Serializer extends BeanContext {
 		trimStrings,
 		sortCollections,
 		sortMaps,
-		addRootType;
+		addRootType,
+		useWhitespace;
 	private final UriContext uriContext;
 	private final UriResolution uriResolution;
 	private final UriRelativity uriRelativity;
@@ -909,6 +952,7 @@ public abstract class Serializer extends BeanContext {
 		uriContext = getProperty(SERIALIZER_uriContext, UriContext.class, UriContext.DEFAULT);
 		uriResolution = getProperty(SERIALIZER_uriResolution, UriResolution.class, UriResolution.NONE);
 		uriRelativity = getProperty(SERIALIZER_uriRelativity, UriRelativity.class, UriRelativity.RESOURCE);
+		useWhitespace = getBooleanProperty(SERIALIZER_useWhitespace, false);
 		listener = getClassProperty(SERIALIZER_listener, SerializerListener.class, null);
 
 		this.produces = MediaType.forString(produces);
@@ -1252,6 +1296,17 @@ public abstract class Serializer extends BeanContext {
 	}
 
 	/**
+	 * Configuration property:  Trim strings.
+	 *
+	 * @see #SERIALIZER_trimStrings
+	 * @return
+	 * 	<jk>true</jk> if string values will be trimmed of whitespace using {@link String#trim()} before being serialized.
+	 */
+	protected final boolean isUseWhitespace() {
+		return useWhitespace;
+	}
+
+	/**
 	 * Configuration property:  Serializer listener.
 	 *
 	 * @see #SERIALIZER_listener
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerBuilder.java
index d917a57..0299647 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerBuilder.java
@@ -614,6 +614,59 @@ public class SerializerBuilder extends BeanContextBuilder {
 		return set(SERIALIZER_uriResolution, value);
 	}
 
+	/**
+	 * Configuration property:  Use whitespace.
+	 *
+	 * <p>
+	 * If <jk>true</jk>, newlines and indentation and spaces are added to the output to improve readability.
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link WriterSerializer#SERIALIZER_useWhitespace}
+	 * </ul>
+	 *
+	 * @param value
+	 * 	The new value for this property.
+	 * 	<br>The default is <jk>false</jk>.
+	 * @return This object (for method chaining).
+	 */
+	public SerializerBuilder useWhitespace(boolean value) {
+		return set(SERIALIZER_useWhitespace, value);
+	}
+
+	/**
+	 * Configuration property:  Use whitespace.
+	 *
+	 * <p>
+	 * Shortcut for calling <code>useWhitespace(<jk>true</jk>)</code>.
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link WriterSerializer#SERIALIZER_useWhitespace}
+	 * </ul>
+	 * @return This object (for method chaining).
+	 */
+	public SerializerBuilder useWhitespace() {
+		return set(SERIALIZER_useWhitespace, true);
+	}
+
+	/**
+	 * Configuration property:  Use whitespace.
+	 *
+	 * <p>
+	 * Shortcut for calling <code>useWhitespace(<jk>true</jk>)</code>.
+	 *
+	 * <h5 class='section'>See Also:</h5>
+	 * <ul>
+	 * 	<li class='jf'>{@link WriterSerializer#SERIALIZER_useWhitespace}
+	 * </ul>
+	 *
+	 * @return This object (for method chaining).
+	 */
+	public SerializerBuilder ws() {
+		return useWhitespace();
+	}
+
 	@Override /* BeanContextBuilder */
 	public SerializerBuilder beanClassVisibility(Visibility value) {
 		super.beanClassVisibility(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroupBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroupBuilder.java
index dff4f4b..9f1d5c2 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroupBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerGroupBuilder.java
@@ -679,7 +679,7 @@ public class SerializerGroupBuilder extends BeanContextBuilder {
 	 *
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='jf'>{@link WriterSerializer#WSERIALIZER_useWhitespace}
+	 * 	<li class='jf'>{@link Serializer#SERIALIZER_useWhitespace}
 	 * </ul>
 	 *
 	 * @param value
@@ -688,7 +688,7 @@ public class SerializerGroupBuilder extends BeanContextBuilder {
 	 * @return This object (for method chaining).
 	 */
 	public SerializerGroupBuilder useWhitespace(boolean value) {
-		return set(WSERIALIZER_useWhitespace, value);
+		return set(SERIALIZER_useWhitespace, value);
 	}
 
 	/**
@@ -699,12 +699,12 @@ public class SerializerGroupBuilder extends BeanContextBuilder {
 	 *
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='jf'>{@link WriterSerializer#WSERIALIZER_useWhitespace}
+	 * 	<li class='jf'>{@link Serializer#SERIALIZER_useWhitespace}
 	 * </ul>
 	 * @return This object (for method chaining).
 	 */
 	public SerializerGroupBuilder useWhitespace() {
-		return set(WSERIALIZER_useWhitespace, true);
+		return set(SERIALIZER_useWhitespace, true);
 	}
 
 	/**
@@ -715,7 +715,7 @@ public class SerializerGroupBuilder extends BeanContextBuilder {
 	 *
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='jf'>{@link WriterSerializer#WSERIALIZER_useWhitespace}
+	 * 	<li class='jf'>{@link Serializer#SERIALIZER_useWhitespace}
 	 * </ul>
 	 *
 	 * @return This object (for method chaining).
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
index 96437f2..8627561 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSession.java
@@ -60,6 +60,7 @@ public abstract class SerializerSession extends BeanSession {
 	private boolean isBottom;                                                       // If 'true', then we're at a leaf in the model (i.e. a String, Number, Boolean, or null).
 	private BeanPropertyMeta currentProperty;
 	private ClassMeta<?> currentClass;
+	private final boolean useWhitespace;
 	private final SerializerListener listener;
 
 	/** The current indentation depth into the model. */
@@ -80,11 +81,13 @@ public abstract class SerializerSession extends BeanSession {
 	 * 	serializer contexts.
 	 */
 	protected SerializerSession(Serializer ctx, SerializerSessionArgs args) {
-		super(ctx, args);
+		super(ctx, args == null ? SerializerSessionArgs.DEFAULT : args);
 		this.ctx = ctx;
+		args = args == null ? SerializerSessionArgs.DEFAULT : args;
 		this.javaMethod = args.javaMethod;
 		this.uriResolver = new UriResolver(ctx.getUriResolution(), ctx.getUriRelativity(), args.uriContext == null ? ctx.getUriContext() : args.uriContext);
 		this.listener = newInstance(SerializerListener.class, ctx.getListener());
+		this.useWhitespace = args.useWhitespace != null ? args.useWhitespace : ctx.isUseWhitespace();
 
 		this.indent = getInitialDepth();
 		if (isDetectRecursions() || isDebug()) {
@@ -761,6 +764,17 @@ public abstract class SerializerSession extends BeanSession {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	/**
+	 * Configuration property:  Use whitespace.
+	 *
+	 * @see #SERIALIZER_useWhitespace
+	 * @return
+	 * 	<jk>true</jk> if whitespace is added to the output to improve readability.
+	 */
+	public final boolean isUseWhitespace() {
+		return useWhitespace;
+	}
+
+	/**
 	 * Configuration property:  Initial depth.
 	 *
 	 * @see #SERIALIZER_initialDepth
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSessionArgs.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSessionArgs.java
index 26a0593..7226e80 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSessionArgs.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/SerializerSessionArgs.java
@@ -26,8 +26,14 @@ import org.apache.juneau.http.*;
  */
 public final class SerializerSessionArgs extends BeanSessionArgs {
 
+	/**
+	 * Default serializer session args.
+	 */
+	public static final SerializerSessionArgs DEFAULT = new SerializerSessionArgs();
+
 	Method javaMethod;
 	UriContext uriContext;
+	Boolean useWhitespace;
 
 	/**
 	 * Constructor
@@ -59,11 +65,14 @@ public final class SerializerSessionArgs extends BeanSessionArgs {
 	 * @param uriContext
 	 * 	The URI context.
 	 * 	<br>Identifies the current request URI used for resolution of URIs to absolute or root-relative form.
+	 * @param useWhitespace
+	 * 	Override the use-whitespace flag on the serializer.
 	 */
-	public SerializerSessionArgs(ObjectMap properties, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, Boolean debug, UriContext uriContext) {
+	public SerializerSessionArgs(ObjectMap properties, Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, Boolean debug, UriContext uriContext, Boolean 	useWhitespace) {
 		super(properties, locale, timeZone, mediaType, debug);
 		this.javaMethod = javaMethod;
 		this.uriContext = uriContext;
+		this.useWhitespace = useWhitespace;
 	}
 
 	/**
@@ -92,6 +101,19 @@ public final class SerializerSessionArgs extends BeanSessionArgs {
 		return this;
 	}
 
+	/**
+	 * Use-whitespace flag
+	 *
+	 * @param useWhitespace
+	 * 	The use-whitespace flag.
+	 * 	<br>Overrides the use-whitespace flag on the serializer.
+	 * @return This object (for method chaining).
+	 */
+	public SerializerSessionArgs useWhitespace(Boolean useWhitespace) {
+		this.useWhitespace = useWhitespace;
+		return this;
+	}
+
 	@Override /* BeanSessionArgs */
 	public SerializerSessionArgs locale(Locale locale) {
 		super.locale(locale);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
index 04c2858..4a13783 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
@@ -105,47 +105,6 @@ public abstract class WriterSerializer extends Serializer {
 	 */
 	public static final String WSERIALIZER_quoteChar = PREFIX + "quoteChar.s";
 
-	/**
-	 * Configuration property:  Use whitespace.
-	 *
-	 * <h5 class='section'>Property:</h5>
-	 * <ul>
-	 * 	<li><b>Name:</b>  <js>"WriterSerializer.useWhitespace.b"</js>
-	 * 	<li><b>Data type:</b>  <code>Boolean</code>
-	 * 	<li><b>Default:</b>  <jk>false</jk>
-	 * 	<li><b>Session property:</b>  <jk>false</jk>
-	 * 	<li><b>Methods:</b>
-	 * 		<ul>
-	 * 			<li class='jm'>{@link WriterSerializerBuilder#useWhitespace(boolean)}
-	 * 			<li class='jm'>{@link WriterSerializerBuilder#useWhitespace()}
-	 * 			<li class='jm'>{@link WriterSerializerBuilder#ws()}
-	 * 		</ul>
-	 * </ul>
-	 *
-	 * <h5 class='section'>Description:</h5>
-	 * <p>
-	 * If <jk>true</jk>, whitespace is added to the output to improve readability.
-	 *
-	 * <h5 class='section'>Example:</h5>
-	 * <p class='bcode'>
-	 * 	<jc>// Create a serializer with whitespace enabled.</jc>
-	 * 	WriterSerializer s = JsonSerializer
-	 * 		.<jsm>create</jsm>()
-	 * 		.ws()
-	 * 		.build();
-	 *
-	 * 	<jc>// Same, but use property.</jc>
-	 * 	WriterSerializer s = JsonSerializer
-	 * 		.<jsm>create</jsm>()
-	 * 		.set(<jsf>WSERIALIZER_useWhitespace</jsf>, <jk>true</jk>)
-	 * 		.build();
-	 *
-	 * 	<jc>// Produces "\{\n\t'foo': 'bar'\n\}\n"</jc>
-	 * 	String json = s.serialize(<jk>new</jk> MyBean());
-	 * </p>
-	 */
-	public static final String WSERIALIZER_useWhitespace = PREFIX + "useWhitespace.b";
-
 	static final WriterSerializer DEFAULT = new WriterSerializer(PropertyStore.create().build(), "", "") {
 		@Override
 		public WriterSerializerSession createSession(SerializerSessionArgs args) {
@@ -158,7 +117,6 @@ public abstract class WriterSerializer extends Serializer {
 	//-------------------------------------------------------------------------------------------------------------------
 
 	private final int maxIndent;
-	private final boolean useWhitespace;
 	private final char quoteChar;
 
 	/**
@@ -191,7 +149,6 @@ public abstract class WriterSerializer extends Serializer {
 	protected WriterSerializer(PropertyStore ps, String produces, String accept) {
 		super(ps, produces, accept);
 
-		useWhitespace = getBooleanProperty(WSERIALIZER_useWhitespace, false);
 		maxIndent = getIntegerProperty(WSERIALIZER_maxIndent, 100);
 		quoteChar = getStringProperty(WSERIALIZER_quoteChar, "\"").charAt(0);
 	}
@@ -280,17 +237,6 @@ public abstract class WriterSerializer extends Serializer {
 	}
 
 	/**
-	 * Configuration property:  Use whitespace.
-	 *
-	 * @see #WSERIALIZER_useWhitespace
-	 * @return
-	 * 	<jk>true</jk> if whitespace is added to the output to improve readability.
-	 */
-	protected final boolean isUseWhitespace() {
-		return useWhitespace;
-	}
-
-	/**
 	 * Configuration property:  Quote character.
 	 *
 	 * @see #WSERIALIZER_quoteChar
@@ -305,7 +251,6 @@ public abstract class WriterSerializer extends Serializer {
 	public ObjectMap asMap() {
 		return super.asMap()
 			.append("WriterSerializer", new ObjectMap()
-				.append("useWhitespace", useWhitespace)
 				.append("maxIndent", maxIndent)
 				.append("quoteChar", quoteChar)
 			);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerBuilder.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerBuilder.java
index 1af8ebc..a354a21 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerBuilder.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerBuilder.java
@@ -102,59 +102,6 @@ public class WriterSerializerBuilder extends SerializerBuilder {
 		return quoteChar('\'');
 	}
 
-	/**
-	 * Configuration property:  Use whitespace.
-	 *
-	 * <p>
-	 * If <jk>true</jk>, newlines and indentation and spaces are added to the output to improve readability.
-	 *
-	 * <h5 class='section'>See Also:</h5>
-	 * <ul>
-	 * 	<li class='jf'>{@link WriterSerializer#WSERIALIZER_useWhitespace}
-	 * </ul>
-	 *
-	 * @param value
-	 * 	The new value for this property.
-	 * 	<br>The default is <jk>false</jk>.
-	 * @return This object (for method chaining).
-	 */
-	public WriterSerializerBuilder useWhitespace(boolean value) {
-		return set(WSERIALIZER_useWhitespace, value);
-	}
-
-	/**
-	 * Configuration property:  Use whitespace.
-	 *
-	 * <p>
-	 * Shortcut for calling <code>useWhitespace(<jk>true</jk>)</code>.
-	 *
-	 * <h5 class='section'>See Also:</h5>
-	 * <ul>
-	 * 	<li class='jf'>{@link WriterSerializer#WSERIALIZER_useWhitespace}
-	 * </ul>
-	 * @return This object (for method chaining).
-	 */
-	public WriterSerializerBuilder useWhitespace() {
-		return set(WSERIALIZER_useWhitespace, true);
-	}
-
-	/**
-	 * Configuration property:  Use whitespace.
-	 *
-	 * <p>
-	 * Shortcut for calling <code>useWhitespace(<jk>true</jk>)</code>.
-	 *
-	 * <h5 class='section'>See Also:</h5>
-	 * <ul>
-	 * 	<li class='jf'>{@link WriterSerializer#WSERIALIZER_useWhitespace}
-	 * </ul>
-	 *
-	 * @return This object (for method chaining).
-	 */
-	public WriterSerializerBuilder ws() {
-		return useWhitespace();
-	}
-
 	@Override /* BeanContextBuilder */
 	public WriterSerializerBuilder beanClassVisibility(Visibility value) {
 		super.beanClassVisibility(value);
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java
index f66dbc7..2302804 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializerSession.java
@@ -105,17 +105,6 @@ public abstract class WriterSerializerSession extends SerializerSession {
 	}
 
 	/**
-	 * Configuration property:  Use whitespace.
-	 *
-	 * @see #WSERIALIZER_useWhitespace
-	 * @return
-	 * 	<jk>true</jk> if whitespace is added to the output to improve readability.
-	 */
-	public final boolean isUseWhitespace() {
-		return ctx.isUseWhitespace();
-	}
-
-	/**
 	 * Configuration property:  Quote character.
 	 *
 	 * @see #WSERIALIZER_quoteChar
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializer.java
index 3bebc97..16bcb3d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/uon/UonSerializer.java
@@ -279,7 +279,7 @@ public class UonSerializer extends WriterSerializer {
 		 * @param ps The property store containing all the settings for this object.
 		 */
 		public Readable(PropertyStore ps) {
-			super(ps.builder().set(WSERIALIZER_useWhitespace, true).build());
+			super(ps.builder().set(SERIALIZER_useWhitespace, true).build());
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
index 0cdc005..41bbc7b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
@@ -222,7 +222,7 @@ public class UrlEncodingSerializer extends UonSerializer {
 		 * @param ps The property store containing all the settings for this object.
 		 */
 		public Readable(PropertyStore ps) {
-			super(ps.builder().set(WSERIALIZER_useWhitespace, true).build());
+			super(ps.builder().set(SERIALIZER_useWhitespace, true).build());
 		}
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
index d5a0e6a..59310ea 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
@@ -380,7 +380,7 @@ public class XmlSerializer extends WriterSerializer {
 			super(
 				ps.builder()
 					.set(WSERIALIZER_quoteChar, '\'')
-					.set(WSERIALIZER_useWhitespace, true)
+					.set(SERIALIZER_useWhitespace, true)
 					.build()
 				);
 		}
@@ -436,7 +436,7 @@ public class XmlSerializer extends WriterSerializer {
 				ps.builder()
 					.set(XML_enableNamespaces, true)
 					.set(WSERIALIZER_quoteChar, '\'')
-					.set(WSERIALIZER_useWhitespace, true)
+					.set(SERIALIZER_useWhitespace, true)
 					.build()
 				);
 		}
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
index 776a21a..8a58f0c 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/RequestBeanProxyTest.java
@@ -28,6 +28,7 @@ import org.apache.juneau.rest.*;
 import org.apache.juneau.rest.annotation.*;
 import org.apache.juneau.rest.client.*;
 import org.apache.juneau.rest.mock.*;
+import org.apache.juneau.serializer.*;
 import org.apache.juneau.urlencoding.*;
 import org.apache.juneau.utils.*;
 import org.junit.*;
@@ -1158,27 +1159,37 @@ public class RequestBeanProxyTest {
 
 	public static class XSerializer implements HttpPartSerializer {
 		@Override
-		public String serialize(HttpPartType type, HttpPartSchema schema, Object value) {
-			if (value == null)
-				return "NULL";
-			if (value instanceof Collection)
-				return join((Collection<?>)value, "X");
-			if (isArray(value))
-				return join(toList(value, Object.class), "X");
-			return "x" + value + "x";
+		public HttpPartSerializerSession createSession(SerializerSessionArgs args) {
+			return new HttpPartSerializerSession() {
+				@Override
+				public String serialize(HttpPartType type, HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException {
+					if (value == null)
+						return "NULL";
+					if (value instanceof Collection)
+						return join((Collection<?>)value, "X");
+					if (isArray(value))
+						return join(toList(value, Object.class), "X");
+					return "x" + value + "x";
+				}
+			};
 		}
 	}
 
 	public static class ListSerializer implements HttpPartSerializer {
 		@Override
-		public String serialize(HttpPartType type, HttpPartSchema schema, Object value) {
-			if (value == null)
-				return "NULL";
-			if (value instanceof Collection)
-				return join((Collection<?>)value, '|');
-			if (isArray(value))
-				return join(toList(value, Object.class), "|");
-			return "?" + value + "?";
+		public HttpPartSerializerSession createSession(SerializerSessionArgs args) {
+			return new HttpPartSerializerSession() {
+				@Override
+				public String serialize(HttpPartType type, HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException {
+					if (value == null)
+						return "NULL";
+					if (value instanceof Collection)
+						return join((Collection<?>)value, '|');
+					if (isArray(value))
+						return join(toList(value, Object.class), "|");
+					return "?" + value + "?";
+				}
+			};
 		}
 	}
 }
diff --git a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyTest.java b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyTest.java
index ed1e36f..216f5b7 100644
--- a/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyTest.java
+++ b/juneau-microservice/juneau-microservice-test/src/test/java/org/apache/juneau/rest/test/client/ThirdPartyProxyTest.java
@@ -2862,8 +2862,13 @@ public class ThirdPartyProxyTest extends RestTestcase {
 
 	public static class DummyPartSerializer implements HttpPartSerializer {
 		@Override
-		public String serialize(HttpPartType type, HttpPartSchema schema, Object value) {
-			return "dummy-"+value;
+		public HttpPartSerializerSession createSession(SerializerSessionArgs args) {
+			return new HttpPartSerializerSession() {
+				@Override
+				public String serialize(HttpPartType type, HttpPartSchema schema, Object value) throws SerializeException, SchemaValidationException {
+					return "dummy-"+value;
+				}
+			};
 		}
 	}
 }
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
index b1c3efb..eb574ae 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCall.java
@@ -210,7 +210,7 @@ public final class RestCall extends BeanSession implements Closeable {
 		if (! ("*".equals(name) || isEmpty(name))) {
 			if (value != null && ! (ObjectUtils.isEmpty(value) && skipIfEmpty))
 				try {
-					uriBuilder.addParameter(name, serializer.serialize(HttpPartType.QUERY, schema, value));
+					uriBuilder.addParameter(name, serializer.createSession(null).serialize(HttpPartType.QUERY, schema, value));
 				} catch (SerializeException | SchemaValidationException e) {
 					throw new RestCallException(e);
 				}
@@ -445,7 +445,7 @@ public final class RestCall extends BeanSession implements Closeable {
 			if (path.indexOf(var) == -1)
 				throw new RestCallException("Path variable {"+name+"} was not found in path.");
 			try {
-				uriBuilder.setPath(path.replace(var, serializer.serialize(HttpPartType.PATH, schema, value)));
+				uriBuilder.setPath(path.replace(var, serializer.createSession(null).serialize(HttpPartType.PATH, schema, value)));
 			} catch (SerializeException | SchemaValidationException e) {
 				throw new RestCallException(e);
 			}
@@ -587,7 +587,7 @@ public final class RestCall extends BeanSession implements Closeable {
 		if (! ("*".equals(name) || isEmpty(name))) {
 			if (value != null && ! (ObjectUtils.isEmpty(value) && skipIfEmpty))
 				try {
-					request.setHeader(name, serializer.serialize(HttpPartType.HEADER, schema, value));
+					request.setHeader(name, serializer.createSession(null).serialize(HttpPartType.HEADER, schema, value));
 				} catch (SerializeException | SchemaValidationException e) {
 					throw new RestCallException(e);
 				}
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
index b28b1de..0ec6db9 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestClientBuilder.java
@@ -1805,7 +1805,7 @@ public class RestClientBuilder extends BeanContextBuilder {
 	 *
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='jf'>{@link WriterSerializer#WSERIALIZER_useWhitespace}
+	 * 	<li class='jf'>{@link Serializer#SERIALIZER_useWhitespace}
 	 * </ul>
 	 *
 	 * @param value
@@ -1814,7 +1814,7 @@ public class RestClientBuilder extends BeanContextBuilder {
 	 * @return This object (for method chaining).
 	 */
 	public RestClientBuilder useWhitespace(boolean value) {
-		return set(WSERIALIZER_useWhitespace, value);
+		return set(SERIALIZER_useWhitespace, value);
 	}
 
 	/**
@@ -1825,12 +1825,12 @@ public class RestClientBuilder extends BeanContextBuilder {
 	 *
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='jf'>{@link WriterSerializer#WSERIALIZER_useWhitespace}
+	 * 	<li class='jf'>{@link Serializer#SERIALIZER_useWhitespace}
 	 * </ul>
 	 * @return This object (for method chaining).
 	 */
 	public RestClientBuilder useWhitespace() {
-		return set(WSERIALIZER_useWhitespace, true);
+		return set(SERIALIZER_useWhitespace, true);
 	}
 
 	/**
@@ -1841,13 +1841,13 @@ public class RestClientBuilder extends BeanContextBuilder {
 	 *
 	 * <h5 class='section'>See Also:</h5>
 	 * <ul>
-	 * 	<li class='jf'>{@link WriterSerializer#WSERIALIZER_useWhitespace}
+	 * 	<li class='jf'>{@link Serializer#SERIALIZER_useWhitespace}
 	 * </ul>
 	 *
 	 * @return This object (for method chaining).
 	 */
 	public RestClientBuilder ws() {
-		return set(WSERIALIZER_useWhitespace, true);
+		return set(SERIALIZER_useWhitespace, true);
 	}
 
 	/**
diff --git a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/SerializedNameValuePair.java b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/SerializedNameValuePair.java
index d23c572..5adca48 100644
--- a/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/SerializedNameValuePair.java
+++ b/juneau-rest/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/SerializedNameValuePair.java
@@ -63,7 +63,7 @@ public final class SerializedNameValuePair implements NameValuePair {
 	@Override /* NameValuePair */
 	public String getValue() {
 		try {
-			return serializer.serialize(HttpPartType.FORMDATA, schema, value);
+			return serializer.createSession(null).serialize(HttpPartType.FORMDATA, schema, value);
 		} catch (SerializeException | SchemaValidationException e) {
 			throw new RuntimeException(e);
 		}
diff --git a/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java b/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
index edf6010..33f2002 100644
--- a/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
+++ b/juneau-rest/juneau-rest-server-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java
@@ -121,7 +121,7 @@ public class BaseProvider implements MessageBodyReader<Object>, MessageBodyWrite
 			Locale locale = getLocale(headers);
 			TimeZone timeZone = getTimeZone(headers);
 
-			SerializerSession session = s.createSession(new SerializerSessionArgs(mp, null, locale, timeZone, sm.getMediaType(), null, null));
+			SerializerSession session = s.createSession(new SerializerSessionArgs(mp, null, locale, timeZone, sm.getMediaType(), null, null, null));
 
 			// Leave this open in case an error occurs.
 			Closeable c = s.isWriterSerializer() ? new OutputStreamWriter(os, UTF8) : os;
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
index 105b303..8be3926 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestInfoProvider.java
@@ -14,10 +14,8 @@ package org.apache.juneau.rest;
 
 import static org.apache.juneau.internal.ReflectionUtils.*;
 import static org.apache.juneau.internal.StringUtils.*;
-import static org.apache.juneau.jsonschema.JsonSchemaSerializer.*;
 import static org.apache.juneau.rest.RestParamType.*;
 import static org.apache.juneau.rest.util.AnnotationUtils.*;
-import static org.apache.juneau.serializer.OutputStreamSerializer.*;
 
 import java.lang.reflect.*;
 import java.lang.reflect.Method;
@@ -916,13 +914,12 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 
 		if (isOk || isBody) {
 			List<MediaType> mediaTypes = isOk ? sm.getSerializers().getSupportedMediaTypes() : sm.getParsers().getSupportedMediaTypes();
-			ObjectMap sprops = new ObjectMap().append(WSERIALIZER_useWhitespace, true).append(OSSERIALIZER_binaryFormat, BinaryFormat.SPACED_HEX);
 
 			for (MediaType mt : mediaTypes) {
 				if (mt != MediaType.HTML) {
 					Serializer s2 = sm.getSerializers().getSerializer(mt);
 					if (s2 != null) {
-						SerializerSessionArgs args = new SerializerSessionArgs(sprops, req.getJavaMethod(), req.getLocale(), null, mt, req.isDebug() ? true : null, req.getUriContext());
+						SerializerSessionArgs args = new SerializerSessionArgs(null, req.getJavaMethod(), req.getLocale(), null, mt, req.isDebug() ? true : null, req.getUriContext(), true);
 						try {
 							String eVal = s2.createSession(args).serializeToString(example);
 							examples.put(s2.getPrimaryMediaType().toString(), eVal);
@@ -934,7 +931,7 @@ public class BasicRestInfoProvider implements RestInfoProvider {
 			}
 		} else {
 			String paramName = piri.getString("name");
-			String s = sm.partSerializer.serialize(HttpPartType.valueOf(in.toUpperCase()), null, example);
+			String s = sm.partSerializer.createSession(req.getSerializerSessionArgs()).serialize(HttpPartType.valueOf(in.toUpperCase()), null, example);
 			if ("query".equals(in))
 				s = "?" + urlEncodeLax(paramName) + "=" + urlEncodeLax(s);
 			else if ("formData".equals(in))
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
index fa57141..c6679f8 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestBody.java
@@ -48,7 +48,6 @@ public class RequestBody {
 	private ParserGroup parsers;
 	private long maxInput;
 	private RequestHeaders headers;
-	private BeanSession beanSession;
 	private int contentLength = 0;
 	private MediaType mediaType;
 	private Parser parser;
@@ -77,11 +76,6 @@ public class RequestBody {
 		return this;
 	}
 
-	RequestBody beanSession(BeanSession beanSession) {
-		this.beanSession = beanSession;
-		return this;
-	}
-
 	RequestBody load(MediaType mediaType, Parser parser, byte[] body) {
 		this.mediaType = mediaType;
 		this.parser = parser;
@@ -481,7 +475,7 @@ public class RequestBody {
 		if ((isEmpty(mt) || mt.toString().startsWith("text/plain"))) {
 			if (partParser != null) {
 				String in = asString();
-				return partParser.parse(HttpPartType.BODY, schema, isEmpty(in) ? null : in, cm);
+				return partParser.createSession(req.getParserSessionArgs()).parse(HttpPartType.BODY, schema, isEmpty(in) ? null : in, cm);
 			} else if (cm.hasStringTransform()) {
 				return cm.getStringTransform().transform(asString());
 			}
@@ -531,10 +525,10 @@ public class RequestBody {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
-		return beanSession.getClassMeta(type, args);
+		return req.getBeanSession().getClassMeta(type, args);
 	}
 
 	private <T> ClassMeta<T> getClassMeta(Class<T> type) {
-		return beanSession.getClassMeta(type);
+		return req.getBeanSession().getClassMeta(type);
 	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java
index 52397b2..3de30d8 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestFormData.java
@@ -56,17 +56,12 @@ import org.apache.juneau.rest.exception.*;
 public class RequestFormData extends LinkedHashMap<String,String[]> {
 	private static final long serialVersionUID = 1L;
 
-	private HttpPartParser parser;
-	private BeanSession beanSession;
+	private final RestRequest req;
+	private final HttpPartParser parser;
 
-	RequestFormData setParser(HttpPartParser parser) {
+	RequestFormData(RestRequest req, HttpPartParser parser) {
+		this.req = req;
 		this.parser = parser;
-		return this;
-	}
-
-	RequestFormData setBeanSession(BeanSession beanSession) {
-		this.beanSession = beanSession;
-		return this;
 	}
 
 	/**
@@ -576,7 +571,7 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	private <T> T parse(HttpPartParser parser, HttpPartSchema schema, String val, ClassMeta<T> c) throws SchemaValidationException, ParseException {
 		if (parser == null)
 			parser = this.parser;
-		return parser.parse(HttpPartType.FORMDATA, schema, val, c);
+		return parser.createSession(req.getParserSessionArgs()).parse(HttpPartType.FORMDATA, schema, val, c);
 	}
 
 	/**
@@ -605,10 +600,10 @@ public class RequestFormData extends LinkedHashMap<String,String[]> {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
-		return beanSession.getClassMeta(type, args);
+		return req.getBeanSession().getClassMeta(type, args);
 	}
 
 	private <T> ClassMeta<T> getClassMeta(Class<T> type) {
-		return beanSession.getClassMeta(type);
+		return req.getBeanSession().getClassMeta(type);
 	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java
index dc34a84..d4fa6b9 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestHeaders.java
@@ -41,12 +41,13 @@ import org.apache.juneau.rest.exception.*;
 public class RequestHeaders extends TreeMap<String,String[]> {
 	private static final long serialVersionUID = 1L;
 
+	private final RestRequest req;
 	private HttpPartParser parser;
-	private BeanSession beanSession;
 	private RequestQuery queryParams;
 
-	RequestHeaders() {
+	RequestHeaders(RestRequest req) {
 		super(String.CASE_INSENSITIVE_ORDER);
+		this.req = req;
 	}
 
 	RequestHeaders parser(HttpPartParser parser) {
@@ -54,12 +55,7 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 		return this;
 	}
 
-	RequestHeaders beanSession(BeanSession beanSession) {
-		this.beanSession = beanSession;
-		return this;
-	}
-
-	RequestHeaders setQueryParams(RequestQuery queryParams) {
+	RequestHeaders queryParams(RequestQuery queryParams) {
 		this.queryParams = queryParams;
 		return this;
 	}
@@ -408,7 +404,7 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	private <T> T parse(HttpPartParser parser, HttpPartSchema schema, String val, ClassMeta<T> cm) throws SchemaValidationException, ParseException {
 		if (parser == null)
 			parser = this.parser;
-		return parser.parse(HttpPartType.HEADER, schema, val, cm);
+		return parser.createSession(req.getParserSessionArgs()).parse(HttpPartType.HEADER, schema, val, cm);
 	}
 
 	/**
@@ -418,7 +414,7 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	 * @return A new headers object.
 	 */
 	public RequestHeaders subset(String...headers) {
-		RequestHeaders rh2 = new RequestHeaders().parser(parser).beanSession(beanSession).setQueryParams(queryParams);
+		RequestHeaders rh2 = new RequestHeaders(req).parser(parser).queryParams(queryParams);
 		for (String h : headers)
 			if (containsKey(h))
 				rh2.put(h, get(h));
@@ -958,10 +954,10 @@ public class RequestHeaders extends TreeMap<String,String[]> {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
-		return beanSession.getClassMeta(type, args);
+		return req.getBeanSession().getClassMeta(type, args);
 	}
 
 	private <T> ClassMeta<T> getClassMeta(Class<T> type) {
-		return beanSession.getClassMeta(type);
+		return req.getBeanSession().getClassMeta(type);
 	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java
index 0e859d4..5b05045 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestPathMatch.java
@@ -36,12 +36,13 @@ import org.apache.juneau.rest.exception.*;
 public class RequestPathMatch extends TreeMap<String,String> {
 	private static final long serialVersionUID = 1L;
 
+	private final RestRequest req;
 	private HttpPartParser parser;
-	private BeanSession beanSession;
 	private String remainder, pattern;
 
-	RequestPathMatch() {
+	RequestPathMatch(RestRequest req) {
 		super(String.CASE_INSENSITIVE_ORDER);
+		this.req = req;
 	}
 
 	RequestPathMatch parser(HttpPartParser parser) {
@@ -49,11 +50,6 @@ public class RequestPathMatch extends TreeMap<String,String> {
 		return this;
 	}
 
-	RequestPathMatch beanSession(BeanSession beanSession) {
-		this.beanSession = beanSession;
-		return this;
-	}
-
 	RequestPathMatch remainder(String remainder) {
 		this.remainder = remainder;
 		return this;
@@ -83,7 +79,7 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	 * @throws InternalServerError Thrown if any other exception occurs.
 	 */
 	public String getString(String name) throws BadRequest, InternalServerError {
-		return getInner(parser, null, name, null, beanSession.string());
+		return getInner(parser, null, name, null, req.getBeanSession().string());
 	}
 
 	/**
@@ -269,7 +265,7 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	private <T> T parse(HttpPartParser parser, HttpPartSchema schema, String val, ClassMeta<T> cm) throws SchemaValidationException, ParseException {
 		if (parser == null)
 			parser = this.parser;
-		return parser.parse(HttpPartType.PATH, schema, val, cm);
+		return parser.createSession(req.getParserSessionArgs()).parse(HttpPartType.PATH, schema, val, cm);
 	}
 
 	/**
@@ -350,10 +346,10 @@ public class RequestPathMatch extends TreeMap<String,String> {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
-		return beanSession.getClassMeta(type, args);
+		return req.getBeanSession().getClassMeta(type, args);
 	}
 
 	private <T> ClassMeta<T> getClassMeta(Class<T> type) {
-		return beanSession.getClassMeta(type);
+		return req.getBeanSession().getClassMeta(type);
 	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java
index 7722602..cbad175 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RequestQuery.java
@@ -45,16 +45,15 @@ import org.apache.juneau.utils.*;
 public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	private static final long serialVersionUID = 1L;
 
+	private final RestRequest req;
 	private HttpPartParser parser;
-	private BeanSession beanSession;
 
-	RequestQuery parser(HttpPartParser parser) {
-		this.parser = parser;
-		return this;
+	RequestQuery(RestRequest req) {
+		this.req = req;
 	}
 
-	RequestQuery beanSession(BeanSession beanSession) {
-		this.beanSession = beanSession;
+	RequestQuery parser(HttpPartParser parser) {
+		this.parser = parser;
 		return this;
 	}
 
@@ -62,7 +61,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * Create a copy of the request query parameters.
 	 */
 	RequestQuery copy() {
-		RequestQuery rq = new RequestQuery();
+		RequestQuery rq = new RequestQuery(req);
 		rq.putAll(this);
 		return rq;
 	}
@@ -454,7 +453,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	 * @throws InternalServerError Thrown if any other exception occurs.
 	 */
 	public <T> T getAll(String name, Class<T> c) throws BadRequest, InternalServerError {
-		return getAllInner(null, null, name, null, beanSession.getClassMeta(c));
+		return getAllInner(null, null, name, null, getClassMeta(c));
 	}
 
 	/**
@@ -634,7 +633,7 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	private <T> T parse(HttpPartParser parser, HttpPartSchema schema, String val, ClassMeta<T> c) throws SchemaValidationException, ParseException {
 		if (parser == null)
 			parser = this.parser;
-		return parser.parse(HttpPartType.QUERY, schema, val, c);
+		return parser.createSession(req.getParserSessionArgs()).parse(HttpPartType.QUERY, schema, val, c);
 	}
 
 	/**
@@ -682,10 +681,10 @@ public final class RequestQuery extends LinkedHashMap<String,String[]> {
 	//-----------------------------------------------------------------------------------------------------------------
 
 	private <T> ClassMeta<T> getClassMeta(Type type, Type...args) {
-		return beanSession.getClassMeta(type, args);
+		return req.getBeanSession().getClassMeta(type, args);
 	}
 
 	private <T> ClassMeta<T> getClassMeta(Class<T> type) {
-		return beanSession.getClassMeta(type);
+		return req.getBeanSession().getClassMeta(type);
 	}
 }
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
index bb10b9c..3e1480e 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestParamDefaults.java
@@ -622,13 +622,13 @@ class RestParamDefaults {
 
 		@SuppressWarnings({ "unchecked", "rawtypes" })
 		@Override /* RestMethodParam */
-		public Object resolve(RestRequest req, final RestResponse res) throws Exception {
+		public Object resolve(final RestRequest req, final RestResponse res) throws Exception {
 			Value<Object> v = (Value<Object>)getTypeClass().newInstance();
 			v.listener(new ValueListener() {
 				@Override
 				public void onSet(Object newValue) {
 					try {
-						res.setHeader(name, partSerializer.serialize(HttpPartType.HEADER, schema, newValue));
+						res.setHeader(name, partSerializer.createSession(req.getSerializerSessionArgs()).serialize(HttpPartType.HEADER, schema, newValue));
 					} catch (SerializeException | SchemaValidationException e) {
 						throw new RuntimeException(e);
 					}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
index 9a75f96..aeec43c 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -94,6 +94,8 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	private RequestHeaders headers;
 	private Config cf;
 	private Swagger swagger;
+	private SerializerSessionArgs serializerSessionArgs;
+	private ParserSessionArgs parserSessionArgs;
 
 	/**
 	 * Constructor.
@@ -107,7 +109,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 
 			// If this is a POST, we want to parse the query parameters ourselves to prevent
 			// the servlet code from processing the HTTP body as URL-Encoded parameters.
-			queryParams = new RequestQuery();
+			queryParams = new RequestQuery(this);
 			if (isPost)
 				RestUtils.parseQuery(getQueryString(), queryParams);
 			else
@@ -124,7 +126,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 
 			method = _method;
 
-			headers = new RequestHeaders();
+			headers = new RequestHeaders(this);
 			for (Enumeration<String> e = getHeaderNames(); e.hasMoreElements();) {
 				String name = e.nextElement();
 				headers.put(name, super.getHeaders(name));
@@ -141,11 +143,11 @@ public final class RestRequest extends HttpServletRequestWrapper {
 			}
 
 			if (context.isAllowHeaderParams())
-				headers.setQueryParams(queryParams);
+				headers.queryParams(queryParams);
 
 			debug = "true".equals(getQuery().getString("debug", "false")) || "true".equals(getHeaders().getString("Debug", "false"));
 
-			this.pathParams = new RequestPathMatch();
+			this.pathParams = new RequestPathMatch(this);
 
 		} catch (RestException e) {
 			throw e;
@@ -163,22 +165,18 @@ public final class RestRequest extends HttpServletRequestWrapper {
 		this.properties = properties;
 		this.beanSession = rjm.beanContext.createSession();
 		this.pathParams
-			.parser(rjm.partParser)
-			.beanSession(beanSession);
+			.parser(rjm.partParser);
 		this.queryParams
 			.addDefault(rjm.defaultQuery)
-			.parser(rjm.partParser)
-			.beanSession(beanSession);
+			.parser(rjm.partParser);
 		this.headers
 			.addDefault(rjm.defaultRequestHeaders)
 			.addDefault(context.getDefaultRequestHeaders())
-			.parser(rjm.partParser)
-			.beanSession(beanSession);
+			.parser(rjm.partParser);
 		this.body
 			.encoders(rjm.encoders)
 			.parsers(rjm.parsers)
 			.headers(headers)
-			.beanSession(beanSession)
 			.maxInput(rjm.maxInput);
 
 		String stylesheet = getQuery().getString("stylesheet");
@@ -195,9 +193,6 @@ public final class RestRequest extends HttpServletRequestWrapper {
 				+ "\n=== END ========================================================================";
 			context.getLogger().log(Level.WARNING, msg);
 		}
-
-		if (isPlainText())
-			this.properties.put(WSERIALIZER_useWhitespace, true);
 	}
 
 	/**
@@ -560,8 +555,7 @@ public final class RestRequest extends HttpServletRequestWrapper {
 	public RequestFormData getFormData() throws InternalServerError {
 		try {
 			if (formData == null) {
-				formData = new RequestFormData();
-				formData.setParser(restJavaMethod.partParser).setBeanSession(beanSession);
+				formData = new RequestFormData(this, restJavaMethod.partParser);
 				if (! body.isLoaded()) {
 					formData.putAll(getParameterMap());
 				} else {
@@ -1437,6 +1431,18 @@ public final class RestRequest extends HttpServletRequestWrapper {
 		return sb.toString();
 	}
 
+	SerializerSessionArgs getSerializerSessionArgs() {
+		if (serializerSessionArgs == null)
+			serializerSessionArgs = new SerializerSessionArgs(getProperties(), getJavaMethod(), getLocale(), getHeaders().getTimeZone(), null, isDebug() ? true : null, getUriContext(), isPlainText() ? true : null);
+		return serializerSessionArgs;
+	}
+
+	ParserSessionArgs getParserSessionArgs() {
+		if (parserSessionArgs == null)
+			parserSessionArgs = new ParserSessionArgs(getProperties(), getJavaMethod(), getLocale(), getHeaders().getTimeZone(), null, isDebug() ? true : null, getUriContext());
+		return parserSessionArgs;
+	}
+
 	/**
 	 * Logger.
 	 *
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
index 416415d..6964a53 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
@@ -80,7 +80,7 @@ public final class RestResponse extends HttpServletResponseWrapper {
 			String passThroughHeaders = req.getHeader("x-response-headers");
 			if (passThroughHeaders != null) {
 				HttpPartParser p = context.getPartParser();
-				ObjectMap m = p.parse(HttpPartType.HEADER, null, passThroughHeaders, context.getBeanContext().getClassMeta(ObjectMap.class));
+				ObjectMap m = p.createSession(req.getParserSessionArgs()).parse(HttpPartType.HEADER, null, passThroughHeaders, context.getBeanContext().getClassMeta(ObjectMap.class));
 				for (Map.Entry<String,Object> e : m.entrySet())
 					setHeader(e.getKey(), e.getValue().toString());
 			}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/converters/Queryable.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/converters/Queryable.java
index 662e298..16b7e4c 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/converters/Queryable.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/converters/Queryable.java
@@ -74,13 +74,74 @@ public final class Queryable implements RestConverter {
 	/**
 	 * Swagger parameters for this converter.
 	 */
-	public static final String SWAGGER_PARAMS= ""
-		+ "{in:'query',name:'s',description:'Search.\nComma-delimited list of key/value pairs representing column names and search tokens.\n\\'*\\' and \\'?\\' can be used as meta-characters.',schema:{type:'string'},x-examples:{example:'?s=Bill*,birthDate>2000'}},"
-		+ "{in:'query',name:'v',description:'View.\nComma-delimited list of column names to display.',schema:{type:'string'},x-examples:{example:'?v=name,birthDate'}},"
-		+ "{in:'query',name:'o',description:'Order by.\nComma-delimited list of columns to sort by.\nColumn names can be suffixed with \\'+\\' or \\'-\\' to indicate ascending or descending order.\nThe default is ascending order.',schema:{type:'string'},x-examples:{example:'?o=name,birthDate-'}},"
-		+ "{in:'query',name:'i',description:'Case-insensitive.\nBoolean flag for case-insensitive matching on the search parameters.',schema:{type:'boolean'},x-examples:{example:'?i=true'}},"
-		+ "{in:'query',name:'p',description:'Position.\nOnly return rows starting at the specified index position (zero-indexed).\nDefault is 0',schema:{type:'integer'},x-examples:{example:'?p=100'}},"
-		+ "{in:'query',name:'l',description:'Limit.\nOnly return the specified number of rows.\nDefault is 0 (meaning return all rows).',schema:{type:'integer'},x-examples:{example:'?l=100'}}"
+	public static final String SWAGGER_PARAMS=""
+		+ "{"
+			+ "in:'query',"
+			+ "name:'s',"
+			+ "description:'"
+				+ "Search.\n"
+				+ "Key/value pairs representing column names and search tokens.\n"
+				+ "\\'*\\' and \\'?\\' can be used as meta-characters in string fields.\n"
+				+ "\\'>\\', \\'>=\\', \\'<\\', and \\'<=\\' can be used as limits on numeric and date fields.\n"
+				+ "Date fields can be matched with partial dates (e.g. \\'2018\\' to match any date in the year 2018)."
+			+ "',"
+			+ "schema:{type:'array',collectionFormat:'csv'},"
+			+ "x-examples:{example:'?s=Bill*,birthDate>2000'}"
+		+ "},"
+		+ "{"
+			+ "in:'query',"
+			+ "name:'v',"
+			+ "description:'"
+				+ "View.\n"
+				+ "Column names to display."
+			+"',"
+			+ "schema:{type:'array',collectionFormat:'csv'},"
+			+ "x-examples:{example:'?v=name,birthDate'}"
+		+ "},"
+		+ "{"
+			+ "in:'query',"
+			+ "name:'o',"
+			+ "description:'"
+				+ "Order by.\n"
+				+ "Columns to sort by.\n"
+				+ "Column names can be suffixed with \\'+\\' or \\'-\\' to indicate ascending or descending order.\n"
+				+ "The default is ascending order."
+			+ "',"
+			+ "schema:{type:'array',collectionFormat:'csv'},"
+			+ "x-examples:{example:'?o=name,birthDate-'}"
+		+ "},"
+		+ "{"
+			+ "in:'query',"
+			+ "name:'i',"
+			+ "description:'"
+				+ "Case-insensitive.\n"
+				+ "Flag for case-insensitive matching on the search parameters."
+			+ "',"
+			+ "schema:{type:'boolean'},"
+			+ "x-examples:{example:'?i=true'}"
+		+ "},"
+		+ "{"
+			+ "in:'query',"
+			+ "name:'p',"
+			+ "description:'"
+				+ "Position.\n"
+				+ "Only return rows starting at the specified index position (zero-indexed).\n"
+				+ "Default is 0"
+			+"',"
+			+ "schema:{type:'integer'},"
+			+ "x-examples:{example:'?p=100'}"
+			+ "},"
+		+ "{"
+			+ "in:'query',"
+			+ "name:'l',"
+			+ "description:'"
+				+ "Limit.\n"
+				+ "Only return the specified number of rows.\n"
+				+ "Default is 0 (meaning return all rows)."
+			+"',"
+			+ "schema:{type:'integer'},"
+			+ "x-examples:{example:'?l=100'}"
+		+ "}"
 	;
 
 	@Override /* RestConverter */
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
index ae76234..0411ca2 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
@@ -69,7 +69,7 @@ public class DefaultHandler implements ResponseHandler {
 				}
 				p.append("mediaType", mediaType).append("characterEncoding", res.getCharacterEncoding());
 
-				SerializerSession session = s.createSession(new SerializerSessionArgs(p, req.getJavaMethod(), req.getLocale(), req.getHeaders().getTimeZone(), mediaType, req.isDebug() ? true : null, req.getUriContext()));
+				SerializerSession session = s.createSession(new SerializerSessionArgs(p, req.getJavaMethod(), req.getLocale(), req.getHeaders().getTimeZone(), mediaType, req.isDebug() ? true : null, req.getUriContext(), req.isPlainText() ? true : null));
 
 				for (Map.Entry<String,String> h : session.getResponseHeaders().entrySet())
 					res.setHeader(h.getKey(), h.getValue());
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
index d6b5f41..45a0f06 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java
@@ -95,7 +95,7 @@ public abstract class MenuItemWidget extends Widget {
 		} else if (o instanceof CharSequence) {
 			sb.append((CharSequence)o);
 		} else {
-			SerializerSessionArgs args = new SerializerSessionArgs(req.getProperties(), null, req.getLocale(), null, null, req.isDebug() ? true : null, req.getUriContext());
+			SerializerSessionArgs args = new SerializerSessionArgs(req.getProperties(), null, req.getLocale(), null, null, req.isDebug() ? true : null, req.getUriContext(), req.isPlainText() ? true : null);
 			WriterSerializerSession session = HtmlSerializer.DEFAULT.createSession(args);
 			session.indent = 2;
 			session.serialize(o, sb);